Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,482 @@
'use strict';
const {
RegExpPrototypeExec,
StringPrototypeIndexOf,
StringPrototypeSlice,
Symbol,
globalThis,
} = primordials;
const path = require('path');
const {
codes: {
ERR_EVAL_ESM_CANNOT_PRINT,
ERR_INVALID_ARG_TYPE,
ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET,
},
} = require('internal/errors');
const { pathToFileURL } = require('internal/url');
const { exitCodes: { kGenericUserError } } = internalBinding('errors');
const {
kSourcePhase,
kEvaluationPhase,
} = internalBinding('module_wrap');
const { stripTypeScriptModuleTypes } = require('internal/modules/typescript');
const {
executionAsyncId,
clearDefaultTriggerAsyncId,
clearAsyncIdStack,
hasAsyncIdStack,
afterHooksExist,
emitAfter,
popAsyncContext,
} = require('internal/async_hooks');
const { containsModuleSyntax } = internalBinding('contextify');
const { getOptionValue } = require('internal/options');
const {
makeContextifyScript, runScriptInThisContext,
} = require('internal/vm');
const { emitExperimentalWarning } = require('internal/util');
// shouldAbortOnUncaughtToggle is a typed array for faster
// communication with JS.
const { shouldAbortOnUncaughtToggle } = internalBinding('util');
const kEvalTag = '[eval]';
function tryGetCwd() {
try {
return process.cwd();
} catch {
// getcwd(3) can fail if the current working directory has been deleted.
// Fall back to the directory name of the (absolute) executable path.
// It's not really correct but what are the alternatives?
return path.dirname(process.execPath);
}
}
let evalIndex = 0;
function getEvalModuleUrl() {
return `${pathToFileURL(process.cwd())}/[eval${++evalIndex}]`;
}
/**
* Evaluate an ESM entry point and return the promise that gets fulfilled after
* it finishes evaluation.
* @param {string} source Source code the ESM
* @param {boolean} print Whether the result should be printed.
* @returns {Promise}
*/
function evalModuleEntryPoint(source, print) {
if (print) {
throw new ERR_EVAL_ESM_CANNOT_PRINT();
}
RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs.
return require('internal/modules/run_main').runEntryPointWithESMLoader(
(loader) => loader.eval(source, getEvalModuleUrl(), true),
);
}
function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) {
const origModule = globalThis.module; // Set e.g. when called from the REPL.
const module = createModule(name);
const baseUrl = pathToFileURL(module.filename).href;
if (shouldUseModuleEntryPoint(name, body)) {
return getOptionValue('--experimental-strip-types') ?
evalTypeScriptModuleEntryPoint(body, print) :
evalModuleEntryPoint(body, print);
}
const evalFunction = () => runScriptInContext(name,
body,
breakFirstLine,
print,
module,
baseUrl,
undefined,
origModule);
if (shouldLoadESM) {
return require('internal/modules/run_main').runEntryPointWithESMLoader(evalFunction);
}
evalFunction();
}
const exceptionHandlerState = {
captureFn: null,
reportFlag: false,
};
function setUncaughtExceptionCaptureCallback(fn) {
if (fn === null) {
exceptionHandlerState.captureFn = fn;
shouldAbortOnUncaughtToggle[0] = 1;
process.report.reportOnUncaughtException = exceptionHandlerState.reportFlag;
return;
}
if (typeof fn !== 'function') {
throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'null'], fn);
}
if (exceptionHandlerState.captureFn !== null) {
throw new ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET();
}
exceptionHandlerState.captureFn = fn;
shouldAbortOnUncaughtToggle[0] = 0;
exceptionHandlerState.reportFlag =
process.report.reportOnUncaughtException === true;
process.report.reportOnUncaughtException = false;
}
function hasUncaughtExceptionCaptureCallback() {
return exceptionHandlerState.captureFn !== null;
}
function noop() {}
// XXX(joyeecheung): for some reason this cannot be defined at the top-level
// and exported to be written to process._fatalException, it has to be
// returned as an *anonymous function* wrapped inside a factory function,
// otherwise it breaks the test-timers.setInterval async hooks test -
// this may indicate that node::errors::TriggerUncaughtException() should
// fix up the callback scope before calling into process._fatalException,
// or this function should take extra care of the async hooks before it
// schedules a setImmediate.
function createOnGlobalUncaughtException() {
// The C++ land node::errors::TriggerUncaughtException() will
// exit the process if it returns false, and continue execution if it
// returns true (which indicates that the exception is handled by the user).
return (er, fromPromise) => {
// It's possible that defaultTriggerAsyncId was set for a constructor
// call that threw and was never cleared. So clear it now.
clearDefaultTriggerAsyncId();
const type = fromPromise ? 'unhandledRejection' : 'uncaughtException';
process.emit('uncaughtExceptionMonitor', er, type);
if (exceptionHandlerState.captureFn !== null) {
exceptionHandlerState.captureFn(er);
} else if (!process.emit('uncaughtException', er, type)) {
// If someone handled it, then great. Otherwise, die in C++ land
// since that means that we'll exit the process, emit the 'exit' event.
try {
if (!process._exiting) {
process._exiting = true;
process.exitCode = kGenericUserError;
process.emit('exit', kGenericUserError);
}
} catch {
// Nothing to be done about it at this point.
}
return false;
}
// If we handled an error, then make sure any ticks get processed
// by ensuring that the next Immediate cycle isn't empty.
require('timers').setImmediate(noop);
// Emit the after() hooks now that the exception has been handled.
if (afterHooksExist()) {
do {
const asyncId = executionAsyncId();
if (asyncId === 0)
popAsyncContext(0);
else
emitAfter(asyncId);
} while (hasAsyncIdStack());
}
// And completely empty the id stack, including anything that may be
// cached on the native side.
clearAsyncIdStack();
return true;
};
}
function readStdin(callback) {
process.stdin.setEncoding('utf8');
let code = '';
process.stdin.on('data', (d) => {
code += d;
});
process.stdin.on('end', () => {
callback(code);
});
}
/**
* Adds the TS message to the error stack.
*
* At the 3rd line of the stack, the message is added.
* @param {string} originalStack The stack to decorate
* @param {string} newMessage the message to add to the error stack
* @returns {void}
*/
function decorateCJSErrorWithTSMessage(originalStack, newMessage) {
let index;
for (let i = 0; i < 3; i++) {
index = StringPrototypeIndexOf(originalStack, '\n', index + 1);
}
return StringPrototypeSlice(originalStack, 0, index) +
'\n' + newMessage +
StringPrototypeSlice(originalStack, index);
}
/**
*
* Wrapper of evalScript
*
* This function wraps the evaluation of the source code in a try-catch block.
* If the source code fails to be evaluated, it will retry evaluating the source code
* with the TypeScript parser.
*
* If the source code fails to be evaluated with the TypeScript parser,
* it will rethrow the original error, adding the TypeScript error message to the stack.
*
* This way we don't change the behavior of the code, but we provide a better error message
* in case of a typescript error.
* @param {string} name The name of the file
* @param {string} source The source code to evaluate
* @param {boolean} breakFirstLine Whether to break on the first line
* @param {boolean} print If the result should be printed
* @param {boolean} shouldLoadESM If the code should be loaded as an ESM module
* @returns {void}
*/
function evalTypeScript(name, source, breakFirstLine, print, shouldLoadESM = false) {
const origModule = globalThis.module; // Set e.g. when called from the REPL.
const module = createModule(name);
const baseUrl = pathToFileURL(module.filename).href;
if (shouldUseModuleEntryPoint(name, source)) {
return evalTypeScriptModuleEntryPoint(source, print);
}
let compiledScript;
// This variable can be modified if the source code is stripped.
let sourceToRun = source;
try {
compiledScript = compileScript(name, source, baseUrl);
} catch (originalError) {
try {
sourceToRun = stripTypeScriptModuleTypes(source, kEvalTag, false);
// Retry the CJS/ESM syntax detection after stripping the types.
if (shouldUseModuleEntryPoint(name, sourceToRun)) {
return evalTypeScriptModuleEntryPoint(source, print);
}
// If the ContextifiedScript was successfully created, execute it.
// outside the try-catch block to avoid catching runtime errors.
compiledScript = compileScript(name, sourceToRun, baseUrl);
// Emit the experimental warning after the code was successfully evaluated.
emitExperimentalWarning('Type Stripping');
} catch (tsError) {
// If it's invalid or unsupported TypeScript syntax, rethrow the original error
// with the TypeScript error message added to the stack.
if (tsError.code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' || tsError.code === 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX') {
originalError.stack = decorateCJSErrorWithTSMessage(originalError.stack, tsError.message);
throw originalError;
}
throw tsError;
}
}
const evalFunction = () => runScriptInContext(name,
sourceToRun,
breakFirstLine,
print,
module,
baseUrl,
compiledScript,
origModule);
if (shouldLoadESM) {
return require('internal/modules/run_main').runEntryPointWithESMLoader(evalFunction);
}
evalFunction();
}
/**
* Wrapper of evalModuleEntryPoint
*
* This function wraps the compilation of the source code in a try-catch block.
* If the source code fails to be compiled, it will retry transpiling the source code
* with the TypeScript parser.
* @param {string} source The source code to evaluate
* @param {boolean} print If the result should be printed
* @returns {Promise} The module evaluation promise
*/
function evalTypeScriptModuleEntryPoint(source, print) {
if (print) {
throw new ERR_EVAL_ESM_CANNOT_PRINT();
}
RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs.
return require('internal/modules/run_main').runEntryPointWithESMLoader(
async (loader) => {
const url = getEvalModuleUrl();
let moduleWrap;
try {
// Compile the module to check for syntax errors.
moduleWrap = loader.createModuleWrap(source, url);
} catch (originalError) {
try {
const strippedSource = stripTypeScriptModuleTypes(source, kEvalTag, false);
// If the moduleWrap was successfully created, execute the module job.
// outside the try-catch block to avoid catching runtime errors.
moduleWrap = loader.createModuleWrap(strippedSource, url);
// Emit the experimental warning after the code was successfully compiled.
emitExperimentalWarning('Type Stripping');
} catch (tsError) {
// If it's invalid or unsupported TypeScript syntax, rethrow the original error
// with the TypeScript error message added to the stack.
if (tsError.code === 'ERR_INVALID_TYPESCRIPT_SYNTAX' ||
tsError.code === 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX') {
originalError.stack = `${tsError.message}\n\n${originalError.stack}`;
throw originalError;
}
throw tsError;
}
}
// If the moduleWrap was successfully created either with by just compiling
// or after transpilation, execute the module job.
return loader.executeModuleJob(url, moduleWrap, true);
},
);
};
/**
*
* Function used to shortcut when `--input-type=module-typescript` is set.
* @param {string} source
* @param {boolean} print
*/
function parseAndEvalModuleTypeScript(source, print) {
// We know its a TypeScript module, we can safely emit the experimental warning.
const strippedSource = stripTypeScriptModuleTypes(source, kEvalTag);
evalModuleEntryPoint(strippedSource, print);
}
/**
* Function used to shortcut when `--input-type=commonjs-typescript` is set
* @param {string} name The name of the file
* @param {string} source The source code to evaluate
* @param {boolean} breakFirstLine Whether to break on the first line
* @param {boolean} print If the result should be printed
* @param {boolean} shouldLoadESM If the code should be loaded as an ESM module
* @returns {void}
*/
function parseAndEvalCommonjsTypeScript(name, source, breakFirstLine, print, shouldLoadESM = false) {
// We know its a TypeScript module, we can safely emit the experimental warning.
const strippedSource = stripTypeScriptModuleTypes(source, kEvalTag);
evalScript(name, strippedSource, breakFirstLine, print, shouldLoadESM);
}
/**
*
* @param {string} name - The filename of the script.
* @param {string} body - The code of the script.
* @param {string} baseUrl Path of the parent importing the module.
* @returns {ContextifyScript} The created contextify script.
*/
function compileScript(name, body, baseUrl) {
const hostDefinedOptionId = Symbol(name);
async function importModuleDynamically(specifier, _, importAttributes, phase) {
const cascadedLoader = require('internal/modules/esm/loader').getOrInitializeCascadedLoader();
return cascadedLoader.import(specifier, baseUrl, importAttributes,
phase === 'source' ? kSourcePhase : kEvaluationPhase);
}
return makeContextifyScript(
body, // code
name, // filename,
0, // lineOffset
0, // columnOffset,
undefined, // cachedData
false, // produceCachedData
undefined, // parsingContext
hostDefinedOptionId, // hostDefinedOptionId
importModuleDynamically, // importModuleDynamically
);
}
/**
* @param {string} name - The filename of the script.
* @param {string} body - The code of the script.
* @returns {boolean} Whether the module entry point should be evaluated as a module.
*/
function shouldUseModuleEntryPoint(name, body) {
return getOptionValue('--experimental-detect-module') &&
getOptionValue('--input-type') === '' &&
containsModuleSyntax(body, name, null, 'no CJS variables');
}
/**
*
* @param {string} name - The filename of the script.
* @returns {import('internal/modules/esm/loader').CJSModule} The created module.
*/
function createModule(name) {
const CJSModule = require('internal/modules/cjs/loader').Module;
const cwd = tryGetCwd();
const module = new CJSModule(name);
module.filename = path.join(cwd, name);
module.paths = CJSModule._nodeModulePaths(cwd);
return module;
}
/**
*
* @param {string} name - The filename of the script.
* @param {string} body - The code of the script.
* @param {boolean} breakFirstLine Whether to break on the first line
* @param {boolean} print If the result should be printed
* @param {import('internal/modules/esm/loader').CJSModule} module The module
* @param {string} baseUrl Path of the parent importing the module.
* @param {object} compiledScript The compiled script.
* @param {any} origModule The original module.
* @returns {void}
*/
function runScriptInContext(name, body, breakFirstLine, print, module, baseUrl, compiledScript, origModule) {
// Create wrapper for cache entry
const script = `
globalThis.module = module;
globalThis.exports = exports;
globalThis.__dirname = __dirname;
globalThis.require = require;
return (main) => main();
`;
globalThis.__filename = name;
RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs.
const result = module._compile(script, `${name}-wrapper`)(() => {
// If the script was already compiled, use it.
return runScriptInThisContext(
compiledScript ?? compileScript(name, body, baseUrl),
true, !!breakFirstLine);
});
if (print) {
const { log } = require('internal/console/global');
process.on('exit', () => {
log(result);
});
}
if (origModule !== undefined)
globalThis.module = origModule;
}
module.exports = {
parseAndEvalCommonjsTypeScript,
parseAndEvalModuleTypeScript,
readStdin,
tryGetCwd,
evalModuleEntryPoint,
evalTypeScript,
evalScript,
onGlobalUncaughtException: createOnGlobalUncaughtException(),
setUncaughtExceptionCaptureCallback,
hasUncaughtExceptionCaptureCallback,
};

