diff options
author | Joyee Cheung <joyeec9h3@gmail.com> | 2018-11-27 01:50:41 +0800 |
---|---|---|
committer | Joyee Cheung <joyeec9h3@gmail.com> | 2018-12-04 05:54:49 +0800 |
commit | edcb9500902437a7edf912b27f259c173ce14767 (patch) | |
tree | c6325da716f8004c8e5a0954a0a6466c4f745753 | |
parent | fa19ce92339edb0d741bfe1855ac39d4bc80e1d2 (diff) | |
download | node-new-edcb9500902437a7edf912b27f259c173ce14767.tar.gz |
src: use NativeModuleLoader to compile all the bootstrappers
This patch moves all the bootstrapper compilation to use
NativeModuleLoader::CompileAndCall(). With this we no longer
need to mess with the error decoration and handling any more -
there is no point in handling the JS error occurred during bootstrapping
by ourselves, we should just crash or let the VM handle it.
PR-URL: https://github.com/nodejs/node/pull/24775
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
-rw-r--r-- | lib/internal/bootstrap/loaders.js | 587 | ||||
-rw-r--r-- | lib/internal/bootstrap/node.js | 1234 | ||||
-rw-r--r-- | lib/internal/per_context.js | 6 | ||||
-rw-r--r-- | src/node.cc | 210 | ||||
-rw-r--r-- | test/message/eval_messages.out | 8 | ||||
-rw-r--r-- | test/message/events_unhandled_error_nexttick.out | 2 | ||||
-rw-r--r-- | test/message/nexttick_throw.out | 2 |
7 files changed, 975 insertions, 1074 deletions
diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index 88227f2927..155d9c9239 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -39,335 +39,336 @@ 'use strict'; -(function bootstrapInternalLoaders(process, getBinding, getLinkedBinding, - getInternalBinding, debugBreak) { - if (debugBreak) - debugger; // eslint-disable-line no-debugger - - const { - apply: ReflectApply, - deleteProperty: ReflectDeleteProperty, - get: ReflectGet, - getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor, - has: ReflectHas, - set: ReflectSet, - } = Reflect; - const { - prototype: { - hasOwnProperty: ObjectHasOwnProperty, - }, - create: ObjectCreate, - defineProperty: ObjectDefineProperty, - keys: ObjectKeys, - } = Object; - - // Set up process.moduleLoadList. - const moduleLoadList = []; - ObjectDefineProperty(process, 'moduleLoadList', { - value: moduleLoadList, - configurable: true, - enumerable: true, - writable: false - }); - - // internalBindingWhitelist contains the name of internalBinding modules - // that are whitelisted for access via process.binding()... This is used - // to provide a transition path for modules that are being moved over to - // internalBinding. - const internalBindingWhitelist = [ - 'async_wrap', - 'buffer', - 'cares_wrap', - 'constants', - 'contextify', - 'crypto', - 'fs', - 'fs_event_wrap', - 'http_parser', - 'icu', - 'js_stream', - 'natives', - 'pipe_wrap', - 'process_wrap', - 'signal_wrap', - 'spawn_sync', - 'stream_wrap', - 'tcp_wrap', - 'tls_wrap', - 'tty_wrap', - 'udp_wrap', - 'url', - 'util', - 'uv', - 'v8', - 'zlib' - ]; - // We will use a lazy loaded SafeSet in internalBindingWhitelistHas - // for checking existence in this list. - let internalBindingWhitelistSet; - - // Set up process.binding() and process._linkedBinding(). - { - const bindingObj = ObjectCreate(null); - - process.binding = function binding(module) { - module = String(module); - // Deprecated specific process.binding() modules, but not all, allow - // selective fallback to internalBinding for the deprecated ones. - if (internalBindingWhitelistHas(module)) { - return internalBinding(module); - } - let mod = bindingObj[module]; - if (typeof mod !== 'object') { - mod = bindingObj[module] = getBinding(module); - moduleLoadList.push(`Binding ${module}`); - } - return mod; - }; - - process._linkedBinding = function _linkedBinding(module) { - module = String(module); - let mod = bindingObj[module]; - if (typeof mod !== 'object') - mod = bindingObj[module] = getLinkedBinding(module); - return mod; - }; - } +// This file is compiled as if it's wrapped in a function with arguments +// passed by node::LoadEnvironment() +/* global process, getBinding, getLinkedBinding, getInternalBinding */ +/* global debugBreak */ + +if (debugBreak) + debugger; // eslint-disable-line no-debugger + +const { + apply: ReflectApply, + deleteProperty: ReflectDeleteProperty, + get: ReflectGet, + getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor, + has: ReflectHas, + set: ReflectSet, +} = Reflect; +const { + prototype: { + hasOwnProperty: ObjectHasOwnProperty, + }, + create: ObjectCreate, + defineProperty: ObjectDefineProperty, + keys: ObjectKeys, +} = Object; + +// Set up process.moduleLoadList. +const moduleLoadList = []; +ObjectDefineProperty(process, 'moduleLoadList', { + value: moduleLoadList, + configurable: true, + enumerable: true, + writable: false +}); - // Set up internalBinding() in the closure. - let internalBinding; - { - const bindingObj = ObjectCreate(null); - internalBinding = function internalBinding(module) { - let mod = bindingObj[module]; - if (typeof mod !== 'object') { - mod = bindingObj[module] = getInternalBinding(module); - moduleLoadList.push(`Internal Binding ${module}`); - } - return mod; - }; - } +// internalBindingWhitelist contains the name of internalBinding modules +// that are whitelisted for access via process.binding()... This is used +// to provide a transition path for modules that are being moved over to +// internalBinding. +const internalBindingWhitelist = [ + 'async_wrap', + 'buffer', + 'cares_wrap', + 'constants', + 'contextify', + 'crypto', + 'fs', + 'fs_event_wrap', + 'http_parser', + 'icu', + 'js_stream', + 'natives', + 'pipe_wrap', + 'process_wrap', + 'signal_wrap', + 'spawn_sync', + 'stream_wrap', + 'tcp_wrap', + 'tls_wrap', + 'tty_wrap', + 'udp_wrap', + 'url', + 'util', + 'uv', + 'v8', + 'zlib' +]; +// We will use a lazy loaded SafeSet in internalBindingWhitelistHas +// for checking existence in this list. +let internalBindingWhitelistSet; + +// Set up process.binding() and process._linkedBinding(). +{ + const bindingObj = ObjectCreate(null); + + process.binding = function binding(module) { + module = String(module); + // Deprecated specific process.binding() modules, but not all, allow + // selective fallback to internalBinding for the deprecated ones. + if (internalBindingWhitelistHas(module)) { + return internalBinding(module); + } + let mod = bindingObj[module]; + if (typeof mod !== 'object') { + mod = bindingObj[module] = getBinding(module); + moduleLoadList.push(`Binding ${module}`); + } + return mod; + }; - // Create this WeakMap in js-land because V8 has no C++ API for WeakMap. - internalBinding('module_wrap').callbackMap = new WeakMap(); - - // Set up NativeModule. - function NativeModule(id) { - this.filename = `${id}.js`; - this.id = id; - this.exports = {}; - this.reflect = undefined; - this.exportKeys = undefined; - this.loaded = false; - this.loading = false; + process._linkedBinding = function _linkedBinding(module) { + module = String(module); + let mod = bindingObj[module]; + if (typeof mod !== 'object') + mod = bindingObj[module] = getLinkedBinding(module); + return mod; + }; +} + +// Set up internalBinding() in the closure. +let internalBinding; +{ + const bindingObj = ObjectCreate(null); + internalBinding = function internalBinding(module) { + let mod = bindingObj[module]; + if (typeof mod !== 'object') { + mod = bindingObj[module] = getInternalBinding(module); + moduleLoadList.push(`Internal Binding ${module}`); + } + return mod; + }; +} + +// Create this WeakMap in js-land because V8 has no C++ API for WeakMap. +internalBinding('module_wrap').callbackMap = new WeakMap(); + +// Set up NativeModule. +function NativeModule(id) { + this.filename = `${id}.js`; + this.id = id; + this.exports = {}; + this.reflect = undefined; + this.exportKeys = undefined; + this.loaded = false; + this.loading = false; +} + +NativeModule._source = getInternalBinding('natives'); +NativeModule._cache = {}; + +const config = getBinding('config'); + +// Think of this as module.exports in this file even though it is not +// written in CommonJS style. +const loaderExports = { internalBinding, NativeModule }; +const loaderId = 'internal/bootstrap/loaders'; + +NativeModule.require = function(id) { + if (id === loaderId) { + return loaderExports; } - NativeModule._source = getInternalBinding('natives'); - NativeModule._cache = {}; - - const config = getBinding('config'); + const cached = NativeModule.getCached(id); + if (cached && (cached.loaded || cached.loading)) { + return cached.exports; + } - // Think of this as module.exports in this file even though it is not - // written in CommonJS style. - const loaderExports = { internalBinding, NativeModule }; - const loaderId = 'internal/bootstrap/loaders'; + if (!NativeModule.exists(id)) { + // Model the error off the internal/errors.js model, but + // do not use that module given that it could actually be + // the one causing the error if there's a bug in Node.js. + // eslint-disable-next-line no-restricted-syntax + const err = new Error(`No such built-in module: ${id}`); + err.code = 'ERR_UNKNOWN_BUILTIN_MODULE'; + err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]'; + throw err; + } - NativeModule.require = function(id) { - if (id === loaderId) { - return loaderExports; - } + moduleLoadList.push(`NativeModule ${id}`); - const cached = NativeModule.getCached(id); - if (cached && (cached.loaded || cached.loading)) { - return cached.exports; - } + const nativeModule = new NativeModule(id); - if (!NativeModule.exists(id)) { - // Model the error off the internal/errors.js model, but - // do not use that module given that it could actually be - // the one causing the error if there's a bug in Node.js. - // eslint-disable-next-line no-restricted-syntax - const err = new Error(`No such built-in module: ${id}`); - err.code = 'ERR_UNKNOWN_BUILTIN_MODULE'; - err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]'; - throw err; - } + nativeModule.cache(); + nativeModule.compile(); - moduleLoadList.push(`NativeModule ${id}`); + return nativeModule.exports; +}; - const nativeModule = new NativeModule(id); +NativeModule.isDepsModule = function(id) { + return id.startsWith('node-inspect/') || id.startsWith('v8/'); +}; - nativeModule.cache(); - nativeModule.compile(); +NativeModule.requireForDeps = function(id) { + if (!NativeModule.exists(id) || + // TODO(TimothyGu): remove when DEP0084 reaches end of life. + NativeModule.isDepsModule(id)) { + id = `internal/deps/${id}`; + } + return NativeModule.require(id); +}; - return nativeModule.exports; - }; +NativeModule.getCached = function(id) { + return NativeModule._cache[id]; +}; - NativeModule.isDepsModule = function(id) { - return id.startsWith('node-inspect/') || id.startsWith('v8/'); - }; +NativeModule.exists = function(id) { + return NativeModule._source.hasOwnProperty(id); +}; - NativeModule.requireForDeps = function(id) { - if (!NativeModule.exists(id) || - // TODO(TimothyGu): remove when DEP0084 reaches end of life. - NativeModule.isDepsModule(id)) { - id = `internal/deps/${id}`; +if (config.exposeInternals) { + NativeModule.nonInternalExists = function(id) { + // Do not expose this to user land even with --expose-internals. + if (id === loaderId) { + return false; } - return NativeModule.require(id); + return NativeModule.exists(id); }; - NativeModule.getCached = function(id) { - return NativeModule._cache[id]; + NativeModule.isInternal = function(id) { + // Do not expose this to user land even with --expose-internals. + return id === loaderId; }; - - NativeModule.exists = function(id) { - return NativeModule._source.hasOwnProperty(id); +} else { + NativeModule.nonInternalExists = function(id) { + return NativeModule.exists(id) && !NativeModule.isInternal(id); }; - if (config.exposeInternals) { - NativeModule.nonInternalExists = function(id) { - // Do not expose this to user land even with --expose-internals. - if (id === loaderId) { - return false; - } - return NativeModule.exists(id); - }; - - NativeModule.isInternal = function(id) { - // Do not expose this to user land even with --expose-internals. - return id === loaderId; - }; - } else { - NativeModule.nonInternalExists = function(id) { - return NativeModule.exists(id) && !NativeModule.isInternal(id); - }; - - NativeModule.isInternal = function(id) { - return id.startsWith('internal/') || - (id === 'worker_threads' && !config.experimentalWorker); - }; - } - - NativeModule.getSource = function(id) { - return NativeModule._source[id]; + NativeModule.isInternal = function(id) { + return id.startsWith('internal/') || + (id === 'worker_threads' && !config.experimentalWorker); }; - - NativeModule.wrap = function(script) { - return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; +} + +NativeModule.getSource = function(id) { + return NativeModule._source[id]; +}; + +NativeModule.wrap = function(script) { + return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; +}; + +NativeModule.wrapper = [ + '(function (exports, require, module, process, internalBinding) {', + '\n});' +]; + +const getOwn = (target, property, receiver) => { + return ReflectApply(ObjectHasOwnProperty, target, [property]) ? + ReflectGet(target, property, receiver) : + undefined; +}; + +// Provide named exports for all builtin libraries so that the libraries +// may be imported in a nicer way for ESM users. The default export is left +// as the entire namespace (module.exports) and wrapped in a proxy such +// that APMs and other behavior are still left intact. +NativeModule.prototype.proxifyExports = function() { + this.exportKeys = ObjectKeys(this.exports); + + const update = (property, value) => { + if (this.reflect !== undefined && + ReflectApply(ObjectHasOwnProperty, + this.reflect.exports, [property])) + this.reflect.exports[property].set(value); }; - NativeModule.wrapper = [ - '(function (exports, require, module, process, internalBinding) {', - '\n});' - ]; - - const getOwn = (target, property, receiver) => { - return ReflectApply(ObjectHasOwnProperty, target, [property]) ? - ReflectGet(target, property, receiver) : - undefined; - }; - - // Provide named exports for all builtin libraries so that the libraries - // may be imported in a nicer way for ESM users. The default export is left - // as the entire namespace (module.exports) and wrapped in a proxy such - // that APMs and other behavior are still left intact. - NativeModule.prototype.proxifyExports = function() { - this.exportKeys = ObjectKeys(this.exports); - - const update = (property, value) => { - if (this.reflect !== undefined && - ReflectApply(ObjectHasOwnProperty, - this.reflect.exports, [property])) - this.reflect.exports[property].set(value); - }; - - const handler = { - __proto__: null, - defineProperty: (target, prop, descriptor) => { - // Use `Object.defineProperty` instead of `Reflect.defineProperty` - // to throw the appropriate error if something goes wrong. - ObjectDefineProperty(target, prop, descriptor); - if (typeof descriptor.get === 'function' && - !ReflectHas(handler, 'get')) { - handler.get = (target, prop, receiver) => { - const value = ReflectGet(target, prop, receiver); - if (ReflectApply(ObjectHasOwnProperty, target, [prop])) - update(prop, value); - return value; - }; - } - update(prop, getOwn(target, prop)); + const handler = { + __proto__: null, + defineProperty: (target, prop, descriptor) => { + // Use `Object.defineProperty` instead of `Reflect.defineProperty` + // to throw the appropriate error if something goes wrong. + ObjectDefineProperty(target, prop, descriptor); + if (typeof descriptor.get === 'function' && + !ReflectHas(handler, 'get')) { + handler.get = (target, prop, receiver) => { + const value = ReflectGet(target, prop, receiver); + if (ReflectApply(ObjectHasOwnProperty, target, [prop])) + update(prop, value); + return value; + }; + } + update(prop, getOwn(target, prop)); + return true; + }, + deleteProperty: (target, prop) => { + if (ReflectDeleteProperty(target, prop)) { + update(prop, undefined); return true; - }, - deleteProperty: (target, prop) => { - if (ReflectDeleteProperty(target, prop)) { - update(prop, undefined); - return true; - } - return false; - }, - set: (target, prop, value, receiver) => { - const descriptor = ReflectGetOwnPropertyDescriptor(target, prop); - if (ReflectSet(target, prop, value, receiver)) { - if (descriptor && typeof descriptor.set === 'function') { - for (const key of this.exportKeys) { - update(key, getOwn(target, key, receiver)); - } - } else { - update(prop, getOwn(target, prop, receiver)); + } + return false; + }, + set: (target, prop, value, receiver) => { + const descriptor = ReflectGetOwnPropertyDescriptor(target, prop); + if (ReflectSet(target, prop, value, receiver)) { + if (descriptor && typeof descriptor.set === 'function') { + for (const key of this.exportKeys) { + update(key, getOwn(target, key, receiver)); } - return true; + } else { + update(prop, getOwn(target, prop, receiver)); } - return false; + return true; } - }; - - this.exports = new Proxy(this.exports, handler); + return false; + } }; - const { compileFunction } = getInternalBinding('native_module'); - NativeModule.prototype.compile = function() { - const id = this.id; + this.exports = new Proxy(this.exports, handler); +}; - this.loading = true; +const { compileFunction } = getInternalBinding('native_module'); +NativeModule.prototype.compile = function() { + const id = this.id; - try { - const requireFn = this.id.startsWith('internal/deps/') ? - NativeModule.requireForDeps : - NativeModule.require; + this.loading = true; - const fn = compileFunction(id); - fn(this.exports, requireFn, this, process, internalBinding); + try { + const requireFn = this.id.startsWith('internal/deps/') ? + NativeModule.requireForDeps : + NativeModule.require; - if (config.experimentalModules && !NativeModule.isInternal(this.id)) { - this.proxifyExports(); - } + const fn = compileFunction(id); + fn(this.exports, requireFn, this, process, internalBinding); - this.loaded = true; - } finally { - this.loading = false; + if (config.experimentalModules && !NativeModule.isInternal(this.id)) { + this.proxifyExports(); } - }; - NativeModule.prototype.cache = function() { - NativeModule._cache[this.id] = this; - }; - - // Coverage must be turned on early, so that we can collect - // it for Node.js' own internal libraries. - if (process.env.NODE_V8_COVERAGE) { - NativeModule.require('internal/process/coverage').setup(); + this.loaded = true; + } finally { + this.loading = false; } - - function internalBindingWhitelistHas(name) { - if (!internalBindingWhitelistSet) { - const { SafeSet } = NativeModule.require('internal/safe_globals'); - internalBindingWhitelistSet = new SafeSet(internalBindingWhitelist); - } - return internalBindingWhitelistSet.has(name); +}; + +NativeModule.prototype.cache = function() { + NativeModule._cache[this.id] = this; +}; + +// Coverage must be turned on early, so that we can collect +// it for Node.js' own internal libraries. +if (process.env.NODE_V8_COVERAGE) { + NativeModule.require('internal/process/coverage').setup(); +} + +function internalBindingWhitelistHas(name) { + if (!internalBindingWhitelistSet) { + const { SafeSet } = NativeModule.require('internal/safe_globals'); + internalBindingWhitelistSet = new SafeSet(internalBindingWhitelist); } + return internalBindingWhitelistSet.has(name); +} - // This will be passed to the bootstrapNodeJSCore function in - // bootstrap/node.js. - return loaderExports; -}); +// This will be passed to internal/bootstrap/node.js. +return loaderExports; diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 220b706d7c..cdc1f06010 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -12,696 +12,696 @@ // into this bootstrapper to bootstrap Node.js core. 'use strict'; -(function bootstrapNodeJSCore(process, - // bootstrapper properties... destructured to - // avoid retaining a reference to the bootstrap - // object. - { _setupTraceCategoryState, - _setupNextTick, - _setupPromises, _chdir, _cpuUsage, - _hrtime, _hrtimeBigInt, - _memoryUsage, _rawDebug, - _umask, _initgroups, _setegid, _seteuid, - _setgid, _setuid, _setgroups, - _shouldAbortOnUncaughtToggle }, - { internalBinding, NativeModule }, - triggerFatalException) { - const exceptionHandlerState = { captureFn: null }; - const isMainThread = internalBinding('worker').threadId === 0; - - function startup() { - setupTraceCategoryState(); - - setupProcessObject(); - - // Do this good and early, since it handles errors. - setupProcessFatal(); - - setupProcessICUVersions(); - - 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' - ); - } - - perThreadSetup.setupAssert(); - perThreadSetup.setupConfig(NativeModule._source); +// This file is compiled as if it's wrapped in a function with arguments +// passed by node::LoadEnvironment() +/* global process, bootstrappers, loaderExports, triggerFatalException */ +const { + _setupTraceCategoryState, + _setupNextTick, + _setupPromises, _chdir, _cpuUsage, + _hrtime, _hrtimeBigInt, + _memoryUsage, _rawDebug, + _umask, _initgroups, _setegid, _seteuid, + _setgid, _setuid, _setgroups, + _shouldAbortOnUncaughtToggle +} = bootstrappers; +const { internalBinding, NativeModule } = loaderExports; + +const exceptionHandlerState = { captureFn: null }; +const isMainThread = internalBinding('worker').threadId === 0; + +function startup() { + setupTraceCategoryState(); + + setupProcessObject(); + + // Do this good and early, since it handles errors. + setupProcessFatal(); + + setupProcessICUVersions(); + + 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' + ); + } - if (isMainThread) { - mainThreadSetup.setupSignalHandlers(internalBinding); - } + perThreadSetup.setupAssert(); + perThreadSetup.setupConfig(NativeModule._source); - perThreadSetup.setupUncaughtExceptionCapture(exceptionHandlerState, - _shouldAbortOnUncaughtToggle); + if (isMainThread) { + mainThreadSetup.setupSignalHandlers(internalBinding); + } - NativeModule.require('internal/process/warning').setup(); - NativeModule.require('internal/process/next_tick').setup(_setupNextTick, - _setupPromises); + perThreadSetup.setupUncaughtExceptionCapture(exceptionHandlerState, + _shouldAbortOnUncaughtToggle); + + NativeModule.require('internal/process/warning').setup(); + NativeModule.require('internal/process/next_tick').setup(_setupNextTick, + _setupPromises); + + if (isMainThread) { + mainThreadSetup.setupStdio(); + mainThreadSetup.setupProcessMethods( + _chdir, _umask, _initgroups, _setegid, _seteuid, + _setgid, _setuid, _setgroups + ); + } else { + workerThreadSetup.setupStdio(); + } - if (isMainThread) { - mainThreadSetup.setupStdio(); - mainThreadSetup.setupProcessMethods( - _chdir, _umask, _initgroups, _setegid, _seteuid, - _setgid, _setuid, _setgroups - ); - } else { - workerThreadSetup.setupStdio(); - } + const perf = internalBinding('performance'); + const { + NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE, + } = perf.constants; - const perf = internalBinding('performance'); - const { - NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE, - } = perf.constants; + perThreadSetup.setupRawDebug(_rawDebug); + perThreadSetup.setupHrtime(_hrtime, _hrtimeBigInt); + perThreadSetup.setupCpuUsage(_cpuUsage); + perThreadSetup.setupMemoryUsage(_memoryUsage); + perThreadSetup.setupKillAndExit(); - perThreadSetup.setupRawDebug(_rawDebug); - perThreadSetup.setupHrtime(_hrtime, _hrtimeBigInt); - perThreadSetup.setupCpuUsage(_cpuUsage); - perThreadSetup.setupMemoryUsage(_memoryUsage); - perThreadSetup.setupKillAndExit(); + if (global.__coverage__) + NativeModule.require('internal/process/write-coverage').setup(); - if (global.__coverage__) - NativeModule.require('internal/process/write-coverage').setup(); - - if (process.env.NODE_V8_COVERAGE) { - NativeModule.require('internal/process/coverage').setupExitHooks(); - } + if (process.env.NODE_V8_COVERAGE) { + NativeModule.require('internal/process/coverage').setupExitHooks(); + } - if (process.config.variables.v8_enable_inspector) { - NativeModule.require('internal/inspector_async_hook').setup(); - } + if (process.config.variables.v8_enable_inspector) { + NativeModule.require('internal/inspector_async_hook').setup(); + } - const { getOptionValue } = NativeModule.require('internal/options'); + const { getOptionValue } = NativeModule.require('internal/options'); - if (getOptionValue('--help')) { - NativeModule.require('internal/print_help').print(process.stdout); - return; - } + if (getOptionValue('--help')) { + NativeModule.require('internal/print_help').print(process.stdout); + return; + } - if (getOptionValue('--completion-bash')) { - NativeModule.require('internal/bash_completion').print(process.stdout); - return; - } + if (getOptionValue('--completion-bash')) { + NativeModule.require('internal/bash_completion').print(process.stdout); + return; + } - if (isMainThread) { - mainThreadSetup.setupChildProcessIpcChannel(); - } + if (isMainThread) { + mainThreadSetup.setupChildProcessIpcChannel(); + } - const browserGlobals = !process._noBrowserGlobals; - if (browserGlobals) { - setupGlobalTimeouts(); - setupGlobalConsole(); - setupGlobalURL(); - setupGlobalEncoding(); - setupQueueMicrotask(); - } + const browserGlobals = !process._noBrowserGlobals; + if (browserGlobals) { + setupGlobalTimeouts(); + setupGlobalConsole(); + setupGlobalURL(); + setupGlobalEncoding(); + setupQueueMicrotask(); + } - if (getOptionValue('--experimental-worker')) { - setupDOMException(); - } + if (getOptionValue('--experimental-worker')) { + 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); - } + // 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; + 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); + } - // 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) { + const experimentalModules = getOptionValue('--experimental-modules'); + const experimentalVMModules = getOptionValue('--experimental-vm-modules'); + if (experimentalModules || experimentalVMModules) { + if (experimentalModules) { process.emitWarning( - '`node --inspect --debug-brk` is deprecated. ' + - 'Please use `node --inspect-brk` instead.', - 'DeprecationWarning', 'DEP0062', startup, true); + 'The ESM module loader is experimental.', + 'ExperimentalWarning', undefined); } + NativeModule.require('internal/process/esm_loader').setup(); + } - 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); - } - NativeModule.require('internal/process/esm_loader').setup(); + 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 } = process.binding('config'); + const utilBinding = internalBinding('util'); + const types = internalBinding('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]; } + } - 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 } = process.binding('config'); - const utilBinding = internalBinding('util'); - const types = internalBinding('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(jasnell): The following have been globals since around 2012. + // That's just silly. The underlying perfctr support has been removed + // so these are now deprecated non-ops that can be removed after one + // major release cycle. + if (process.platform === 'win32') { + function noop() {} + const names = [ + 'NET_SERVER_CONNECTION', + 'NET_SERVER_CONNECTION_CLOSE', + 'HTTP_SERVER_REQUEST', + 'HTTP_SERVER_RESPONSE', + 'HTTP_CLIENT_REQUEST', + 'HTTP_CLIENT_RESPONSE' + ]; + for (var n = 0; n < names.length; n++) { + Object.defineProperty(global, `COUNTER_${names[n]}`, { + configurable: true, + enumerable: false, + value: deprecate(noop, + `COUNTER_${names[n]}() is deprecated.`, + 'DEP0120') + }); } + } - // TODO(jasnell): The following have been globals since around 2012. - // That's just silly. The underlying perfctr support has been removed - // so these are now deprecated non-ops that can be removed after one - // major release cycle. - if (process.platform === 'win32') { - function noop() {} - const names = [ - 'NET_SERVER_CONNECTION', - 'NET_SERVER_CONNECTION_CLOSE', - 'HTTP_SERVER_REQUEST', - 'HTTP_SERVER_RESPONSE', - 'HTTP_CLIENT_REQUEST', - 'HTTP_CLIENT_RESPONSE' - ]; - for (var n = 0; n < names.length; n++) { - Object.defineProperty(global, `COUNTER_${names[n]}`, { - configurable: true, - enumerable: false, - value: deprecate(noop, - `COUNTER_${names[n]}() is deprecated.`, - 'DEP0120') - }); - } - } + perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE); - perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE); + perThreadSetup.setupAllowedFlags(); - perThreadSetup.setupAllowedFlags(); + startExecution(); +} - startExecution(); +// 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 startExecution() { + // This means we are in a Worker context, and any script execution + // will be directed by the worker module. + if (internalBinding('worker').getEnvMessagePort() !== undefined) { + NativeModule.require('internal/worker').setupChild(evalScript); + return; } - // 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 startExecution() { - // This means we are in a Worker context, and any script execution - // will be directed by the worker module. - if (internalBinding('worker').getEnvMessagePort() !== undefined) { - NativeModule.require('internal/worker').setupChild(evalScript); - return; - } + // 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 (NativeModule.exists('_third_party_main')) { + process.nextTick(() => { + NativeModule.require('_third_party_main'); + }); + return; + } - // 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 (NativeModule.exists('_third_party_main')) { - process.nextTick(() => { - NativeModule.require('_third_party_main'); - }); - return; + // `node inspect ...` or `node debug ...` + if (process.argv[1] === 'inspect' || process.argv[1] === 'debug') { + if (process.argv[1] === 'debug') { + process.emitWarning( + '`node debug` is deprecated. Please use `node inspect` instead.', + 'DeprecationWarning', 'DEP0068'); } - // `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; + } - // Start the debugger agent. - process.nextTick(() => { - NativeModule.require('internal/deps/node-inspect/lib/_inspect').start(); - }); - return; - } + // `node --prof-process` + // TODO(joyeecheung): use internal/options instead of process.profProcess + if (process.profProcess) { + NativeModule.require('internal/v8_prof_processor'); + return; + } - // `node --prof-process` - // TODO(joyeecheung): use internal/options instead of process.profProcess - if (process.profProcess) { - NativeModule.require('internal/v8_prof_processor'); - return; - } + // There is user code to be run. + prepareUserCodeExecution(); + executeUserCode(); +} + +function prepareUserCodeExecution() { + // If this is a worker in cluster mode, start up the communication + // channel. This needs to be done before any user code gets executed + // (including preload modules). + if (process.argv[1] && process.env.NODE_UNIQUE_ID) { + const cluster = NativeModule.require('cluster'); + cluster._setupWorker(); + // Make sure it's not accidentally inherited by child processes. + delete process.env.NODE_UNIQUE_ID; + } - // There is user code to be run. - prepareUserCodeExecution(); - executeUserCode(); + // For user code, we preload modules if `-r` is passed + // TODO(joyeecheung): use internal/options instead of + // process._preload_modules + if (process._preload_modules) { + const { + _preloadModules + } = NativeModule.require('internal/modules/cjs/loader'); + _preloadModules(process._preload_modules); + } +} + +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. + // TODO(joyeecheung): use internal/options instead of + // process._eval/process._forceRepl + if (process._eval != null && !process._forceRepl) { + const { + addBuiltinLibsToObject + } = NativeModule.require('internal/modules/cjs/helpers'); + addBuiltinLibsToObject(global); + evalScript('[eval]', wrapForBreakOnFirstLine(process._eval)); + return; } - 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; - } + // 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]); - // For user code, we preload modules if `-r` is passed - // TODO(joyeecheung): use internal/options instead of - // process._preload_modules - if (process._preload_modules) { - const { - _preloadModules - } = NativeModule.require('internal/modules/cjs/loader'); - _preloadModules(process._preload_modules); - } - } + const CJSModule = NativeModule.require('internal/modules/cjs/loader'); - 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 user passed `-c` or `--check` arguments to Node, check its syntax + // instead of actually running the file. // TODO(joyeecheung): use internal/options instead of - // process._eval/process._forceRepl - if (process._eval != null && !process._forceRepl) { - const { - addBuiltinLibsToObject - } = NativeModule.require('internal/modules/cjs/helpers'); - addBuiltinLibsToObject(global); - evalScript('[eval]', wrapForBreakOnFirstLine(process._eval)); - return; + // process._syntax_check_only + if (process._syntax_check_only != null) { + 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); } - // 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. - // TODO(joyeecheung): use internal/options instead of - // process._syntax_check_only - if (process._syntax_check_only != null) { - 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; - } + // 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; + // 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(); + }); } - repl.on('exit', () => { - if (repl._flushing) { - repl.pause(); - return repl.once('flushHistory', () => { - process.exit(); - }); - } - process.exit(); - }); + process.exit(); }); + }); - // User passed '-e' or '--eval' along with `-i` or `--interactive` - if (process._eval != null) { - evalScript('[eval]', wrapForBreakOnFirstLine(process._eval)); - } - return; + // User passed '-e' or '--eval' along with `-i` or `--interactive` + if (process._eval != null) { + evalScript('[eval]', wrapForBreakOnFirstLine(process._eval)); } - - // Stdin is not a TTY, we will read it and execute it. - readAndExecuteStdin(); + return; } - function readAndExecuteStdin() { - process.stdin.setEncoding('utf8'); + // Stdin is not a TTY, we will read it and execute it. + readAndExecuteStdin(); +} - let code = ''; - process.stdin.on('data', (d) => { - code += d; - }); +function readAndExecuteStdin() { + process.stdin.setEncoding('utf8'); - process.stdin.on('end', () => { - if (process._syntax_check_only != null) { - checkScriptSyntax(code, '[stdin]'); - } else { - process._eval = code; - evalScript('[stdin]', wrapForBreakOnFirstLine(process._eval)); - } - }); - } + let code = ''; + process.stdin.on('data', (d) => { + code += d; + }); - function setupTraceCategoryState() { - const { traceCategoryState } = internalBinding('trace_events'); - const kCategoryAsyncHooks = 0; - let traceEventsAsyncHook; - - function toggleTraceCategoryState() { - // Dynamically enable/disable the traceEventsAsyncHook - const asyncHooksEnabled = !!traceCategoryState[kCategoryAsyncHooks]; - - if (asyncHooksEnabled) { - // Lazy load internal/trace_events_async_hooks only if the async_hooks - // trace event category is enabled. - if (!traceEventsAsyncHook) { - traceEventsAsyncHook = - NativeModule.require('internal/trace_events_async_hooks'); - } - traceEventsAsyncHook.enable(); - } else if (traceEventsAsyncHook) { - traceEventsAsyncHook.disable(); + process.stdin.on('end', () => { + if (process._syntax_check_only != null) { + checkScriptSyntax(code, '[stdin]'); + } else { + process._eval = code; + evalScript('[stdin]', wrapForBreakOnFirstLine(process._eval)); + } + }); +} + +function setupTraceCategoryState() { + const { traceCategoryState } = internalBinding('trace_events'); + const kCategoryAsyncHooks = 0; + let traceEventsAsyncHook; + + function toggleTraceCategoryState() { + // Dynamically enable/disable the traceEventsAsyncHook + const asyncHooksEnabled = !!traceCategoryState[kCategoryAsyncHooks]; + + if (asyncHooksEnabled) { + // Lazy load internal/trace_events_async_hooks only if the async_hooks + // trace event category is enabled. + if (!traceEventsAsyncHook) { + traceEventsAsyncHook = + NativeModule.require('internal/trace_events_async_hooks'); } + traceEventsAsyncHook.enable(); + } else if (traceEventsAsyncHook) { + traceEventsAsyncHook.disable(); } - - toggleTraceCategoryState(); - _setupTraceCategoryState(toggleTraceCategoryState); } - function setupProcessObject() { - const EventEmitter = NativeModule.require('events'); - const origProcProto = Object.getPrototypeOf(process); - Object.setPrototypeOf(origProcProto, EventEmitter.prototype); - EventEmitter.call(process); + toggleTraceCategoryState(); + _setupTraceCategoryState(toggleTraceCategoryState); +} + +function setupProcessObject() { + const EventEmitter = NativeModule.require('events'); + const origProcProto = Object.getPrototypeOf(process); + Object.setPrototypeOf(origProcProto, EventEmitter.prototype); + EventEmitter.call(process); +} + +function setupGlobalVariables() { + Object.defineProperty(global, Symbol.toStringTag, { + value: 'global', + writable: false, + enumerable: false, + configurable: true + }); + global.process = process; + const util = NativeModule.require('util'); + + function makeGetter(name) { + return util.deprecate(function() { + return this; + }, `'${name}' is deprecated, use 'global'`, 'DEP0016'); } - function setupGlobalVariables() { - Object.defineProperty(global, Symbol.toStringTag, { - value: 'global', - writable: false, - enumerable: false, - configurable: true - }); - global.process = process; - const util = NativeModule.require('util'); - - function makeGetter(name) { - return util.deprecate(function() { - return this; - }, `'${name}' is deprecated, use 'global'`, 'DEP0016'); - } - - function makeSetter(name) { - return util.deprecate(function(value) { - Object.defineProperty(this, name, { - configurable: true, - writable: true, - enumerable: true, - value: value - }); - }, `'${name}' is deprecated, use 'global'`, 'DEP0016'); - } - - Object.defineProperties(global, { - GLOBAL: { - configurable: true, - get: makeGetter('GLOBAL'), - set: makeSetter('GLOBAL') - }, - root: { + function makeSetter(name) { + return util.deprecate(function(value) { + Object.defineProperty(this, name, { configurable: true, - get: makeGetter('root'), - set: makeSetter('root') - } - }); - - // This, as side effect, removes `setupBufferJS` from the buffer binding, - // and exposes it on `internal/buffer`. - NativeModule.require('internal/buffer'); - - global.Buffer = NativeModule.require('buffer').Buffer; - process.domain = null; - process._exiting = false; - } - - function setupGlobalTimeouts() { - const timers = NativeModule.require('timers'); - global.clearImmediate = timers.clearImmediate; - global.clearInterval = timers.clearInterval; - global.clearTimeout = timers.clearTimeout; - global.setImmediate = timers.setImmediate; - global.setInterval = timers.setInterval; - global.setTimeout = timers.setTimeout; + writable: true, + enumerable: true, + value: value + }); + }, `'${name}' is deprecated, use 'global'`, 'DEP0016'); } - function setupGlobalConsole() { - const consoleFromVM = global.console; - const consoleFromNode = - NativeModule.require('internal/console/global'); - // Override global console from the one provided by the VM - // to the one implemented by Node.js - Object.defineProperty(global, 'console', { + Object.defineProperties(global, { + GLOBAL: { configurable: true, - enumerable: false, - value: consoleFromNode, - writable: true - }); - // TODO(joyeecheung): can we skip this if inspector is not active? - if (process.config.variables.v8_enable_inspector) { - const inspector = - NativeModule.require('internal/console/inspector'); - inspector.addInspectorApis(consoleFromNode, consoleFromVM); - // This will be exposed by `require('inspector').console` later. - inspector.consoleFromVM = consoleFromVM; + get: makeGetter('GLOBAL'), + set: makeSetter('GLOBAL') + }, + root: { + configurable: true, + get: makeGetter('root'), + set: makeSetter('root') } + }); + + // This, as side effect, removes `setupBufferJS` from the buffer binding, + // and exposes it on `internal/buffer`. + NativeModule.require('internal/buffer'); + + global.Buffer = NativeModule.require('buffer').Buffer; + process.domain = null; + process._exiting = false; +} + +function setupGlobalTimeouts() { + const timers = NativeModule.require('timers'); + global.clearImmediate = timers.clearImmediate; + global.clearInterval = timers.clearInterval; + global.clearTimeout = timers.clearTimeout; + global.setImmediate = timers.setImmediate; + global.setInterval = timers.setInterval; + global.setTimeout = timers.setTimeout; +} + +function setupGlobalConsole() { + const consoleFromVM = global.console; + const consoleFromNode = + NativeModule.require('internal/console/global'); + // Override global console from the one provided by the VM + // to the one implemented by Node.js + Object.defineProperty(global, 'console', { + configurable: true, + enumerable: false, + value: consoleFromNode, + writable: true + }); + // TODO(joyeecheung): can we skip this if inspector is not active? + if (process.config.variables.v8_enable_inspector) { + const inspector = + NativeModule.require('internal/console/inspector'); + inspector.addInspectorApis(consoleFromNode, consoleFromVM); + // This will be exposed by `require('inspector').console` later. + inspector.consoleFromVM = consoleFromVM; } - - function setupGlobalURL() { - const { URL, URLSearchParams } = NativeModule.require('internal/url'); - Object.defineProperties(global, { - URL: { - value: URL, - writable: true, - configurable: true, - enumerable: false - }, - URLSearchParams: { - value: URLSearchParams, - writable: true, - configurable: true, - enumerable: false - } - }); - } - - function setupGlobalEncoding() { - const { TextEncoder, TextDecoder } = NativeModule.require('util'); - Object.defineProperties(global, { - TextEncoder: { - value: TextEncoder, +} + +function setupGlobalURL() { + const { URL, URLSearchParams } = NativeModule.require('internal/url'); + Object.defineProperties(global, { + URL: { + value: URL, + writable: true, + configurable: true, + enumerable: false + }, + URLSearchParams: { + value: URLSearchParams, + writable: true, + configurable: true, + enumerable: false + } + }); +} + +function setupGlobalEncoding() { + const { TextEncoder, TextDecoder } = NativeModule.require('util'); + Object.defineProperties(global, { + TextEncoder: { + value: TextEncoder, + writable: true, + configurable: true, + enumerable: false + }, + TextDecoder: { + value: TextDecoder, + writable: true, + configurable: true, + enumerable: false + } + }); +} + +function setupQueueMicrotask() { + Object.defineProperty(global, 'queueMicrotask', { + get: () => { + process.emitWarning('queueMicrotask() is experimental.', + 'ExperimentalWarning'); + const { setupQueueMicrotask } = + NativeModule.require('internal/queue_microtask'); + const queueMicrotask = setupQueueMicrotask(triggerFatalException); + Object.defineProperty(global, 'queueMicrotask', { + value: queueMicrotask, writable: true, + enumerable: false, configurable: true, - enumerable: false - }, - TextDecoder: { - value: TextDecoder, + }); + return queueMicrotask; + }, + set: (v) => { + Object.defineProperty(global, 'queueMicrotask', { + value: v, writable: true, + enumerable: false, configurable: true, - enumerable: false - } - }); - } - - function setupQueueMicrotask() { - Object.defineProperty(global, 'queueMicrotask', { - get: () => { - process.emitWarning('queueMicrotask() is experimental.', - 'ExperimentalWarning'); - const { setupQueueMicrotask } = - NativeModule.require('internal/queue_microtask'); - const queueMicrotask = setupQueueMicrotask(triggerFatalException); - Object.defineProperty(global, 'queueMicrotask', { - value: queueMicrotask, - writable: true, - enumerable: false, - configurable: true, - }); - return queueMicrotask; - }, - set: (v) => { - Object.defineProperty(global, 'queueMicrotask', { - value: v, - writable: true, - enumerable: false, - configurable: true, - }); - }, - enumerable: false, - configurable: true, - }); - } - - function setupDOMException() { - // Registers the constructor with C++. - const DOMException = NativeModule.require('internal/domexception'); - const { registerDOMException } = internalBinding('messaging'); - registerDOMException(DOMException); - } - - function noop() {} - - function setupProcessFatal() { - const { - executionAsyncId, - clearDefaultTriggerAsyncId, - clearAsyncIdStack, - hasAsyncIdStack, - afterHooksExist, - emitAfter - } = NativeModule.require('internal/async_hooks'); - - process._fatalException = (er) => { - // It's possible that defaultTriggerAsyncId was set for a constructor - // call that threw and was never cleared. So clear it now. - clearDefaultTriggerAsyncId(); - - if (exceptionHandlerState.captureFn !== null) { - exceptionHandlerState.captureFn(er); - } else if (!process.emit('uncaughtException', er)) { - // 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 = 1; - process.emit('exit', 1); - } - } catch { - // Nothing to be done about it at this point. - } - try { - const { kExpandStackSymbol } = NativeModule.require('internal/util'); - if (typeof er[kExpandStackSymbol] === 'function') - er[kExpandStackSymbol](); - } catch { - // Nothing to be done about it at this point. + }); + }, + enumerable: false, + configurable: true, + }); +} + +function setupDOMException() { + // Registers the constructor with C++. + const DOMException = NativeModule.require('internal/domexception'); + const { registerDOMException } = internalBinding('messaging'); + registerDOMException(DOMException); +} + +function noop() {} + +function setupProcessFatal() { + const { + executionAsyncId, + clearDefaultTriggerAsyncId, + clearAsyncIdStack, + hasAsyncIdStack, + afterHooksExist, + emitAfter + } = NativeModule.require('internal/async_hooks'); + + process._fatalException = (er) => { + // It's possible that defaultTriggerAsyncId was set for a constructor + // call that threw and was never cleared. So clear it now. + clearDefaultTriggerAsyncId(); + + if (exceptionHandlerState.captureFn !== null) { + exceptionHandlerState.captureFn(er); + } else if (!process.emit('uncaughtException', er)) { + // 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 = 1; + process.emit('exit', 1); } - return false; + } catch { + // Nothing to be done about it at this point. } - - // If we handled an error, then make sure any ticks get processed - // by ensuring that the next Immediate cycle isn't empty. - NativeModule.require('timers').setImmediate(noop); - - // Emit the after() hooks now that the exception has been handled. - if (afterHooksExist()) { - do { - emitAfter(executionAsyncId()); - } while (hasAsyncIdStack()); - // Or completely empty the id stack. - } else { - clearAsyncIdStack(); + try { + const { kExpandStackSymbol } = NativeModule.require('internal/util'); + if (typeof er[kExpandStackSymbol] === 'function') + er[kExpandStackSymbol](); + } catch { + // Nothing to be done about it at this point. } - - return true; - }; - } - - function setupProcessICUVersions() { - const icu = process.binding('config').hasIntl ? - internalBinding('icu') : undefined; - if (!icu) return; // no Intl/ICU: nothing to add here. - // With no argument, getVersion() returns a comma separated list - // of possible types. - const versionTypes = icu.getVersion().split(','); - - for (var n = 0; n < versionTypes.length; n++) { - const name = versionTypes[n]; - const version = icu.getVersion(name); - Object.defineProperty(process.versions, name, { - writable: false, - enumerable: true, - value: version - }); + return false; } - } - function wrapForBreakOnFirstLine(source) { - if (!process._breakFirstLine) - return source; - const fn = `function() {\n\n${source};\n\n}`; - return `process.binding('inspector').callAndPauseOnStart(${fn}, {})`; - } - - function evalScript(name, body) { - const CJSModule = NativeModule.require('internal/modules/cjs/loader'); - const path = NativeModule.require('path'); - const { tryGetCwd } = NativeModule.require('internal/util'); - const cwd = tryGetCwd(path); - - const module = new CJSModule(name); - module.filename = path.join(cwd, name); - module.paths = CJSModule._nodeModulePaths(cwd); - const script = `global.__filename = ${JSON.stringify(name)};\n` + - 'global.exports = exports;\n' + - 'global.module = module;\n' + - 'global.__dirname = __dirname;\n' + - 'global.require = require;\n' + - 'return require("vm").runInThisContext(' + - `${JSON.stringify(body)}, { filename: ` + - `${JSON.stringify(name)}, displayErrors: true });\n`; - const result = module._compile(script, `${name}-wrapper`); - if (process._print_eval) console.log(result); - // Handle any nextTicks added in the first tick of the program. - process._tickCallback(); - } + // If we handled an error, then make sure any ticks get processed + // by ensuring that the next Immediate cycle isn't empty. + NativeModule.require('timers').setImmediate(noop); - 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'); + // Emit the after() hooks now that the exception has been handled. + if (afterHooksExist()) { + do { + emitAfter(executionAsyncId()); + } while (hasAsyncIdStack()); + // Or completely empty the id stack. + } else { + clearAsyncIdStack(); + } - // 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 true; + }; +} + +function setupProcessICUVersions() { + const icu = process.binding('config').hasIntl ? + internalBinding('icu') : undefined; + if (!icu) return; // no Intl/ICU: nothing to add here. + // With no argument, getVersion() returns a comma separated list + // of possible types. + const versionTypes = icu.getVersion().split(','); + + for (var n = 0; n < versionTypes.length; n++) { + const name = versionTypes[n]; + const version = icu.getVersion(name); + Object.defineProperty(process.versions, name, { + writable: false, + enumerable: true, + value: version + }); } - - startup(); -}); +} + +function wrapForBreakOnFirstLine(source) { + if (!process._breakFirstLine) + return source; + const fn = `function() {\n\n${source};\n\n}`; + return `process.binding('inspector').callAndPauseOnStart(${fn}, {})`; +} + +function evalScript(name, body) { + const CJSModule = NativeModule.require('internal/modules/cjs/loader'); + const path = NativeModule.require('path'); + const { tryGetCwd } = NativeModule.require('internal/util'); + const cwd = tryGetCwd(path); + + const module = new CJSModule(name); + module.filename = path.join(cwd, name); + module.paths = CJSModule._nodeModulePaths(cwd); + const script = `global.__filename = ${JSON.stringify(name)};\n` + + 'global.exports = exports;\n' + + 'global.module = module;\n' + + 'global.__dirname = __dirname;\n' + + 'global.require = require;\n' + + 'return require("vm").runInThisContext(' + + `${JSON.stringify(body)}, { filename: ` + + `${JSON.stringify(name)}, displayErrors: true });\n`; + const result = module._compile(script, `${name}-wrapper`); + if (process._print_eval) console.log(result); + // Handle any nextTicks added in the first tick of the program. + process._tickCallback(); +} + +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 }); +} + +startup(); diff --git a/lib/internal/per_context.js b/lib/internal/per_context.js index 87fc8d247e..725ba403df 100644 --- a/lib/internal/per_context.js +++ b/lib/internal/per_context.js @@ -1,9 +1,9 @@ -// arguments: global +// This file is compiled as if it's wrapped in a function with arguments +// passed by node::NewContext() +/* global global */ 'use strict'; -// node::NewContext calls this script - // https://github.com/nodejs/node/issues/14909 if (global.Intl) delete global.Intl.v8BreakIterator; diff --git a/src/node.cc b/src/node.cc index 975373baa6..24fe3a71e9 100644 --- a/src/node.cc +++ b/src/node.cc @@ -116,7 +116,6 @@ typedef int mode_t; namespace node { -using errors::TryCatchScope; using native_module::NativeModuleLoader; using options_parser::kAllowedInEnvironment; using options_parser::kDisallowedInEnvironment; @@ -144,7 +143,6 @@ using v8::NamedPropertyHandlerConfiguration; using v8::NewStringType; using v8::None; using v8::Nothing; -using v8::Null; using v8::Object; using v8::ObjectTemplate; using v8::PropertyAttribute; @@ -741,41 +739,6 @@ Local<Value> MakeCallback(Isolate* isolate, .FromMaybe(Local<Value>())); } -// Executes a str within the current v8 context. -static MaybeLocal<Value> ExecuteString(Environment* env, - Local<String> source, - Local<String> filename) { - EscapableHandleScope scope(env->isolate()); - TryCatchScope try_catch(env); - - // try_catch must be nonverbose to disable FatalException() handler, - // we will handle exceptions ourself. - try_catch.SetVerbose(false); - - ScriptOrigin origin(filename); - - MaybeLocal<Script> script = - Script::Compile(env->context(), source, &origin); - if (script.IsEmpty()) { - ReportException(env, try_catch); - env->Exit(3); - return MaybeLocal<Value>(); - } - - MaybeLocal<Value> result = script.ToLocalChecked()->Run(env->context()); - if (result.IsEmpty()) { - if (try_catch.HasTerminated()) { - env->isolate()->CancelTerminateExecution(); - return MaybeLocal<Value>(); - } - ReportException(env, try_catch); - env->Exit(4); - return MaybeLocal<Value>(); - } - - return scope.Escape(result.ToLocalChecked()); -} - static void WaitForInspectorDisconnect(Environment* env) { #if HAVE_INSPECTOR if (env->inspector_agent()->IsActive()) { @@ -1334,39 +1297,13 @@ void SignalExit(int signo) { raise(signo); } - -static MaybeLocal<Function> GetBootstrapper( +static MaybeLocal<Value> ExecuteBootstrapper( Environment* env, - Local<String> source, - Local<String> script_name) { - EscapableHandleScope scope(env->isolate()); - - TryCatchScope try_catch(env); - - // Disable verbose mode to stop FatalException() handler from trying - // to handle the exception. Errors this early in the start-up phase - // are not safe to ignore. - try_catch.SetVerbose(false); - - // Execute the bootstrapper javascript file - MaybeLocal<Value> bootstrapper_v = ExecuteString(env, source, script_name); - if (bootstrapper_v.IsEmpty()) // This happens when execution was interrupted. - return MaybeLocal<Function>(); - - if (try_catch.HasCaught()) { - ReportException(env, try_catch); - exit(10); - } - - CHECK(bootstrapper_v.ToLocalChecked()->IsFunction()); - return scope.Escape(bootstrapper_v.ToLocalChecked().As<Function>()); -} - -static bool ExecuteBootstrapper(Environment* env, Local<Function> bootstrapper, - int argc, Local<Value> argv[], - Local<Value>* out) { - bool ret = bootstrapper->Call( - env->context(), Null(env->isolate()), argc, argv).ToLocal(out); + const char* id, + std::vector<Local<String>>* parameters, + std::vector<Local<Value>>* arguments) { + MaybeLocal<Value> ret = per_process_loader.CompileAndCall( + env->context(), id, parameters, arguments, env); // 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 @@ -1375,123 +1312,86 @@ static bool ExecuteBootstrapper(Environment* env, Local<Function> bootstrapper, // 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) { + if (ret.IsEmpty()) { env->async_hooks()->clear_async_id_stack(); } return ret; } - void LoadEnvironment(Environment* env) { HandleScope handle_scope(env->isolate()); - - TryCatchScope try_catch(env); - // Disable verbose mode to stop FatalException() handler from trying - // to handle the exception. Errors this early in the start-up phase - // are not safe to ignore. - try_catch.SetVerbose(false); - - // The bootstrapper scripts are lib/internal/bootstrap/loaders.js and - // lib/internal/bootstrap/node.js, each included as a static C string - // generated in node_javascript.cc by node_js2c. - - // TODO(joyeecheung): use NativeModuleLoader::Compile - // We duplicate the string literals here since once we refactor the bootstrap - // compilation out to NativeModuleLoader none of this is going to matter Isolate* isolate = env->isolate(); - Local<String> loaders_name = - FIXED_ONE_BYTE_STRING(isolate, "internal/bootstrap/loaders.js"); - Local<String> loaders_source = - per_process_loader.GetSource(isolate, "internal/bootstrap/loaders"); - MaybeLocal<Function> loaders_bootstrapper = - GetBootstrapper(env, loaders_source, loaders_name); - Local<String> node_name = - FIXED_ONE_BYTE_STRING(isolate, "internal/bootstrap/node.js"); - Local<String> node_source = - per_process_loader.GetSource(isolate, "internal/bootstrap/node"); - MaybeLocal<Function> node_bootstrapper = - GetBootstrapper(env, node_source, node_name); - - if (loaders_bootstrapper.IsEmpty() || node_bootstrapper.IsEmpty()) { - // Execution was interrupted. - return; - } + Local<Context> context = env->context(); // Add a reference to the global object - Local<Object> global = env->context()->Global(); + Local<Object> global = context->Global(); #if defined HAVE_DTRACE || defined HAVE_ETW InitDTrace(env, global); #endif - // Enable handling of uncaught exceptions - // (FatalException(), break on uncaught exception in debugger) - // - // This is not strictly necessary since it's almost impossible - // to attach the debugger fast enough to break on exception - // thrown during process startup. - try_catch.SetVerbose(true); - - env->SetMethod(env->process_object(), "_rawDebug", RawDebug); + Local<Object> process = env->process_object(); + // Setting global properties for the bootstrappers to use: + // - global + // - process._rawDebug // Expose the global object as a property on itself // (Allows you to set stuff on `global` from anywhere in JavaScript.) - global->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "global"), - global).FromJust(); + global->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global) + .FromJust(); + env->SetMethod(process, "_rawDebug", RawDebug); // Create binding loaders - Local<Function> get_binding_fn = env->NewFunctionTemplate(binding::GetBinding) - ->GetFunction(env->context()) - .ToLocalChecked(); - - Local<Function> get_linked_binding_fn = + std::vector<Local<String>> loaders_params = { + env->process_string(), + FIXED_ONE_BYTE_STRING(isolate, "getBinding"), + FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"), + FIXED_ONE_BYTE_STRING(isolate, "getInternalBinding"), + FIXED_ONE_BYTE_STRING(isolate, "debugBreak")}; + std::vector<Local<Value>> loaders_args = { + process, + env->NewFunctionTemplate(binding::GetBinding) + ->GetFunction(context) + .ToLocalChecked(), env->NewFunctionTemplate(binding::GetLinkedBinding) - ->GetFunction(env->context()) - .ToLocalChecked(); - - Local<Function> get_internal_binding_fn = + ->GetFunction(context) + .ToLocalChecked(), env->NewFunctionTemplate(binding::GetInternalBinding) - ->GetFunction(env->context()) - .ToLocalChecked(); - - Local<Value> loaders_bootstrapper_args[] = { - env->process_object(), - get_binding_fn, - get_linked_binding_fn, - get_internal_binding_fn, - Boolean::New(env->isolate(), - env->options()->debug_options->break_node_first_line) - }; + ->GetFunction(context) + .ToLocalChecked(), + Boolean::New(isolate, + env->options()->debug_options->break_node_first_line)}; + MaybeLocal<Value> loader_exports; // Bootstrap internal loaders - Local<Value> bootstrapped_loaders; - if (!ExecuteBootstrapper(env, loaders_bootstrapper.ToLocalChecked(), - arraysize(loaders_bootstrapper_args), - loaders_bootstrapper_args, - &bootstrapped_loaders)) { + loader_exports = ExecuteBootstrapper( + env, "internal/bootstrap/loaders", &loaders_params, &loaders_args); + if (loader_exports.IsEmpty()) { return; } - Local<Function> trigger_fatal_exception = - env->NewFunctionTemplate(FatalException)->GetFunction(env->context()) - .ToLocalChecked(); - // Bootstrap Node.js Local<Object> bootstrapper = Object::New(env->isolate()); SetupBootstrapObject(env, bootstrapper); - Local<Value> bootstrapped_node; - Local<Value> node_bootstrapper_args[] = { - env->process_object(), - bootstrapper, - bootstrapped_loaders, - trigger_fatal_exception, - }; - if (!ExecuteBootstrapper(env, node_bootstrapper.ToLocalChecked(), - arraysize(node_bootstrapper_args), - node_bootstrapper_args, - &bootstrapped_node)) { + + // process, bootstrappers, loaderExports, triggerFatalException + std::vector<Local<String>> node_params = { + env->process_string(), + FIXED_ONE_BYTE_STRING(isolate, "bootstrappers"), + FIXED_ONE_BYTE_STRING(isolate, "loaderExports"), + FIXED_ONE_BYTE_STRING(isolate, "triggerFatalException")}; + std::vector<Local<Value>> node_args = { + process, + bootstrapper, + loader_exports.ToLocalChecked(), + env->NewFunctionTemplate(FatalException) + ->GetFunction(context) + .ToLocalChecked()}; + + if (ExecuteBootstrapper( + env, "internal/bootstrap/node", &node_params, &node_args) + .IsEmpty()) { return; } } diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out index c26c63d2b0..dfa8ec0f7d 100644 --- a/test/message/eval_messages.out +++ b/test/message/eval_messages.out @@ -12,7 +12,7 @@ SyntaxError: Strict mode code may not include a with statement at executeUserCode (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*) - at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) + at internal/bootstrap/node.js:*:* 42 42 [eval]:1 @@ -29,7 +29,7 @@ Error: hello at executeUserCode (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*) - at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) + at internal/bootstrap/node.js:*:* [eval]:1 throw new Error("hello") @@ -45,7 +45,7 @@ Error: hello at executeUserCode (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*) - at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) + at internal/bootstrap/node.js:*:* 100 [eval]:1 var x = 100; y = x; @@ -61,7 +61,7 @@ ReferenceError: y is not defined at executeUserCode (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*) - at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) + at internal/bootstrap/node.js:*:* [eval]:1 var ______________________________________________; throw 10 diff --git a/test/message/events_unhandled_error_nexttick.out b/test/message/events_unhandled_error_nexttick.out index d043839fe2..1c0ed6df93 100644 --- a/test/message/events_unhandled_error_nexttick.out +++ b/test/message/events_unhandled_error_nexttick.out @@ -21,4 +21,4 @@ Emitted 'error' event at: at executeUserCode (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*) - at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) + at internal/bootstrap/node.js:*:* diff --git a/test/message/nexttick_throw.out b/test/message/nexttick_throw.out index 5f3c85f874..2bf69e8146 100644 --- a/test/message/nexttick_throw.out +++ b/test/message/nexttick_throw.out @@ -10,4 +10,4 @@ ReferenceError: undefined_reference_error_maker is not defined at executeUserCode (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*) - at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) + at internal/bootstrap/node.js:*:* |