View File

@ -0,0 +1,150 @@
'use strict';
// This file is a modified version of the on-exit-leak-free module on npm.
const {
ArrayPrototypeFilter,
ArrayPrototypeIndexOf,
ArrayPrototypePush,
ArrayPrototypeSplice,
SafeFinalizationRegistry,
SafeWeakRef,
} = primordials;
const { validateObject, kValidateObjectAllowFunction } = require('internal/validators');
const { emitExperimentalWarning } = require('internal/util');
function createFinalization() {
/**
* @type {SafeFinalizationRegistry}
*/
let registry = null;
const refs = {
__proto__: null,
exit: [],
beforeExit: [],
};
const functions = {
__proto__: null,
exit: onExit,
beforeExit: onBeforeExit,
};
function install(event) {
if (refs[event].length > 0) {
return;
}
process.on(event, functions[event]);
}
function uninstall(event) {
if (refs[event].length > 0) {
return;
}
process.removeListener(event, functions[event]);
if (refs.exit.length === 0 && refs.beforeExit.length === 0) {
registry = null;
}
}
function onExit() {
callRefsToFree('exit');
}
function onBeforeExit() {
callRefsToFree('beforeExit');
}
function callRefsToFree(event) {
for (const ref of refs[event]) {
const obj = ref.deref();
const fn = ref.fn;
// This should always happen, however GC is
// indeterministic so it might not happen.
/* istanbul ignore else */
if (obj !== undefined) {
fn(obj, event);
}
}
refs[event] = [];
}
function clear(ref) {
for (const event of ['exit', 'beforeExit']) {
const index = ArrayPrototypeIndexOf(refs[event], ref);
ArrayPrototypeSplice(refs[event], index, index + 1);
uninstall(event);
}
}
function _register(event, obj, fn) {
install(event);
const ref = new SafeWeakRef(obj);
ref.fn = fn;
registry ||= new SafeFinalizationRegistry(clear);
registry.register(obj, ref);
ArrayPrototypePush(refs[event], ref);
}
/**
* Execute the given function when the process exits,
* and clean things up when the object is gc.
* @param {any} obj
* @param {Function} fn
*/
function register(obj, fn) {
emitExperimentalWarning('process.finalization.register');
validateObject(obj, 'obj', kValidateObjectAllowFunction);
_register('exit', obj, fn);
}
/**
* Execute the given function before the process exits,
* and clean things up when the object is gc.
* @param {any} obj
* @param {Function} fn
*/
function registerBeforeExit(obj, fn) {
emitExperimentalWarning('process.finalization.registerBeforeExit');
validateObject(obj, 'obj', kValidateObjectAllowFunction);
_register('beforeExit', obj, fn);
}
/**
* Unregister the given object from the onExit or onBeforeExit event.
* @param {object} obj
*/
function unregister(obj) {
emitExperimentalWarning('process.finalization.unregister');
if (!registry) {
return;
}
registry.unregister(obj);
for (const event of ['exit', 'beforeExit']) {
refs[event] = ArrayPrototypeFilter(refs[event], (ref) => {
const _obj = ref.deref();
return _obj && _obj !== obj;
});
uninstall(event);
}
}
return {
register,
registerBeforeExit,
unregister,
};
}
module.exports = {
createFinalization,
};

View File

@ -0,0 +1,555 @@
'use strict';
// This files contains process bootstrappers that can be
// run when setting up each thread, including the main
// thread and the worker threads.
const {
ArrayPrototypeEvery,
ArrayPrototypeForEach,
ArrayPrototypeIncludes,
ArrayPrototypeMap,
ArrayPrototypePush,
ArrayPrototypeSplice,
BigUint64Array,
Float64Array,
FunctionPrototypeCall,
NumberMAX_SAFE_INTEGER,
ObjectDefineProperty,
ObjectEntries,
ObjectFreeze,
ReflectApply,
RegExpPrototypeExec,
SafeArrayIterator,
Set,
SetPrototypeEntries,
SetPrototypeValues,
StringPrototypeEndsWith,
StringPrototypeIncludes,
StringPrototypeReplace,
StringPrototypeSlice,
Symbol,
SymbolFor,
SymbolIterator,
} = primordials;
const {
ErrnoException,
codes: {
ERR_FEATURE_UNAVAILABLE_ON_PLATFORM,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_OPERATION_FAILED,
ERR_OUT_OF_RANGE,
ERR_UNKNOWN_SIGNAL,
ERR_WORKER_UNSUPPORTED_OPERATION,
},
} = require('internal/errors');
const { emitExperimentalWarning } = require('internal/util');
const format = require('internal/util/inspect').format;
const {
validateArray,
validateNumber,
validateObject,
validateString,
} = require('internal/validators');
const dc = require('diagnostics_channel');
const execveDiagnosticChannel = dc.channel('process.execve');
const constants = internalBinding('constants').os.signals;
let getValidatedPath; // We need to lazy load it because of the circular dependency.
const kInternal = Symbol('internal properties');
const { exitCodes: { kNoFailure } } = internalBinding('errors');
const binding = internalBinding('process_methods');
// The 3 entries filled in by the original process.hrtime contains
// the upper/lower 32 bits of the second part of the value,
// and the remaining nanoseconds of the value.
const hrValues = binding.hrtimeBuffer;
// Use a BigUint64Array because this is actually a bit
// faster than simply returning a BigInt from C++ in V8 7.1.
const hrBigintValues = new BigUint64Array(binding.hrtimeBuffer.buffer, 0, 1);
function hrtime(time) {
binding.hrtime();
if (time !== undefined) {
validateArray(time, 'time');
if (time.length !== 2) {
throw new ERR_OUT_OF_RANGE('time', 2, time.length);
}
const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - time[0];
const nsec = hrValues[2] - time[1];
const needsBorrow = nsec < 0;
return [needsBorrow ? sec - 1 : sec, needsBorrow ? nsec + 1e9 : nsec];
}
return [
hrValues[0] * 0x100000000 + hrValues[1],
hrValues[2],
];
}
function hrtimeBigInt() {
binding.hrtimeBigInt();
return hrBigintValues[0];
}
function nop() {}
// The execution of this function itself should not cause any side effects.
function wrapProcessMethods(binding) {
const {
cpuUsage: _cpuUsage,
threadCpuUsage: _threadCpuUsage,
memoryUsage: _memoryUsage,
rss,
resourceUsage: _resourceUsage,
loadEnvFile: _loadEnvFile,
execve: _execve,
} = binding;
function _rawDebug(...args) {
binding._rawDebug(ReflectApply(format, null, args));
}
// Create the argument array that will be passed to the native function.
const cpuValues = new Float64Array(2);
// Replace the native function with the JS version that calls the native
// function.
function cpuUsage(prevValue) {
// If a previous value was passed in, ensure it has the correct shape.
if (prevValue) {
if (!previousValueIsValid(prevValue.user)) {
validateObject(prevValue, 'prevValue');
validateNumber(prevValue.user, 'prevValue.user');
throw new ERR_INVALID_ARG_VALUE.RangeError('prevValue.user',
prevValue.user);
}
if (!previousValueIsValid(prevValue.system)) {
validateNumber(prevValue.system, 'prevValue.system');
throw new ERR_INVALID_ARG_VALUE.RangeError('prevValue.system',
prevValue.system);
}
}
// Call the native function to get the current values.
_cpuUsage(cpuValues);
// If a previous value was passed in, return diff of current from previous.
if (prevValue) {
return {
user: cpuValues[0] - prevValue.user,
system: cpuValues[1] - prevValue.system,
};
}
// If no previous value passed in, return current value.
return {
user: cpuValues[0],
system: cpuValues[1],
};
}
const threadCpuValues = new Float64Array(2);
// Replace the native function with the JS version that calls the native
// function.
function threadCpuUsage(prevValue) {
// If a previous value was passed in, ensure it has the correct shape.
if (prevValue) {
if (!previousValueIsValid(prevValue.user)) {
validateObject(prevValue, 'prevValue');
validateNumber(prevValue.user, 'prevValue.user');
throw new ERR_INVALID_ARG_VALUE.RangeError('prevValue.user',
prevValue.user);
}
if (!previousValueIsValid(prevValue.system)) {
validateNumber(prevValue.system, 'prevValue.system');
throw new ERR_INVALID_ARG_VALUE.RangeError('prevValue.system',
prevValue.system);
}
}
if (process.platform === 'sunos') {
throw new ERR_OPERATION_FAILED('threadCpuUsage is not available on SunOS');
}
// Call the native function to get the current values.
_threadCpuUsage(threadCpuValues);
// If a previous value was passed in, return diff of current from previous.
if (prevValue) {
return {
user: threadCpuValues[0] - prevValue.user,
system: threadCpuValues[1] - prevValue.system,
};
}
// If no previous value passed in, return current value.
return {
user: threadCpuValues[0],
system: threadCpuValues[1],
};
}
// Ensure that a previously passed in value is valid. Currently, the native
// implementation always returns numbers <= Number.MAX_SAFE_INTEGER.
function previousValueIsValid(num) {
return typeof num === 'number' &&
num <= NumberMAX_SAFE_INTEGER &&
num >= 0;
}
const memValues = new Float64Array(5);
function memoryUsage() {
_memoryUsage(memValues);
return {
rss: memValues[0],
heapTotal: memValues[1],
heapUsed: memValues[2],
external: memValues[3],
arrayBuffers: memValues[4],
};
}
memoryUsage.rss = rss;
function exit(code) {
if (arguments.length !== 0) {
process.exitCode = code;
}
if (!process._exiting) {
process._exiting = true;
process.emit('exit', process.exitCode || kNoFailure);
}
// FIXME(joyeecheung): This is an undocumented API that gets monkey-patched
// in the user land. Either document it, or deprecate it in favor of a
// better public alternative.
process.reallyExit(process.exitCode || kNoFailure);
// If this is a worker, v8::Isolate::TerminateExecution() is called above.
// That function spoofs the stack pointer to cause the stack guard
// check to throw the termination exception. Because v8 performs
// stack guard check upon every function call, we give it a chance.
//
// Without this, user code after `process.exit()` would take effect.
// test/parallel/test-worker-voluntarily-exit-followed-by-addition.js
// test/parallel/test-worker-voluntarily-exit-followed-by-throw.js
nop();
}
function kill(pid, sig) {
let err;
// eslint-disable-next-line eqeqeq
if (pid != (pid | 0)) {
throw new ERR_INVALID_ARG_TYPE('pid', 'number', pid);
}
// Preserve null signal
if (sig === (sig | 0)) {
// XXX(joyeecheung): we have to use process._kill here because
// it's monkey-patched by tests.
err = process._kill(pid, sig);
} else {
sig ||= 'SIGTERM';
if (constants[sig]) {
err = process._kill(pid, constants[sig]);
} else {
throw new ERR_UNKNOWN_SIGNAL(sig);
}
}
if (err)
throw new ErrnoException(err, 'kill');
return true;
}
function execve(execPath, args, env) {
emitExperimentalWarning('process.execve');
const { isMainThread } = require('internal/worker');
if (!isMainThread) {
throw new ERR_WORKER_UNSUPPORTED_OPERATION('Calling process.execve');
} else if (process.platform === 'win32' || process.platform === 'os400') {
throw new ERR_FEATURE_UNAVAILABLE_ON_PLATFORM('process.execve');
}
validateString(execPath, 'execPath');
validateArray(args, 'args');
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (typeof arg !== 'string' || StringPrototypeIncludes(arg, '\u0000')) {
throw new ERR_INVALID_ARG_VALUE(`args[${i}]`, arg, 'must be a string without null bytes');
}
}
const envArray = [];
if (env !== undefined) {
validateObject(env, 'env');
for (const { 0: key, 1: value } of ObjectEntries(env)) {
if (
typeof key !== 'string' ||
typeof value !== 'string' ||
StringPrototypeIncludes(key, '\u0000') ||
StringPrototypeIncludes(value, '\u0000')
) {
throw new ERR_INVALID_ARG_VALUE(
'env', env, 'must be an object with string keys and values without null bytes',
);
} else {
ArrayPrototypePush(envArray, `${key}=${value}`);
}
}
}
if (execveDiagnosticChannel.hasSubscribers) {
execveDiagnosticChannel.publish({ execPath, args, env: envArray });
}
// Perform the system call
_execve(execPath, args, envArray);
}
const resourceValues = new Float64Array(16);
function resourceUsage() {
_resourceUsage(resourceValues);
return {
userCPUTime: resourceValues[0],
systemCPUTime: resourceValues[1],
maxRSS: resourceValues[2],
sharedMemorySize: resourceValues[3],
unsharedDataSize: resourceValues[4],
unsharedStackSize: resourceValues[5],
minorPageFault: resourceValues[6],
majorPageFault: resourceValues[7],
swappedOut: resourceValues[8],
fsRead: resourceValues[9],
fsWrite: resourceValues[10],
ipcSent: resourceValues[11],
ipcReceived: resourceValues[12],
signalsCount: resourceValues[13],
voluntaryContextSwitches: resourceValues[14],
involuntaryContextSwitches: resourceValues[15],
};
}
/**
* Loads the `.env` file to process.env.
* @param {string | URL | Buffer | undefined} path
*/
function loadEnvFile(path = undefined) { // Provide optional value so that `loadEnvFile.length` returns 0
if (path != null) {
getValidatedPath ??= require('internal/fs/utils').getValidatedPath;
path = getValidatedPath(path);
_loadEnvFile(path);
} else {
_loadEnvFile();
}
}
return {
_rawDebug,
cpuUsage,
threadCpuUsage,
resourceUsage,
memoryUsage,
kill,
exit,
execve,
loadEnvFile,
};
}
const replaceUnderscoresRegex = /_/g;
const leadingDashesRegex = /^--?/;
const trailingValuesRegex = /=.*$/;
// This builds the initial process.allowedNodeEnvironmentFlags
// from data in the config binding.
function buildAllowedFlags() {
const {
envSettings: { kAllowedInEnvvar },
types: { kBoolean },
} = internalBinding('options');
const { getCLIOptionsInfo } = require('internal/options');
const { options, aliases } = getCLIOptionsInfo();
const allowedNodeEnvironmentFlags = [];
for (const { 0: name, 1: info } of options) {
if (info.envVarSettings === kAllowedInEnvvar) {
ArrayPrototypePush(allowedNodeEnvironmentFlags, name);
if (info.type === kBoolean) {
const negatedName = `--no-${name.slice(2)}`;
ArrayPrototypePush(allowedNodeEnvironmentFlags, negatedName);
}
}
}
function isAccepted(to) {
if (!to.length || to[0] !== '-' || to === '--') return true;
const recursiveExpansion = aliases.get(to);
if (recursiveExpansion) {
if (recursiveExpansion[0] === to)
ArrayPrototypeSplice(recursiveExpansion, 0, 1);
return ArrayPrototypeEvery(recursiveExpansion, isAccepted);
}
return options.get(to).envVarSettings === kAllowedInEnvvar;
}
for (const { 0: from, 1: expansion } of aliases) {
if (ArrayPrototypeEvery(expansion, isAccepted)) {
let canonical = from;
if (StringPrototypeEndsWith(canonical, '='))
canonical = StringPrototypeSlice(canonical, 0, canonical.length - 1);
if (StringPrototypeEndsWith(canonical, ' <arg>'))
canonical = StringPrototypeSlice(canonical, 0, canonical.length - 4);
ArrayPrototypePush(allowedNodeEnvironmentFlags, canonical);
}
}
const trimLeadingDashes =
(flag) => StringPrototypeReplace(flag, leadingDashesRegex, '');
// Save these for comparison against flags provided to
// process.allowedNodeEnvironmentFlags.has() which lack leading dashes.
const nodeFlags = ArrayPrototypeMap(allowedNodeEnvironmentFlags,
trimLeadingDashes);
class NodeEnvironmentFlagsSet extends Set {
constructor(array) {
super();
this[kInternal] = { array };
}
add() {
// No-op, `Set` API compatible
return this;
}
delete() {
// No-op, `Set` API compatible
return false;
}
clear() {
// No-op, `Set` API compatible
}
has(key) {
// This will return `true` based on various possible
// permutations of a flag, including present/missing leading
// dash(es) and/or underscores-for-dashes.
// Strips any values after `=`, inclusive.
// TODO(addaleax): It might be more flexible to run the option parser
// on a dummy option set and see whether it rejects the argument or
// not.
if (typeof key === 'string') {
key = StringPrototypeReplace(key, replaceUnderscoresRegex, '-');
if (RegExpPrototypeExec(leadingDashesRegex, key) !== null) {
key = StringPrototypeReplace(key, trailingValuesRegex, '');
return ArrayPrototypeIncludes(this[kInternal].array, key);
}
return ArrayPrototypeIncludes(nodeFlags, key);
}
return false;
}
entries() {
this[kInternal].set ??=
new Set(new SafeArrayIterator(this[kInternal].array));
return SetPrototypeEntries(this[kInternal].set);
}
forEach(callback, thisArg = undefined) {
ArrayPrototypeForEach(
this[kInternal].array,
(v) => ReflectApply(callback, thisArg, [v, v, this]),
);
}
get size() {
return this[kInternal].array.length;
}
values() {
this[kInternal].set ??=
new Set(new SafeArrayIterator(this[kInternal].array));
return SetPrototypeValues(this[kInternal].set);
}
}
const flagSetValues = NodeEnvironmentFlagsSet.prototype.values;
ObjectDefineProperty(NodeEnvironmentFlagsSet.prototype, SymbolIterator, {
__proto__: null,
value: flagSetValues,
});
ObjectDefineProperty(NodeEnvironmentFlagsSet.prototype, 'keys', {
__proto__: null,
value: flagSetValues,
});
ObjectFreeze(NodeEnvironmentFlagsSet.prototype.constructor);
ObjectFreeze(NodeEnvironmentFlagsSet.prototype);
return ObjectFreeze(new NodeEnvironmentFlagsSet(
allowedNodeEnvironmentFlags,
));
}
// Lazy load internal/trace_events_async_hooks only if the async_hooks
// trace event category is enabled.
let traceEventsAsyncHook;
// Dynamically enable/disable the traceEventsAsyncHook
function toggleTraceCategoryState(asyncHooksEnabled) {
if (asyncHooksEnabled) {
traceEventsAsyncHook ||= require('internal/trace_events_async_hooks').createHook();
traceEventsAsyncHook.enable();
} else if (traceEventsAsyncHook) {
traceEventsAsyncHook.disable();
}
}
const { arch, platform, version } = process;
let refSymbol;
function ref(maybeRefable) {
if (maybeRefable == null) return;
const fn = maybeRefable[refSymbol ??= SymbolFor('nodejs.ref')] || maybeRefable.ref;
if (typeof fn === 'function') FunctionPrototypeCall(fn, maybeRefable);
}
let unrefSymbol;
function unref(maybeRefable) {
if (maybeRefable == null) return;
const fn = maybeRefable[unrefSymbol ??= SymbolFor('nodejs.unref')] || maybeRefable.unref;
if (typeof fn === 'function') FunctionPrototypeCall(fn, maybeRefable);
}
module.exports = {
toggleTraceCategoryState,
buildAllowedFlags,
wrapProcessMethods,
hrtime,
hrtimeBigInt,
arch,
platform,
version,
ref,
unref,
};

View File

@ -0,0 +1,36 @@
'use strict';
const {
ObjectFreeze,
} = primordials;
const permission = internalBinding('permission');
const { validateString, validateBuffer } = require('internal/validators');
const { Buffer } = require('buffer');
const { isBuffer } = Buffer;
let _permission;
module.exports = ObjectFreeze({
__proto__: null,
isEnabled() {
if (_permission === undefined) {
const { getOptionValue } = require('internal/options');
_permission = getOptionValue('--permission');
}
return _permission;
},
has(scope, reference) {
validateString(scope, 'scope');
if (reference != null) {
// TODO: add support for WHATWG URLs and Uint8Arrays.
if (isBuffer(reference)) {
validateBuffer(reference, 'reference');
} else {
validateString(reference, 'reference');
}
}
return permission.has(scope, reference);
},
});

View File

@ -0,0 +1,728 @@
'use strict';
const {
ArrayPrototypeForEach,
Date,
DatePrototypeGetDate,
DatePrototypeGetFullYear,
DatePrototypeGetHours,
DatePrototypeGetMinutes,
DatePrototypeGetMonth,
DatePrototypeGetSeconds,
NumberParseInt,
ObjectDefineProperty,
ObjectFreeze,
String,
globalThis,
} = primordials;
const {
getOptionValue,
refreshOptions,
getEmbedderOptions,
} = require('internal/options');
const {
exposeLazyInterfaces,
defineReplaceableLazyAttribute,
setupCoverageHooks,
emitExperimentalWarning,
deprecate,
} = require('internal/util');
const {
ERR_MISSING_OPTION,
ERR_ACCESS_DENIED,
} = require('internal/errors').codes;
const assert = require('internal/assert');
const {
namespace: {
addSerializeCallback,
isBuildingSnapshot,
},
runDeserializeCallbacks,
} = require('internal/v8/startup_snapshot');
function prepareMainThreadExecution(expandArgv1 = false, initializeModules = true) {
return prepareExecution({
expandArgv1,
initializeModules,
isMainThread: true,
});
}
function prepareTestRunnerMainExecution(loadUserModules = true) {
return prepareExecution({
expandArgv1: false,
initializeModules: true,
isMainThread: true,
forceDefaultLoader: !loadUserModules,
});
}
function prepareWorkerThreadExecution() {
prepareExecution({
expandArgv1: false,
initializeModules: false,
isMainThread: false,
});
}
function prepareShadowRealmExecution() {
// Patch the process object with legacy properties and normalizations.
// Do not expand argv1 as it is not available in ShadowRealm.
patchProcessObject(false);
setupDebugEnv();
// Disable custom loaders in ShadowRealm.
setupUserModules(true);
const {
privateSymbols: {
host_defined_option_symbol,
},
} = internalBinding('util');
const {
vm_dynamic_import_default_internal,
} = internalBinding('symbols');
// For ShadowRealm.prototype.importValue(), the referrer name is
// always null, so the native ImportModuleDynamically() callback would
// always fallback to look up the host-defined option from the
// global object using host_defined_option_symbol. Using
// vm_dynamic_import_default_internal as the host-defined option
// instructs the JS-land importModuleDynamicallyCallback() to
// proxy the request to defaultImportModuleDynamically().
globalThis[host_defined_option_symbol] =
vm_dynamic_import_default_internal;
}
function prepareExecution(options) {
const { expandArgv1, initializeModules, isMainThread, forceDefaultLoader } = options;
refreshRuntimeOptions();
// Patch the process object and get the resolved main entry point.
const mainEntry = patchProcessObject(expandArgv1);
setupTraceCategoryState();
setupInspectorHooks();
setupNetworkInspection();
setupNavigator();
setupWarningHandler();
setupSQLite();
setupQuic();
setupWebStorage();
setupWebsocket();
setupEventsource();
setupCodeCoverage();
setupDebugEnv();
// Process initial diagnostic reporting configuration, if present.
initializeReport();
// Load permission system API
initializePermission();
initializeSourceMapsHandlers();
initializeDeprecations();
initializeConfigFileSupport();
require('internal/dns/utils').initializeDns();
setupHttpProxy();
if (isMainThread) {
assert(internalBinding('worker').isMainThread);
// Worker threads will get the manifest in the message handler.
// Print stack trace on `SIGINT` if option `--trace-sigint` presents.
setupStacktracePrinterOnSigint();
initializeReportSignalHandlers(); // Main-thread-only.
initializeHeapSnapshotSignalHandlers();
// 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().
setupChildProcessIpcChannel();
// 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).
initializeClusterIPC();
// TODO(joyeecheung): do this for worker threads as well.
runDeserializeCallbacks();
} else {
assert(!internalBinding('worker').isMainThread);
// The setup should be called in LOAD_SCRIPT message handler.
assert(!initializeModules);
}
if (initializeModules) {
setupUserModules(forceDefaultLoader);
}
return mainEntry;
}
function setupHttpProxy() {
if (process.env.NODE_USE_ENV_PROXY &&
(process.env.HTTP_PROXY || process.env.HTTPS_PROXY ||
process.env.http_proxy || process.env.https_proxy)) {
const { setGlobalDispatcher, EnvHttpProxyAgent } = require('internal/deps/undici/undici');
const envHttpProxyAgent = new EnvHttpProxyAgent();
setGlobalDispatcher(envHttpProxyAgent);
// TODO(joyeecheung): This currently only affects fetch. Implement handling in the
// http/https Agent constructor too.
// TODO(joyeecheung): This is currently guarded with NODE_USE_ENV_PROXY. Investigate whether
// it's possible to enable it by default without stepping on other existing libraries that
// sets the global dispatcher or monkey patches the global agent.
}
}
function setupUserModules(forceDefaultLoader = false) {
initializeCJSLoader();
initializeESMLoader(forceDefaultLoader);
const {
hasStartedUserCJSExecution,
hasStartedUserESMExecution,
} = require('internal/modules/helpers');
assert(!hasStartedUserCJSExecution());
assert(!hasStartedUserESMExecution());
if (getEmbedderOptions().hasEmbedderPreload) {
runEmbedderPreload();
}
// Do not enable preload modules if custom loaders are disabled.
// For example, loader workers are responsible for doing this themselves.
// And preload modules are not supported in ShadowRealm as well.
if (!forceDefaultLoader) {
loadPreloadModules();
}
// Need to be done after --require setup.
initializeFrozenIntrinsics();
}
function refreshRuntimeOptions() {
refreshOptions();
}
/**
* Patch the process object with legacy properties and normalizations.
* Replace `process.argv[0]` with `process.execPath`, preserving the original `argv[0]` value as `process.argv0`.
* Replace `process.argv[1]` with the resolved absolute file path of the entry point, if found.
* @param {boolean} expandArgv1 - Whether to replace `process.argv[1]` with the resolved absolute file path of
* the main entry point.
*/
function patchProcessObject(expandArgv1) {
const binding = internalBinding('process_methods');
binding.patchProcessObject(process);
// Since we replace process.argv[0] below, preserve the original value in case the user needs it.
ObjectDefineProperty(process, 'argv0', {
__proto__: null,
enumerable: true,
// Only set it to true during snapshot building.
configurable: isBuildingSnapshot(),
value: process.argv[0],
});
process.exitCode = undefined;
process._exiting = false;
process.argv[0] = process.execPath;
/** @type {string} */
let mainEntry;
// If requested, update process.argv[1] to replace whatever the user provided with the resolved absolute file path of
// the entry point.
if (expandArgv1 && process.argv[1] && process.argv[1][0] !== '-') {
// Expand process.argv[1] into a full path.
const path = require('path');
try {
mainEntry = path.resolve(process.argv[1]);
process.argv[1] = mainEntry;
} catch {
// Continue regardless of error.
}
}
// We need to initialize the global console here again with process.stdout
// and friends for snapshot deserialization.
const globalConsole = require('internal/console/global');
const { initializeGlobalConsole } = require('internal/console/constructor');
initializeGlobalConsole(globalConsole);
// TODO(joyeecheung): most of these should be deprecated and removed,
// except some that we need to be able to mutate during run time.
addReadOnlyProcessAlias('_eval', '--eval');
addReadOnlyProcessAlias('_print_eval', '--print');
addReadOnlyProcessAlias('_syntax_check_only', '--check');
addReadOnlyProcessAlias('_forceRepl', '--interactive');
addReadOnlyProcessAlias('_preload_modules', '--require');
addReadOnlyProcessAlias('noDeprecation', '--no-deprecation');
addReadOnlyProcessAlias('noProcessWarnings', '--no-warnings');
addReadOnlyProcessAlias('traceProcessWarnings', '--trace-warnings');
addReadOnlyProcessAlias('throwDeprecation', '--throw-deprecation');
addReadOnlyProcessAlias('profProcess', '--prof-process');
addReadOnlyProcessAlias('traceDeprecation', '--trace-deprecation');
addReadOnlyProcessAlias('_breakFirstLine', '--inspect-brk', false);
addReadOnlyProcessAlias('_breakNodeFirstLine', '--inspect-brk-node', false);
return mainEntry;
}
function addReadOnlyProcessAlias(name, option, enumerable = true) {
const value = getOptionValue(option);
if (value) {
ObjectDefineProperty(process, name, {
__proto__: null,
writable: false,
configurable: true,
enumerable,
value,
});
}
}
function setupWarningHandler() {
const {
onWarning,
resetForSerialization,
} = require('internal/process/warning');
if (getOptionValue('--warnings') &&
process.env.NODE_NO_WARNINGS !== '1') {
process.on('warning', onWarning);
// The code above would add the listener back during deserialization,
// if applicable.
if (isBuildingSnapshot()) {
addSerializeCallback(() => {
process.removeListener('warning', onWarning);
resetForSerialization();
});
}
}
}
// https://websockets.spec.whatwg.org/
function setupWebsocket() {
if (getOptionValue('--no-experimental-websocket')) {
delete globalThis.WebSocket;
delete globalThis.CloseEvent;
}
}
// https://html.spec.whatwg.org/multipage/server-sent-events.html
function setupEventsource() {
if (!getOptionValue('--experimental-eventsource')) {
delete globalThis.EventSource;
}
}
// TODO(aduh95): move this to internal/bootstrap/web/* when the CLI flag is
// removed.
function setupNavigator() {
if (getEmbedderOptions().noBrowserGlobals ||
getOptionValue('--no-experimental-global-navigator')) {
return;
}
// https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
exposeLazyInterfaces(globalThis, 'internal/navigator', ['Navigator']);
defineReplaceableLazyAttribute(globalThis, 'internal/navigator', ['navigator'], false);
}
function setupSQLite() {
if (getOptionValue('--no-experimental-sqlite')) {
return;
}
const { BuiltinModule } = require('internal/bootstrap/realm');
BuiltinModule.allowRequireByUsers('sqlite');
}
function initializeConfigFileSupport() {
if (getOptionValue('--experimental-default-config-file') ||
getOptionValue('--experimental-config-file')) {
emitExperimentalWarning('--experimental-config-file');
}
}
function setupQuic() {
if (!getOptionValue('--experimental-quic')) {
return;
}
const { BuiltinModule } = require('internal/bootstrap/realm');
BuiltinModule.allowRequireByUsers('quic');
}
function setupWebStorage() {
if (getEmbedderOptions().noBrowserGlobals ||
!getOptionValue('--experimental-webstorage')) {
return;
}
// https://html.spec.whatwg.org/multipage/webstorage.html#webstorage
exposeLazyInterfaces(globalThis, 'internal/webstorage', ['Storage']);
defineReplaceableLazyAttribute(globalThis, 'internal/webstorage', [
'localStorage', 'sessionStorage',
]);
}
function setupCodeCoverage() {
// 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. Don't do anything if the
// --experimental-test-coverage flag is present, as the test runner will
// handle coverage.
if (process.env.NODE_V8_COVERAGE &&
!getOptionValue('--experimental-test-coverage')) {
process.env.NODE_V8_COVERAGE =
setupCoverageHooks(process.env.NODE_V8_COVERAGE);
}
}
function setupStacktracePrinterOnSigint() {
if (!getOptionValue('--trace-sigint')) {
return;
}
const { SigintWatchdog } = require('internal/watchdog');
const watchdog = new SigintWatchdog();
watchdog.start();
}
function initializeReport() {
ObjectDefineProperty(process, 'report', {
__proto__: null,
enumerable: true,
configurable: true,
get() {
const { report } = require('internal/process/report');
return report;
},
});
}
function setupDebugEnv() {
require('internal/util/debuglog').initializeDebugEnv(process.env.NODE_DEBUG);
if (getOptionValue('--expose-internals')) {
require('internal/bootstrap/realm').BuiltinModule.exposeInternals();
}
}
// This has to be called after initializeReport() is called
function initializeReportSignalHandlers() {
if (getOptionValue('--report-on-signal')) {
const { addSignalHandler } = require('internal/process/report');
addSignalHandler();
}
}
function initializeHeapSnapshotSignalHandlers() {
const signal = getOptionValue('--heapsnapshot-signal');
const diagnosticDir = getOptionValue('--diagnostic-dir');
if (!signal)
return;
require('internal/validators').validateSignalName(signal);
const { writeHeapSnapshot } = require('v8');
function doWriteHeapSnapshot() {
const heapSnapshotFilename = getHeapSnapshotFilename(diagnosticDir);
writeHeapSnapshot(heapSnapshotFilename);
}
process.on(signal, doWriteHeapSnapshot);
// The code above would add the listener back during deserialization,
// if applicable.
if (isBuildingSnapshot()) {
addSerializeCallback(() => {
process.removeListener(signal, doWriteHeapSnapshot);
});
}
}
function setupTraceCategoryState() {
const { isTraceCategoryEnabled } = internalBinding('trace_events');
const { toggleTraceCategoryState } = require('internal/process/per_thread');
toggleTraceCategoryState(isTraceCategoryEnabled('node.async_hooks'));
}
function setupInspectorHooks() {
// If Debugger.setAsyncCallStackDepth is sent during bootstrap,
// we cannot immediately call into JS to enable the hooks, which could
// interrupt the JS execution of bootstrap. So instead we save the
// notification in the inspector agent if it's sent in the middle of
// bootstrap, and process the notification later here.
if (internalBinding('config').hasInspector) {
const {
enable,
disable,
} = require('internal/inspector_async_hook');
internalBinding('inspector').registerAsyncHook(enable, disable);
}
}
function setupNetworkInspection() {
if (internalBinding('config').hasInspector && getOptionValue('--experimental-network-inspection')) {
const {
enable,
disable,
} = require('internal/inspector_network_tracking');
internalBinding('inspector').setupNetworkTracking(enable, disable);
}
}
// In general deprecations are initialized wherever the APIs are implemented,
// this is used to deprecate APIs implemented in C++ where the deprecation
// utilities are not easily accessible.
function initializeDeprecations() {
const pendingDeprecation = getOptionValue('--pending-deprecation');
// DEP0103: access to `process.binding('util').isX` type checkers
// TODO(addaleax): Turn into a full runtime deprecation.
const utilBinding = internalBinding('util');
const types = 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];
}
// TODO(joyeecheung): this is a legacy property exposed to process.
// Now that we use the config binding to carry this information, remove
// it from the process. We may consider exposing it properly in
// process.features.
const { noBrowserGlobals } = internalBinding('config');
if (noBrowserGlobals) {
ObjectDefineProperty(process, '_noBrowserGlobals', {
__proto__: null,
writable: false,
enumerable: true,
configurable: true,
value: noBrowserGlobals,
});
}
if (pendingDeprecation) {
process.binding = deprecate(process.binding,
'process.binding() is deprecated. ' +
'Please use public APIs instead.', 'DEP0111');
process._tickCallback = deprecate(process._tickCallback,
'process._tickCallback() is deprecated',
'DEP0134');
}
}
function setupChildProcessIpcChannel() {
if (process.env.NODE_CHANNEL_FD) {
const fd = NumberParseInt(process.env.NODE_CHANNEL_FD, 10);
assert(fd >= 0);
// Make sure it's not accidentally inherited by child processes.
delete process.env.NODE_CHANNEL_FD;
const serializationMode =
process.env.NODE_CHANNEL_SERIALIZATION_MODE || 'json';
delete process.env.NODE_CHANNEL_SERIALIZATION_MODE;
require('child_process')._forkChild(fd, serializationMode);
assert(process.send);
}
}
function initializeClusterIPC() {
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 initializePermission() {
const permission = getOptionValue('--permission');
if (permission) {
process.binding = function binding(_module) {
throw new ERR_ACCESS_DENIED('process.binding');
};
// Guarantee path module isn't monkey-patched to bypass permission model
ObjectFreeze(require('path'));
const { has } = require('internal/process/permission');
const warnFlags = [
'--allow-addons',
'--allow-child-process',
'--allow-wasi',
'--allow-worker',
];
for (const flag of warnFlags) {
if (getOptionValue(flag)) {
process.emitWarning(
`The flag ${flag} must be used with extreme caution. ` +
'It could invalidate the permission model.', 'SecurityWarning');
}
}
const warnCommaFlags = [
'--allow-fs-read',
'--allow-fs-write',
];
for (const flag of warnCommaFlags) {
const value = getOptionValue(flag);
if (value.length === 1 && value[0].includes(',')) {
process.emitWarning(
`The ${flag} CLI flag has changed. ` +
'Passing a comma-separated list of paths is no longer valid. ' +
'Documentation can be found at ' +
'https://nodejs.org/api/permissions.html#file-system-permissions',
'Warning',
);
}
}
ObjectDefineProperty(process, 'permission', {
__proto__: null,
enumerable: true,
configurable: false,
value: {
has,
},
});
} else {
const availablePermissionFlags = [
'--allow-fs-read',
'--allow-fs-write',
'--allow-addons',
'--allow-child-process',
'--allow-wasi',
'--allow-worker',
];
ArrayPrototypeForEach(availablePermissionFlags, (flag) => {
const value = getOptionValue(flag);
if (value.length) {
throw new ERR_MISSING_OPTION('--permission');
}
});
}
}
function initializeCJSLoader() {
const { initializeCJS } = require('internal/modules/cjs/loader');
initializeCJS();
}
function initializeESMLoader(forceDefaultLoader) {
const { initializeESM } = require('internal/modules/esm/utils');
initializeESM(forceDefaultLoader);
// Patch the vm module when --experimental-vm-modules is on.
// Please update the comments in vm.js when this block changes.
if (getOptionValue('--experimental-vm-modules')) {
const {
Module, SourceTextModule, SyntheticModule,
} = require('internal/vm/module');
const vm = require('vm');
vm.Module = Module;
vm.SourceTextModule = SourceTextModule;
vm.SyntheticModule = SyntheticModule;
}
}
function initializeSourceMapsHandlers() {
const {
setSourceMapsSupport,
} = require('internal/source_map/source_map_cache');
const enabled = getOptionValue('--enable-source-maps');
setSourceMapsSupport(enabled, {
__proto__: null,
// TODO(legendecas): In order to smoothly improve the source map support,
// skip source maps in node_modules and generated code with
// `--enable-source-maps` in a semver major version.
nodeModules: enabled,
generatedCode: enabled,
});
}
function initializeFrozenIntrinsics() {
if (getOptionValue('--frozen-intrinsics')) {
emitExperimentalWarning('Frozen intristics');
require('internal/freeze_intrinsics')();
}
}
function runEmbedderPreload() {
internalBinding('mksnapshot').runEmbedderPreload(process, require);
}
function loadPreloadModules() {
// For user code, we preload modules if `-r` is passed
const preloadModules = getOptionValue('--require');
if (preloadModules && preloadModules.length > 0) {
const {
Module: {
_preloadModules,
},
} = require('internal/modules/cjs/loader');
_preloadModules(preloadModules);
}
}
function markBootstrapComplete() {
internalBinding('performance').markBootstrapComplete();
}
// Sequence number for diagnostic filenames
let sequenceNumOfheapSnapshot = 0;
// To generate the HeapSnapshotFilename while using custom diagnosticDir
function getHeapSnapshotFilename(diagnosticDir) {
if (!diagnosticDir) return undefined;
const date = new Date();
const year = DatePrototypeGetFullYear(date);
const month = String(DatePrototypeGetMonth(date) + 1).padStart(2, '0');
const day = String(DatePrototypeGetDate(date)).padStart(2, '0');
const hours = String(DatePrototypeGetHours(date)).padStart(2, '0');
const minutes = String(DatePrototypeGetMinutes(date)).padStart(2, '0');
const seconds = String(DatePrototypeGetSeconds(date)).padStart(2, '0');
const dateString = `${year}${month}${day}`;
const timeString = `${hours}${minutes}${seconds}`;
const pid = process.pid;
const threadId = internalBinding('worker').threadId;
const fileSequence = (++sequenceNumOfheapSnapshot).toString().padStart(3, '0');
return `${diagnosticDir}/Heap.${dateString}.${timeString}.${pid}.${threadId}.${fileSequence}.heapsnapshot`;
}
module.exports = {
setupUserModules,
prepareMainThreadExecution,
prepareWorkerThreadExecution,
prepareShadowRealmExecution,
prepareTestRunnerMainExecution,
markBootstrapComplete,
loadPreloadModules,
initializeFrozenIntrinsics,
};

View File

@ -0,0 +1,497 @@
'use strict';
const {
ArrayPrototypePush,
ArrayPrototypeShift,
Error,
ObjectPrototypeHasOwnProperty,
SafeMap,
SafeWeakMap,
} = primordials;
const {
tickInfo,
promiseRejectEvents: {
kPromiseRejectWithNoHandler,
kPromiseHandlerAddedAfterReject,
kPromiseRejectAfterResolved,
kPromiseResolveAfterResolved,
},
setPromiseRejectCallback,
} = internalBinding('task_queue');
const { deprecate } = require('internal/util');
const {
noSideEffectsToString,
triggerUncaughtException,
exitCodes: { kGenericUserError },
} = internalBinding('errors');
const {
pushAsyncContext,
popAsyncContext,
symbols: {
async_id_symbol: kAsyncIdSymbol,
trigger_async_id_symbol: kTriggerAsyncIdSymbol,
},
} = require('internal/async_hooks');
const { isErrorStackTraceLimitWritable } = require('internal/errors');
const AsyncContextFrame = require('internal/async_context_frame');
// *Must* match Environment::TickInfo::Fields in src/env.h.
const kHasRejectionToWarn = 1;
// By default true because in cases where process is not a global
// it is not possible to determine if the user has added a listener
// to the process object.
let hasMultipleResolvesListener = true;
if (process.on) {
hasMultipleResolvesListener = process.listenerCount('multipleResolves') !== 0;
process.on('newListener', (eventName) => {
if (eventName === 'multipleResolves') {
hasMultipleResolvesListener = true;
}
});
process.on('removeListener', (eventName) => {
if (eventName === 'multipleResolves') {
hasMultipleResolvesListener = process.listenerCount('multipleResolves') !== 0;
}
});
}
/**
* Errors & Warnings
*/
class UnhandledPromiseRejection extends Error {
code = 'ERR_UNHANDLED_REJECTION';
name = 'UnhandledPromiseRejection';
/**
* @param {Error} reason
*/
constructor(reason) {
super('This error originated either by throwing inside of an ' +
'async function without a catch block, or by rejecting a promise which ' +
'was not handled with .catch(). The promise rejected with the reason "' +
noSideEffectsToString(reason) + '".');
}
}
class UnhandledPromiseRejectionWarning extends Error {
name = 'UnhandledPromiseRejectionWarning';
/**
* @param {number} uid
*/
constructor(uid) {
const message = 'Unhandled promise rejection. This error originated either by ' +
'throwing inside of an async function without a catch block, ' +
'or by rejecting a promise which was not handled with .catch(). ' +
'To terminate the node process on unhandled promise ' +
'rejection, use the CLI flag `--unhandled-rejections=strict` (see ' +
'https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). ' +
`(rejection id: ${uid})`;
// UnhandledPromiseRejectionWarning will get the stack trace from the
// reason, so we can disable the stack trace limit temporarily for better
// performance.
if (isErrorStackTraceLimitWritable()) {
const stackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 0;
super(message);
Error.stackTraceLimit = stackTraceLimit;
} else {
super(message);
}
}
}
class PromiseRejectionHandledWarning extends Error {
name = 'PromiseRejectionHandledWarning';
/**
* @param {number} uid
*/
constructor(uid) {
super(`Promise rejection was handled asynchronously (rejection id: ${uid})`);
this.id = uid;
}
}
/**
* @typedef PromiseInfo
* @property {*} reason the reason for the rejection
* @property {number} uid the unique id of the promise
* @property {boolean} warned whether the rejection has been warned
* @property {object} [domain] the domain the promise was created in
*/
/**
* @type {WeakMap<Promise, PromiseInfo>}
*/
const maybeUnhandledPromises = new SafeWeakMap();
/**
* Using a Mp causes the promise to be referenced at least for one tick.
* @type {Map<Promise, PromiseInfo>}
*/
let pendingUnhandledRejections = new SafeMap();
/**
* @type {Array<{promise: Promise, warning: Error}>}
*/
const asyncHandledRejections = [];
/**
* @type {number}
*/
let lastPromiseId = 0;
/**
* @param {boolean} value
*/
function setHasRejectionToWarn(value) {
tickInfo[kHasRejectionToWarn] = value ? 1 : 0;
}
/**
* @returns {boolean}
*/
function hasRejectionToWarn() {
return tickInfo[kHasRejectionToWarn] === 1;
}
/**
* @param {string|Error} obj
* @returns {obj is Error}
*/
function isErrorLike(obj) {
return typeof obj === 'object' &&
obj !== null &&
ObjectPrototypeHasOwnProperty(obj, 'stack');
}
/**
* @param {0|1|2|3} type
* @param {Promise} promise
* @param {Error} reason
*/
function promiseRejectHandler(type, promise, reason) {
if (unhandledRejectionsMode === undefined) {
unhandledRejectionsMode = getUnhandledRejectionsMode();
}
switch (type) {
case kPromiseRejectWithNoHandler: // 0
unhandledRejection(promise, reason);
break;
case kPromiseHandlerAddedAfterReject: // 1
handledRejection(promise);
break;
case kPromiseRejectAfterResolved: // 2
if (hasMultipleResolvesListener) {
resolveErrorReject(promise, reason);
}
break;
case kPromiseResolveAfterResolved: // 3
if (hasMultipleResolvesListener) {
resolveErrorResolve(promise, reason);
}
break;
}
}
const multipleResolvesDeprecate = deprecate(
() => {},
'The multipleResolves event has been deprecated.',
'DEP0160',
);
/**
* @param {Promise} promise
* @param {Error} reason
*/
function resolveErrorResolve(promise, reason) {
// We have to wrap this in a next tick. Otherwise the error could be caught by
// the executed promise.
process.nextTick(() => {
// Emit the multipleResolves event.
// This is a deprecated event, so we have to check if it's being listened to.
if (process.emit('multipleResolves', 'resolve', promise, reason)) {
// If the event is being listened to, emit a deprecation warning.
multipleResolvesDeprecate();
}
});
}
/**
* @param {Promise} promise
* @param {Error} reason
*/
function resolveErrorReject(promise, reason) {
// We have to wrap this in a next tick. Otherwise the error could be caught by
// the executed promise.
process.nextTick(() => {
if (process.emit('multipleResolves', 'reject', promise, reason)) {
multipleResolvesDeprecate();
}
});
}
/**
* @param {Promise} promise
* @param {PromiseInfo} promiseInfo
* @returns {boolean}
*/
const emitUnhandledRejection = (promise, promiseInfo) => {
return promiseInfo.domain ?
promiseInfo.domain.emit('error', promiseInfo.reason) :
process.emit('unhandledRejection', promiseInfo.reason, promise);
};
/**
* @param {Promise} promise
* @param {Error} reason
*/
function unhandledRejection(promise, reason) {
pendingUnhandledRejections.set(promise, {
reason,
uid: ++lastPromiseId,
warned: false,
domain: process.domain,
contextFrame: AsyncContextFrame.current(),
});
setHasRejectionToWarn(true);
}
/**
* @param {Promise} promise
*/
function handledRejection(promise) {
if (pendingUnhandledRejections.has(promise)) {
pendingUnhandledRejections.delete(promise);
return;
}
const promiseInfo = maybeUnhandledPromises.get(promise);
if (promiseInfo !== undefined) {
maybeUnhandledPromises.delete(promise);
if (promiseInfo.warned) {
// Generate the warning object early to get a good stack trace.
const warning = new PromiseRejectionHandledWarning(promiseInfo.uid);
ArrayPrototypePush(asyncHandledRejections, { promise, warning });
setHasRejectionToWarn(true);
}
}
}
const unhandledRejectionErrName = UnhandledPromiseRejectionWarning.name;
/**
* @param {PromiseInfo} promiseInfo
*/
function emitUnhandledRejectionWarning(promiseInfo) {
const warning = new UnhandledPromiseRejectionWarning(promiseInfo.uid);
const reason = promiseInfo.reason;
try {
if (isErrorLike(reason)) {
warning.stack = reason.stack;
process.emitWarning(reason.stack, unhandledRejectionErrName);
} else {
process.emitWarning(
noSideEffectsToString(reason), unhandledRejectionErrName);
}
} catch {
try {
process.emitWarning(
noSideEffectsToString(reason), unhandledRejectionErrName);
} catch {
// Ignore.
}
}
process.emitWarning(warning);
}
/**
* @callback UnhandledRejectionsModeHandler
* @param {Promise} promise
* @param {PromiseInfo} promiseInfo
* @param {number} [promiseAsyncId]
* @returns {boolean}
*/
/**
* The mode of unhandled rejections.
* @type {UnhandledRejectionsModeHandler}
*/
let unhandledRejectionsMode;
/**
* --unhandled-rejections=strict:
* Emit 'uncaughtException'. If it's not handled, print the error to stderr
* and exit the process.
* Otherwise, emit 'unhandledRejection'. If 'unhandledRejection' is not
* handled, emit 'UnhandledPromiseRejectionWarning'.
* @type {UnhandledRejectionsModeHandler}
*/
function strictUnhandledRejectionsMode(promise, promiseInfo, promiseAsyncId) {
const reason = promiseInfo.reason;
const err = isErrorLike(reason) ?
reason : new UnhandledPromiseRejection(reason);
// This destroys the async stack, don't clear it after
triggerUncaughtException(err, true /* fromPromise */);
if (promiseAsyncId === undefined) {
pushAsyncContext(
promise[kAsyncIdSymbol],
promise[kTriggerAsyncIdSymbol],
promise,
);
}
const handled = emitUnhandledRejection(promise, promiseInfo);
if (!handled) emitUnhandledRejectionWarning(promiseInfo);
return true;
}
/**
* --unhandled-rejections=none:
* Emit 'unhandledRejection', but do not emit any warning.
* @type {UnhandledRejectionsModeHandler}
*/
function ignoreUnhandledRejectionsMode(promise, promiseInfo) {
emitUnhandledRejection(promise, promiseInfo);
return true;
}
/**
* --unhandled-rejections=warn:
* Emit 'unhandledRejection', then emit 'UnhandledPromiseRejectionWarning'.
* @type {UnhandledRejectionsModeHandler}
*/
function alwaysWarnUnhandledRejectionsMode(promise, promiseInfo) {
emitUnhandledRejection(promise, promiseInfo);
emitUnhandledRejectionWarning(promiseInfo);
return true;
}
/**
* --unhandled-rejections=throw:
* Emit 'unhandledRejection', if it's unhandled, emit
* 'uncaughtException'. If it's not handled, print the error to stderr
* and exit the process.
* @type {UnhandledRejectionsModeHandler}
*/
function throwUnhandledRejectionsMode(promise, promiseInfo) {
const reason = promiseInfo.reason;
const handled = emitUnhandledRejection(promise, promiseInfo);
if (!handled) {
const err = isErrorLike(reason) ?
reason :
new UnhandledPromiseRejection(reason);
// This destroys the async stack, don't clear it after
triggerUncaughtException(err, true /* fromPromise */);
return false;
}
return true;
}
/**
* --unhandled-rejections=warn-with-error-code:
* Emit 'unhandledRejection', if it's unhandled, emit
* 'UnhandledPromiseRejectionWarning', then set process exit code to 1.
* @type {UnhandledRejectionsModeHandler}
*/
function warnWithErrorCodeUnhandledRejectionsMode(promise, promiseInfo) {
const handled = emitUnhandledRejection(promise, promiseInfo);
if (!handled) {
emitUnhandledRejectionWarning(promiseInfo);
process.exitCode = kGenericUserError;
}
return true;
}
/**
* @returns {UnhandledRejectionsModeHandler}
*/
function getUnhandledRejectionsMode() {
const { getOptionValue } = require('internal/options');
switch (getOptionValue('--unhandled-rejections')) {
case 'none':
return ignoreUnhandledRejectionsMode;
case 'warn':
return alwaysWarnUnhandledRejectionsMode;
case 'strict':
return strictUnhandledRejectionsMode;
case 'throw':
return throwUnhandledRejectionsMode;
case 'warn-with-error-code':
return warnWithErrorCodeUnhandledRejectionsMode;
default:
return throwUnhandledRejectionsMode;
}
}
// If this method returns true, we've executed user code or triggered
// a warning to be emitted which requires the microtask and next tick
// queues to be drained again.
function processPromiseRejections() {
let maybeScheduledTicksOrMicrotasks = asyncHandledRejections.length > 0;
while (asyncHandledRejections.length !== 0) {
const { promise, warning } = ArrayPrototypeShift(asyncHandledRejections);
if (!process.emit('rejectionHandled', promise)) {
process.emitWarning(warning);
}
}
let needPop = true;
let promiseAsyncId;
const pending = pendingUnhandledRejections;
pendingUnhandledRejections = new SafeMap();
for (const { 0: promise, 1: promiseInfo } of pending.entries()) {
maybeUnhandledPromises.set(promise, promiseInfo);
promiseInfo.warned = true;
// We need to check if async_hooks are enabled
// don't use enabledHooksExist as a Promise could
// come from a vm.* context and not have an async id
promiseAsyncId = promise[kAsyncIdSymbol];
if (promiseAsyncId !== undefined) {
pushAsyncContext(
promiseAsyncId,
promise[kTriggerAsyncIdSymbol],
promise,
);
}
const { contextFrame } = promiseInfo;
const priorContextFrame = AsyncContextFrame.exchange(contextFrame);
try {
needPop = unhandledRejectionsMode(promise, promiseInfo, promiseAsyncId);
} finally {
AsyncContextFrame.set(priorContextFrame);
needPop &&
promiseAsyncId !== undefined &&
popAsyncContext(promiseAsyncId);
}
maybeScheduledTicksOrMicrotasks = true;
}
return maybeScheduledTicksOrMicrotasks ||
pendingUnhandledRejections.size !== 0;
}
function listenForRejections() {
setPromiseRejectCallback(promiseRejectHandler);
}
module.exports = {
hasRejectionToWarn,
setHasRejectionToWarn,
listenForRejections,
processPromiseRejections,
};

View File

@ -0,0 +1,140 @@
'use strict';
const {
JSONParse,
} = primordials;
const {
ERR_SYNTHETIC,
} = require('internal/errors').codes;
const { getValidatedPath } = require('internal/fs/utils');
const {
validateBoolean,
validateObject,
validateSignalName,
validateString,
} = require('internal/validators');
const nr = internalBinding('report');
const report = {
writeReport(file, err) {
if (typeof file === 'object' && file !== null) {
err = file;
file = undefined;
} else if (file !== undefined) {
validateString(file, 'file');
file = getValidatedPath(file);
}
if (err === undefined) {
err = new ERR_SYNTHETIC();
} else {
validateObject(err, 'err');
}
return nr.writeReport('JavaScript API', 'API', file, err);
},
getReport(err) {
if (err === undefined)
err = new ERR_SYNTHETIC();
else
validateObject(err, 'err');
return JSONParse(nr.getReport(err));
},
get directory() {
return nr.getDirectory();
},
set directory(dir) {
validateString(dir, 'directory');
nr.setDirectory(dir);
},
get filename() {
return nr.getFilename();
},
set filename(name) {
validateString(name, 'filename');
nr.setFilename(name);
},
get compact() {
return nr.getCompact();
},
set compact(b) {
validateBoolean(b, 'compact');
nr.setCompact(b);
},
get excludeNetwork() {
return nr.getExcludeNetwork();
},
set excludeNetwork(b) {
validateBoolean(b, 'excludeNetwork');
nr.setExcludeNetwork(b);
},
get signal() {
return nr.getSignal();
},
set signal(sig) {
validateSignalName(sig, 'signal');
removeSignalHandler();
addSignalHandler(sig);
nr.setSignal(sig);
},
get reportOnFatalError() {
return nr.shouldReportOnFatalError();
},
set reportOnFatalError(trigger) {
validateBoolean(trigger, 'trigger');
nr.setReportOnFatalError(trigger);
},
get reportOnSignal() {
return nr.shouldReportOnSignal();
},
set reportOnSignal(trigger) {
validateBoolean(trigger, 'trigger');
nr.setReportOnSignal(trigger);
removeSignalHandler();
addSignalHandler();
},
get reportOnUncaughtException() {
return nr.shouldReportOnUncaughtException();
},
set reportOnUncaughtException(trigger) {
validateBoolean(trigger, 'trigger');
nr.setReportOnUncaughtException(trigger);
},
get excludeEnv() {
return nr.getExcludeEnv();
},
set excludeEnv(b) {
validateBoolean(b, 'excludeEnv');
nr.setExcludeEnv(b);
},
};
function addSignalHandler(sig) {
if (nr.shouldReportOnSignal()) {
if (typeof sig !== 'string')
sig = nr.getSignal();
process.on(sig, signalHandler);
}
}
function removeSignalHandler() {
const sig = nr.getSignal();
if (sig)
process.removeListener(sig, signalHandler);
}
function signalHandler(sig) {
nr.writeReport(sig, 'Signal', null, '');
}
module.exports = {
addSignalHandler,
report,
};

View File

@ -0,0 +1,54 @@
'use strict';
const {
FunctionPrototypeBind,
SafeMap,
} = primordials;
const {
ErrnoException,
} = require('internal/errors');
const { signals } = internalBinding('constants').os;
let Signal;
const signalWraps = new SafeMap();
function isSignal(event) {
return typeof event === 'string' && signals[event] !== undefined;
}
// Detect presence of a listener for the special signal types
function startListeningIfSignal(type) {
if (isSignal(type) && !signalWraps.has(type)) {
if (Signal === undefined)
Signal = internalBinding('signal_wrap').Signal;
const wrap = new Signal();
wrap.unref();
wrap.onsignal = FunctionPrototypeBind(process.emit, process, type, type);
const signum = signals[type];
const err = wrap.start(signum);
if (err) {
wrap.close();
throw new ErrnoException(err, 'uv_signal_start');
}
signalWraps.set(type, wrap);
}
}
function stopListeningIfSignal(type) {
const wrap = signalWraps.get(type);
if (wrap !== undefined && process.listenerCount(type) === 0) {
wrap.close();
signalWraps.delete(type);
}
}
module.exports = {
startListeningIfSignal,
stopListeningIfSignal,
};

View File

@ -0,0 +1,184 @@
'use strict';
const {
Array,
FunctionPrototypeBind,
Symbol,
} = primordials;
const {
// For easy access to the nextTick state in the C++ land,
// and to avoid unnecessary calls into JS land.
tickInfo,
// Used to run V8's micro task queue.
runMicrotasks,
setTickCallback,
enqueueMicrotask,
} = internalBinding('task_queue');
const {
setHasRejectionToWarn,
hasRejectionToWarn,
listenForRejections,
processPromiseRejections,
} = require('internal/process/promises');
const {
getDefaultTriggerAsyncId,
newAsyncId,
initHooksExist,
destroyHooksExist,
emitInit,
emitBefore,
emitAfter,
emitDestroy,
symbols: { async_id_symbol, trigger_async_id_symbol },
} = require('internal/async_hooks');
const FixedQueue = require('internal/fixed_queue');
const {
validateFunction,
} = require('internal/validators');
const { AsyncResource } = require('async_hooks');
const AsyncContextFrame = require('internal/async_context_frame');
const async_context_frame = Symbol('kAsyncContextFrame');
// *Must* match Environment::TickInfo::Fields in src/env.h.
const kHasTickScheduled = 0;
function hasTickScheduled() {
return tickInfo[kHasTickScheduled] === 1;
}
function setHasTickScheduled(value) {
tickInfo[kHasTickScheduled] = value ? 1 : 0;
}
const queue = new FixedQueue();
// Should be in sync with RunNextTicksNative in node_task_queue.cc
function runNextTicks() {
if (!hasTickScheduled() && !hasRejectionToWarn())
runMicrotasks();
if (!hasTickScheduled() && !hasRejectionToWarn())
return;
processTicksAndRejections();
}
function processTicksAndRejections() {
let tock;
do {
while ((tock = queue.shift()) !== null) {
const priorContextFrame =
AsyncContextFrame.exchange(tock[async_context_frame]);
const asyncId = tock[async_id_symbol];
emitBefore(asyncId, tock[trigger_async_id_symbol], tock);
try {
const callback = tock.callback;
if (tock.args === undefined) {
callback();
} else {
const args = tock.args;
switch (args.length) {
case 1: callback(args[0]); break;
case 2: callback(args[0], args[1]); break;
case 3: callback(args[0], args[1], args[2]); break;
case 4: callback(args[0], args[1], args[2], args[3]); break;
default: callback(...args);
}
}
} finally {
if (destroyHooksExist())
emitDestroy(asyncId);
}
emitAfter(asyncId);
AsyncContextFrame.set(priorContextFrame);
}
runMicrotasks();
} while (!queue.isEmpty() || processPromiseRejections());
setHasTickScheduled(false);
setHasRejectionToWarn(false);
}
// `nextTick()` will not enqueue any callback when the process is about to
// exit since the callback would not have a chance to be executed.
function nextTick(callback) {
validateFunction(callback, 'callback');
if (process._exiting)
return;
let args;
switch (arguments.length) {
case 1: break;
case 2: args = [arguments[1]]; break;
case 3: args = [arguments[1], arguments[2]]; break;
case 4: args = [arguments[1], arguments[2], arguments[3]]; break;
default:
args = new Array(arguments.length - 1);
for (let i = 1; i < arguments.length; i++)
args[i - 1] = arguments[i];
}
if (queue.isEmpty())
setHasTickScheduled(true);
const asyncId = newAsyncId();
const triggerAsyncId = getDefaultTriggerAsyncId();
const tickObject = {
[async_id_symbol]: asyncId,
[trigger_async_id_symbol]: triggerAsyncId,
[async_context_frame]: AsyncContextFrame.current(),
callback,
args,
};
if (initHooksExist())
emitInit(asyncId, 'TickObject', triggerAsyncId, tickObject);
queue.push(tickObject);
}
function runMicrotask() {
this.runInAsyncScope(() => {
const callback = this.callback;
try {
callback();
} finally {
this.emitDestroy();
}
});
}
const defaultMicrotaskResourceOpts = { requireManualDestroy: true };
function queueMicrotask(callback) {
validateFunction(callback, 'callback');
const asyncResource = new AsyncResource(
'Microtask',
defaultMicrotaskResourceOpts,
);
asyncResource.callback = callback;
enqueueMicrotask(FunctionPrototypeBind(runMicrotask, asyncResource));
}
module.exports = {
setupTaskQueue() {
// Sets the per-isolate promise rejection callback
listenForRejections();
// Sets the callback to be run in every tick.
setTickCallback(processTicksAndRejections);
return {
nextTick,
runNextTicks,
};
},
queueMicrotask,
};

View File

@ -0,0 +1,208 @@
'use strict';
const {
ArrayIsArray,
Error,
ErrorCaptureStackTrace,
ErrorPrototypeToString,
SafeSet,
String,
} = primordials;
const {
getOptionValue,
} = require('internal/options');
const assert = require('internal/assert');
const {
codes: {
ERR_INVALID_ARG_TYPE,
},
isErrorStackTraceLimitWritable,
} = require('internal/errors');
const { validateString } = require('internal/validators');
// Lazily loaded
let fs;
let fd;
let warningFile;
let traceWarningHelperShown = false;
function resetForSerialization() {
if (fd !== undefined) {
process.removeListener('exit', closeFdOnExit);
}
fd = undefined;
warningFile = undefined;
traceWarningHelperShown = false;
}
function lazyOption() {
// This will load `warningFile` only once. If the flag is not set,
// `warningFile` will be set to an empty string.
if (warningFile === undefined) {
const diagnosticDir = getOptionValue('--diagnostic-dir');
const redirectWarnings = getOptionValue('--redirect-warnings');
warningFile = diagnosticDir || redirectWarnings || '';
}
return warningFile;
}
// If we can't write to stderr, we'd like to make this a noop,
// so use console.error.
let error;
function writeOut(message) {
error ??= require('internal/console/global').error;
error(message);
}
function closeFdOnExit() {
try {
fs.closeSync(fd);
} catch {
// Continue regardless of error.
}
}
function writeToFile(message) {
if (fd === undefined) {
fs = require('fs');
try {
fd = fs.openSync(warningFile, 'a');
} catch {
return writeOut(message);
}
process.on('exit', closeFdOnExit);
}
fs.appendFile(fd, `${message}\n`, (err) => {
if (err) {
writeOut(message);
}
});
}
function doEmitWarning(warning) {
process.emit('warning', warning);
}
let disableWarningSet;
function onWarning(warning) {
if (!disableWarningSet) {
disableWarningSet = new SafeSet();
const disableWarningValues = getOptionValue('--disable-warning');
for (let i = 0; i < disableWarningValues.length; i++) {
disableWarningSet.add(disableWarningValues[i]);
}
}
if ((warning?.code && disableWarningSet.has(warning.code)) ||
(warning?.name && disableWarningSet.has(warning.name))) return;
if (!(warning instanceof Error)) return;
const isDeprecation = warning.name === 'DeprecationWarning';
if (isDeprecation && process.noDeprecation) return;
const trace = process.traceProcessWarnings ||
(isDeprecation && process.traceDeprecation);
let msg = `(${process.release.name}:${process.pid}) `;
if (warning.code)
msg += `[${warning.code}] `;
if (trace && warning.stack) {
msg += `${warning.stack}`;
} else {
msg +=
typeof warning.toString === 'function' ?
`${warning.toString()}` :
ErrorPrototypeToString(warning);
}
if (typeof warning.detail === 'string') {
msg += `\n${warning.detail}`;
}
if (!trace && !traceWarningHelperShown) {
const flag = isDeprecation ? '--trace-deprecation' : '--trace-warnings';
const argv0 = require('path').basename(process.argv0 || 'node', '.exe');
msg += `\n(Use \`${argv0} ${flag} ...\` to show where the warning ` +
'was created)';
traceWarningHelperShown = true;
}
const warningFile = lazyOption();
if (warningFile) {
return writeToFile(msg);
}
writeOut(msg);
}
// process.emitWarning(error)
// process.emitWarning(str[, type[, code]][, ctor])
// process.emitWarning(str[, options])
function emitWarning(warning, type, code, ctor) {
// Fast path to avoid memory allocation,
// this doesn't eliminate the other if a few lines below
if (process.noDeprecation && type === 'DeprecationWarning') {
return;
}
let detail;
if (type !== null && typeof type === 'object' && !ArrayIsArray(type)) {
ctor = type.ctor;
code = type.code;
if (typeof type.detail === 'string')
detail = type.detail;
type = type.type || 'Warning';
} else if (typeof type === 'function') {
ctor = type;
code = undefined;
type = 'Warning';
}
if (type !== undefined)
validateString(type, 'type');
if (typeof code === 'function') {
ctor = code;
code = undefined;
} else if (code !== undefined) {
validateString(code, 'code');
}
if (typeof warning === 'string') {
warning = createWarningObject(warning, type, code, ctor, detail);
} else if (!(warning instanceof Error)) {
throw new ERR_INVALID_ARG_TYPE('warning', ['Error', 'string'], warning);
}
if (warning.name === 'DeprecationWarning') {
if (process.noDeprecation)
return;
if (process.throwDeprecation) {
// Delay throwing the error to guarantee that all former warnings were
// properly logged.
return process.nextTick(() => {
throw warning;
});
}
}
process.nextTick(doEmitWarning, warning);
}
function emitWarningSync(warning, type, code, ctor) {
process.emit('warning', createWarningObject(warning, type, code, ctor));
}
function createWarningObject(warning, type, code, ctor, detail) {
assert(typeof warning === 'string');
// Improve error creation performance by skipping the error frames.
// They are added in the `captureStackTrace()` function below.
const tmpStackLimit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
// eslint-disable-next-line no-restricted-syntax
warning = new Error(warning);
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpStackLimit;
warning.name = String(type || 'Warning');
if (code !== undefined) warning.code = code;
if (detail !== undefined) warning.detail = detail;
ErrorCaptureStackTrace(warning, ctor || process.emitWarning);
return warning;
}
module.exports = {
emitWarning,
emitWarningSync,
onWarning,
resetForSerialization,
};

View File

@ -0,0 +1,23 @@
'use strict';
// This file contains process bootstrappers that can only be
// run in the worker thread.
const {
codes: {
ERR_WORKER_UNSUPPORTED_OPERATION,
},
} = require('internal/errors');
function unavailable(name) {
function unavailableInWorker() {
throw new ERR_WORKER_UNSUPPORTED_OPERATION(name);
}
unavailableInWorker.disabled = true;
return unavailableInWorker;
}
module.exports = {
unavailable,
};