diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js new file mode 100644 index 00000000000000..0a688a1b0f915a --- /dev/null +++ b/lib/internal/bootstrap_node.js @@ -0,0 +1,433 @@ +// Hello, and welcome to hacking node.js! +// +// This file is invoked by node::LoadEnvironment in src/node.cc, and is +// responsible for bootstrapping the node.js core. As special caution is given +// to the performance of the startup process, many dependencies are invoked +// lazily. + +'use strict'; + +(function(process) { + this.global = this; + + function startup() { + var EventEmitter = NativeModule.require('events'); + process._eventsCount = 0; + + Object.setPrototypeOf(process, Object.create(EventEmitter.prototype, { + constructor: { + value: process.constructor + } + })); + + EventEmitter.call(process); + + let eeWarned = false; + Object.defineProperty(process, 'EventEmitter', { + get() { + const internalUtil = NativeModule.require('internal/util'); + eeWarned = internalUtil.printDeprecationMessage( + "process.EventEmitter is deprecated. Use require('events') instead.", + eeWarned + ); + return EventEmitter; + } + }); + + setupProcessObject(); + + // do this good and early, since it handles errors. + setupProcessFatal(); + + setupGlobalVariables(); + setupGlobalTimeouts(); + setupGlobalConsole(); + + const _process = NativeModule.require('internal/process'); + + _process.setup_hrtime(); + _process.setupConfig(NativeModule._source); + NativeModule.require('internal/process/next_tick').setup(); + NativeModule.require('internal/process/stdio').setup(); + _process.setupKillAndExit(); + _process.setupSignalHandlers(); + + // Do not initialize channel in debugger agent, it deletes env variable + // and the main thread won't see it. + if (process.argv[1] !== '--debug-agent') + _process.setupChannel(); + + _process.setupRawDebug(); + + process.argv[0] = process.execPath; + + // 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. + + if (NativeModule.exists('_third_party_main')) { + // 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. + process.nextTick(function() { + NativeModule.require('_third_party_main'); + }); + + } else if (process.argv[1] == 'debug') { + // Start the debugger agent + NativeModule.require('_debugger').start(); + + } else if (process.argv[1] == '--debug-agent') { + // Start the debugger agent + NativeModule.require('_debug_agent').start(); + + } else if (process.profProcess) { + NativeModule.require('internal/v8_prof_processor'); + + } else { + // There is user code to be run + + // 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) { + var cluster = NativeModule.require('cluster'); + cluster._setupWorker(); + + // Make sure it's not accidentally inherited by child processes. + delete process.env.NODE_UNIQUE_ID; + } + + if (process._eval != null && !process._forceRepl) { + // User passed '-e' or '--eval' arguments to Node without '-i' or + // '--interactive' + preloadModules(); + evalScript('[eval]'); + } else if (process.argv[1]) { + // make process.argv[1] into a full path + var path = NativeModule.require('path'); + process.argv[1] = path.resolve(process.argv[1]); + + var Module = NativeModule.require('module'); + + // check if user passed `-c` or `--check` arguments to Node. + if (process._syntax_check_only != null) { + var vm = NativeModule.require('vm'); + var fs = NativeModule.require('fs'); + var internalModule = NativeModule.require('internal/module'); + // read the source + var filename = Module._resolveFilename(process.argv[1]); + var source = fs.readFileSync(filename, 'utf-8'); + // remove shebang and BOM + source = internalModule.stripBOM(source.replace(/^\#\!.*/, '')); + // wrap it + source = Module.wrap(source); + // compile the script, this will throw if it fails + new vm.Script(source, {filename: filename, displayErrors: true}); + process.exit(0); + } + + preloadModules(); + + if (global.v8debug && + process.execArgv.some(function(arg) { + return arg.match(/^--debug-brk(=[0-9]*)?$/); + })) { + + // XXX Fix this terrible hack! + // + // Give the client program a few ticks to connect. + // Otherwise, there's a race condition where `node debug foo.js` + // will not be able to connect in time to catch the first + // breakpoint message on line 1. + // + // A better fix would be to somehow get a message from the + // global.v8debug object about a connection, and runMain when + // that occurs. --isaacs + + var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50; + setTimeout(Module.runMain, debugTimeout); + + } else { + // Main entry point into most programs: + Module.runMain(); + } + + } else { + preloadModules(); + // If -i or --interactive were passed, or stdin is a TTY. + if (process._forceRepl || NativeModule.require('tty').isatty(0)) { + // REPL + var cliRepl = NativeModule.require('internal/repl'); + cliRepl.createInternalRepl(process.env, function(err, repl) { + if (err) { + throw err; + } + repl.on('exit', function() { + if (repl._flushing) { + repl.pause(); + return repl.once('flushHistory', function() { + process.exit(); + }); + } + process.exit(); + }); + }); + + if (process._eval != null) { + // User passed '-e' or '--eval' + evalScript('[eval]'); + } + } else { + // Read all of stdin - execute it. + process.stdin.setEncoding('utf8'); + + var code = ''; + process.stdin.on('data', function(d) { + code += d; + }); + + process.stdin.on('end', function() { + process._eval = code; + evalScript('[stdin]'); + }); + } + } + } + } + + function setupProcessObject() { + process._setupProcessObject(pushValueToArray); + + function pushValueToArray() { + for (var i = 0; i < arguments.length; i++) + this.push(arguments[i]); + } + } + + function setupGlobalVariables() { + global.process = process; + global.global = global; + const util = NativeModule.require('util'); + + // Deprecate GLOBAL and root + ['GLOBAL', 'root'].forEach(function(name) { + // getter + const get = util.deprecate(function() { + return this; + }, `'${name}' is deprecated, use 'global'`); + // setter + const set = util.deprecate(function(value) { + Object.defineProperty(this, name, { + configurable: true, + writable: true, + enumerable: true, + value: value + }); + }, `'${name}' is deprecated, use 'global'`); + // define property + Object.defineProperty(global, name, { get, set, configurable: true }); + }); + + 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() { + global.__defineGetter__('console', function() { + return NativeModule.require('console'); + }); + } + + function setupProcessFatal() { + + process._fatalException = function(er) { + var caught; + + if (process.domain && process.domain._errorHandler) + caught = process.domain._errorHandler(er) || caught; + + if (!caught) + caught = 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 + if (!caught) { + try { + if (!process._exiting) { + process._exiting = true; + process.emit('exit', 1); + } + } catch (er) { + // nothing to be done about it at this point. + } + + // if we handled an error, then make sure any ticks get processed + } else { + NativeModule.require('timers').setImmediate(process._tickCallback); + } + + return caught; + }; + } + + function evalScript(name) { + var Module = NativeModule.require('module'); + var path = NativeModule.require('path'); + + try { + var cwd = process.cwd(); + } catch (e) { + // 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? + cwd = path.dirname(process.execPath); + } + + var module = new Module(name); + module.filename = path.join(cwd, name); + module.paths = Module._nodeModulePaths(cwd); + var script = process._eval; + var body = script; + 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`; + // Defer evaluation for a tick. This is a workaround for deferred + // events not firing when evaluating scripts from the command line, + // see https://github.com/nodejs/node/issues/1600. + process.nextTick(function() { + var result = module._compile(script, `${name}-wrapper`); + if (process._print_eval) console.log(result); + }); + } + + // Load preload modules + function preloadModules() { + if (process._preload_modules) { + NativeModule.require('module')._preloadModules(process._preload_modules); + } + } + + // Below you find a minimal module system, which is used to load the node + // core modules found in lib/*.js. All core modules are compiled into the + // node binary, so they can be loaded faster. + + var ContextifyScript = process.binding('contextify').ContextifyScript; + function runInThisContext(code, options) { + var script = new ContextifyScript(code, options); + return script.runInThisContext(); + } + + function NativeModule(id) { + this.filename = `${id}.js`; + this.id = id; + this.exports = {}; + this.loaded = false; + } + + NativeModule._source = process.binding('natives'); + NativeModule._cache = {}; + + NativeModule.require = function(id) { + if (id == 'native_module') { + return NativeModule; + } + + var cached = NativeModule.getCached(id); + if (cached) { + return cached.exports; + } + + if (!NativeModule.exists(id)) { + throw new Error(`No such native module ${id}`); + } + + process.moduleLoadList.push(`NativeModule ${id}`); + + var nativeModule = new NativeModule(id); + + nativeModule.cache(); + nativeModule.compile(); + + return nativeModule.exports; + }; + + NativeModule.getCached = function(id) { + return NativeModule._cache[id]; + }; + + NativeModule.exists = function(id) { + return NativeModule._source.hasOwnProperty(id); + }; + + const EXPOSE_INTERNALS = process.execArgv.some(function(arg) { + return arg.match(/^--expose[-_]internals$/); + }); + + if (EXPOSE_INTERNALS) { + NativeModule.nonInternalExists = NativeModule.exists; + + NativeModule.isInternal = function(id) { + return false; + }; + } else { + NativeModule.nonInternalExists = function(id) { + return NativeModule.exists(id) && !NativeModule.isInternal(id); + }; + + NativeModule.isInternal = function(id) { + return id.startsWith('internal/'); + }; + } + + + 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, __filename, __dirname) { ', + '\n});' + ]; + + NativeModule.prototype.compile = function() { + var source = NativeModule.getSource(this.id); + source = NativeModule.wrap(source); + + var fn = runInThisContext(source, { + filename: this.filename, + lineOffset: 0, + displayErrors: true + }); + fn(this.exports, NativeModule.require, this, this.filename); + + this.loaded = true; + }; + + NativeModule.prototype.cache = function() { + NativeModule._cache[this.id] = this; + }; + + startup(); +}); diff --git a/lib/internal/process.js b/lib/internal/process.js new file mode 100644 index 00000000000000..17ca5bc326c08a --- /dev/null +++ b/lib/internal/process.js @@ -0,0 +1,186 @@ +'use strict'; + +var _lazyConstants = null; + +function lazyConstants() { + if (!_lazyConstants) { + _lazyConstants = process.binding('constants'); + } + return _lazyConstants; +} + +exports.setup_hrtime = setup_hrtime; +exports.setupConfig = setupConfig; +exports.setupKillAndExit = setupKillAndExit; +exports.setupSignalHandlers = setupSignalHandlers; +exports.setupChannel = setupChannel; +exports.setupRawDebug = setupRawDebug; + + +const assert = process.assert = function(x, msg) { + if (!x) throw new Error(msg || 'assertion error'); +}; + + +function setup_hrtime() { + const _hrtime = process.hrtime; + const hrValues = new Uint32Array(3); + + process.hrtime = function hrtime(ar) { + _hrtime(hrValues); + + if (typeof ar !== 'undefined') { + if (Array.isArray(ar)) { + const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - ar[0]; + const nsec = hrValues[2] - ar[1]; + return [nsec < 0 ? sec - 1 : sec, nsec < 0 ? nsec + 1e9 : nsec]; + } + + throw new TypeError('process.hrtime() only accepts an Array tuple'); + } + + return [ + hrValues[0] * 0x100000000 + hrValues[1], + hrValues[2] + ]; + }; +} + + +function setupConfig(_source) { + // NativeModule._source + // used for `process.config`, but not a real module + var config = _source.config; + delete _source.config; + + // strip the gyp comment line at the beginning + config = config.split('\n') + .slice(1) + .join('\n') + .replace(/"/g, '\\"') + .replace(/'/g, '"'); + + process.config = JSON.parse(config, function(key, value) { + if (value === 'true') return true; + if (value === 'false') return false; + return value; + }); +} + + +function setupKillAndExit() { + + process.exit = function(code) { + if (code || code === 0) + process.exitCode = code; + + if (!process._exiting) { + process._exiting = true; + process.emit('exit', process.exitCode || 0); + } + process.reallyExit(process.exitCode || 0); + }; + + process.kill = function(pid, sig) { + var err; + + if (pid != (pid | 0)) { + throw new TypeError('invalid pid'); + } + + // preserve null signal + if (0 === sig) { + err = process._kill(pid, 0); + } else { + sig = sig || 'SIGTERM'; + if (lazyConstants()[sig] && + sig.slice(0, 3) === 'SIG') { + err = process._kill(pid, lazyConstants()[sig]); + } else { + throw new Error(`Unknown signal: ${sig}`); + } + } + + if (err) { + var errnoException = require('util')._errnoException; + throw errnoException(err, 'kill'); + } + + return true; + }; +} + + +function setupSignalHandlers() { + // Load events module in order to access prototype elements on process like + // process.addListener. + var signalWraps = {}; + + function isSignal(event) { + return typeof event === 'string' && + event.slice(0, 3) === 'SIG' && + lazyConstants().hasOwnProperty(event); + } + + // Detect presence of a listener for the special signal types + process.on('newListener', function(type, listener) { + if (isSignal(type) && + !signalWraps.hasOwnProperty(type)) { + var Signal = process.binding('signal_wrap').Signal; + var wrap = new Signal(); + + wrap.unref(); + + wrap.onsignal = function() { process.emit(type); }; + + var signum = lazyConstants()[type]; + var err = wrap.start(signum); + if (err) { + wrap.close(); + var errnoException = require('util')._errnoException; + throw errnoException(err, 'uv_signal_start'); + } + + signalWraps[type] = wrap; + } + }); + + process.on('removeListener', function(type, listener) { + if (signalWraps.hasOwnProperty(type) && this.listenerCount(type) === 0) { + signalWraps[type].close(); + delete signalWraps[type]; + } + }); +} + + +function setupChannel() { + // If we were spawned with env NODE_CHANNEL_FD then load that up and + // start parsing data from that stream. + if (process.env.NODE_CHANNEL_FD) { + var fd = parseInt(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; + + var cp = require('child_process'); + + // Load tcp_wrap to avoid situation where we might immediately receive + // a message. + // FIXME is this really necessary? + process.binding('tcp_wrap'); + + cp._forkChild(fd); + assert(process.send); + } +} + + +function setupRawDebug() { + var format = require('util').format; + var rawDebug = process._rawDebug; + process._rawDebug = function() { + rawDebug(format.apply(null, arguments)); + }; +} diff --git a/lib/internal/process/next_tick.js b/lib/internal/process/next_tick.js new file mode 100644 index 00000000000000..529645aa8d65c4 --- /dev/null +++ b/lib/internal/process/next_tick.js @@ -0,0 +1,157 @@ +'use strict'; + +exports.setup = setupNextTick; + +function setupNextTick() { + const promises = require('internal/process/promises'); + const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks); + var nextTickQueue = []; + var microtasksScheduled = false; + + // Used to run V8's micro task queue. + var _runMicrotasks = {}; + + // *Must* match Environment::TickInfo::Fields in src/env.h. + var kIndex = 0; + var kLength = 1; + + process.nextTick = nextTick; + // Needs to be accessible from beyond this scope. + process._tickCallback = _tickCallback; + process._tickDomainCallback = _tickDomainCallback; + + // This tickInfo thing is used so that the C++ code in src/node.cc + // can have easy access to our nextTick state, and avoid unnecessary + // calls into JS land. + const tickInfo = process._setupNextTick(_tickCallback, _runMicrotasks); + + _runMicrotasks = _runMicrotasks.runMicrotasks; + + function tickDone() { + if (tickInfo[kLength] !== 0) { + if (tickInfo[kLength] <= tickInfo[kIndex]) { + nextTickQueue = []; + tickInfo[kLength] = 0; + } else { + nextTickQueue.splice(0, tickInfo[kIndex]); + tickInfo[kLength] = nextTickQueue.length; + } + } + tickInfo[kIndex] = 0; + } + + function scheduleMicrotasks() { + if (microtasksScheduled) + return; + + nextTickQueue.push({ + callback: runMicrotasksCallback, + domain: null + }); + + tickInfo[kLength]++; + microtasksScheduled = true; + } + + function runMicrotasksCallback() { + microtasksScheduled = false; + _runMicrotasks(); + + if (tickInfo[kIndex] < tickInfo[kLength] || + emitPendingUnhandledRejections()) + scheduleMicrotasks(); + } + + function _combinedTickCallback(args, callback) { + if (args === undefined) { + callback(); + } else { + 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; + default: + callback.apply(null, args); + } + } + } + + // Run callbacks that have no domain. + // Using domains will cause this to be overridden. + function _tickCallback() { + var callback, args, tock; + + do { + while (tickInfo[kIndex] < tickInfo[kLength]) { + tock = nextTickQueue[tickInfo[kIndex]++]; + callback = tock.callback; + args = tock.args; + // Using separate callback execution functions allows direct + // callback invocation with small numbers of arguments to avoid the + // performance hit associated with using `fn.apply()` + _combinedTickCallback(args, callback); + if (1e4 < tickInfo[kIndex]) + tickDone(); + } + tickDone(); + _runMicrotasks(); + emitPendingUnhandledRejections(); + } while (tickInfo[kLength] !== 0); + } + + function _tickDomainCallback() { + var callback, domain, args, tock; + + do { + while (tickInfo[kIndex] < tickInfo[kLength]) { + tock = nextTickQueue[tickInfo[kIndex]++]; + callback = tock.callback; + domain = tock.domain; + args = tock.args; + if (domain) + domain.enter(); + // Using separate callback execution functions allows direct + // callback invocation with small numbers of arguments to avoid the + // performance hit associated with using `fn.apply()` + _combinedTickCallback(args, callback); + if (1e4 < tickInfo[kIndex]) + tickDone(); + if (domain) + domain.exit(); + } + tickDone(); + _runMicrotasks(); + emitPendingUnhandledRejections(); + } while (tickInfo[kLength] !== 0); + } + + function TickObject(c, args) { + this.callback = c; + this.domain = process.domain || null; + this.args = args; + } + + function nextTick(callback) { + if (typeof callback !== 'function') + throw new TypeError('callback is not a function'); + // on the way out, don't bother. it won't get fired anyway. + if (process._exiting) + return; + + var args; + if (arguments.length > 1) { + args = new Array(arguments.length - 1); + for (var i = 1; i < arguments.length; i++) + args[i - 1] = arguments[i]; + } + + nextTickQueue.push(new TickObject(callback, args)); + tickInfo[kLength]++; + } +} diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js new file mode 100644 index 00000000000000..165bf3319ee7db --- /dev/null +++ b/lib/internal/process/promises.js @@ -0,0 +1,61 @@ +'use strict'; + +const promiseRejectEvent = process._promiseRejectEvent; +const hasBeenNotifiedProperty = new WeakMap(); +const pendingUnhandledRejections = []; + +exports.setup = setupPromises; + +function setupPromises(scheduleMicrotasks) { + process._setupPromises(function(event, promise, reason) { + if (event === promiseRejectEvent.unhandled) + unhandledRejection(promise, reason); + else if (event === promiseRejectEvent.handled) + rejectionHandled(promise); + else + require('assert').fail('unexpected PromiseRejectEvent'); + }); + + function unhandledRejection(promise, reason) { + hasBeenNotifiedProperty.set(promise, false); + addPendingUnhandledRejection(promise, reason); + } + + function rejectionHandled(promise) { + var hasBeenNotified = hasBeenNotifiedProperty.get(promise); + if (hasBeenNotified !== undefined) { + hasBeenNotifiedProperty.delete(promise); + if (hasBeenNotified === true) { + process.nextTick(function() { + process.emit('rejectionHandled', promise); + }); + } + + } + } + + function emitPendingUnhandledRejections() { + var hadListeners = false; + while (pendingUnhandledRejections.length > 0) { + var promise = pendingUnhandledRejections.shift(); + var reason = pendingUnhandledRejections.shift(); + if (hasBeenNotifiedProperty.get(promise) === false) { + hasBeenNotifiedProperty.set(promise, true); + if (!process.emit('unhandledRejection', reason, promise)) { + // Nobody is listening. + // TODO(petkaantonov) Take some default action, see #830 + } else { + hadListeners = true; + } + } + } + return hadListeners; + } + + function addPendingUnhandledRejection(promise, reason) { + pendingUnhandledRejections.push(promise, reason); + scheduleMicrotasks(); + } + + return emitPendingUnhandledRejections; +} diff --git a/lib/internal/process/stdio.js b/lib/internal/process/stdio.js new file mode 100644 index 00000000000000..55689069ff2cb5 --- /dev/null +++ b/lib/internal/process/stdio.js @@ -0,0 +1,161 @@ +'use strict'; + +exports.setup = setupStdio; + +function setupStdio() { + var stdin, stdout, stderr; + + process.__defineGetter__('stdout', function() { + if (stdout) return stdout; + stdout = createWritableStdioStream(1); + stdout.destroy = stdout.destroySoon = function(er) { + er = er || new Error('process.stdout cannot be closed.'); + stdout.emit('error', er); + }; + if (stdout.isTTY) { + process.on('SIGWINCH', function() { + stdout._refreshSize(); + }); + } + return stdout; + }); + + process.__defineGetter__('stderr', function() { + if (stderr) return stderr; + stderr = createWritableStdioStream(2); + stderr.destroy = stderr.destroySoon = function(er) { + er = er || new Error('process.stderr cannot be closed.'); + stderr.emit('error', er); + }; + if (stderr.isTTY) { + process.on('SIGWINCH', function() { + stderr._refreshSize(); + }); + } + return stderr; + }); + + process.__defineGetter__('stdin', function() { + if (stdin) return stdin; + + var tty_wrap = process.binding('tty_wrap'); + var fd = 0; + + switch (tty_wrap.guessHandleType(fd)) { + case 'TTY': + var tty = require('tty'); + stdin = new tty.ReadStream(fd, { + highWaterMark: 0, + readable: true, + writable: false + }); + break; + + case 'FILE': + var fs = require('fs'); + stdin = new fs.ReadStream(null, { fd: fd, autoClose: false }); + break; + + case 'PIPE': + case 'TCP': + var net = require('net'); + + // It could be that process has been started with an IPC channel + // sitting on fd=0, in such case the pipe for this fd is already + // present and creating a new one will lead to the assertion failure + // in libuv. + if (process._channel && process._channel.fd === fd) { + stdin = new net.Socket({ + handle: process._channel, + readable: true, + writable: false + }); + } else { + stdin = new net.Socket({ + fd: fd, + readable: true, + writable: false + }); + } + // Make sure the stdin can't be `.end()`-ed + stdin._writableState.ended = true; + break; + + default: + // Probably an error on in uv_guess_handle() + throw new Error('Implement me. Unknown stdin file type!'); + } + + // For supporting legacy API we put the FD here. + stdin.fd = fd; + + // stdin starts out life in a paused state, but node doesn't + // know yet. Explicitly to readStop() it to put it in the + // not-reading state. + if (stdin._handle && stdin._handle.readStop) { + stdin._handle.reading = false; + stdin._readableState.reading = false; + stdin._handle.readStop(); + } + + // if the user calls stdin.pause(), then we need to stop reading + // immediately, so that the process can close down. + stdin.on('pause', function() { + if (!stdin._handle) + return; + stdin._readableState.reading = false; + stdin._handle.reading = false; + stdin._handle.readStop(); + }); + + return stdin; + }); + + process.openStdin = function() { + process.stdin.resume(); + return process.stdin; + }; +} + +function createWritableStdioStream(fd) { + var stream; + var tty_wrap = process.binding('tty_wrap'); + + // Note stream._type is used for test-module-load-list.js + + switch (tty_wrap.guessHandleType(fd)) { + case 'TTY': + var tty = require('tty'); + stream = new tty.WriteStream(fd); + stream._type = 'tty'; + break; + + case 'FILE': + var fs = require('fs'); + stream = new fs.SyncWriteStream(fd, { autoClose: false }); + stream._type = 'fs'; + break; + + case 'PIPE': + case 'TCP': + var net = require('net'); + stream = new net.Socket({ + fd: fd, + readable: false, + writable: true + }); + stream._type = 'pipe'; + break; + + default: + // Probably an error on in uv_guess_handle() + throw new Error('Implement me. Unknown stream file type!'); + } + + // For supporting legacy API we put the FD here. + stream.fd = fd; + + stream._isStdio = true; + + return stream; +} diff --git a/node.gyp b/node.gyp index dc525e1421333d..0eeebfcad430a6 100644 --- a/node.gyp +++ b/node.gyp @@ -16,7 +16,7 @@ 'node_target_type%': 'executable', 'node_core_target_name%': 'node', 'library_files': [ - 'src/node.js', + 'lib/internal/bootstrap_node.js', 'lib/_debug_agent.js', 'lib/_debugger.js', 'lib/assert.js', @@ -75,6 +75,10 @@ 'lib/internal/linkedlist.js', 'lib/internal/net.js', 'lib/internal/module.js', + 'lib/internal/process/next_tick.js', + 'lib/internal/process/promises.js', + 'lib/internal/process/stdio.js', + 'lib/internal/process.js', 'lib/internal/readline.js', 'lib/internal/repl.js', 'lib/internal/socket_list.js', diff --git a/src/node.js b/src/node.js deleted file mode 100644 index c58871e31df084..00000000000000 --- a/src/node.js +++ /dev/null @@ -1,972 +0,0 @@ -// Hello, and welcome to hacking node.js! -// -// This file is invoked by node::LoadEnvironment in src/node.cc, and is -// responsible for bootstrapping the node.js core. As special caution is given -// to the performance of the startup process, many dependencies are invoked -// lazily. - -'use strict'; - -(function(process) { - this.global = this; - - function startup() { - var EventEmitter = NativeModule.require('events'); - process._eventsCount = 0; - - Object.setPrototypeOf(process, Object.create(EventEmitter.prototype, { - constructor: { - value: process.constructor - } - })); - - EventEmitter.call(process); - - let eeWarned = false; - Object.defineProperty(process, 'EventEmitter', { - get() { - const internalUtil = NativeModule.require('internal/util'); - eeWarned = internalUtil.printDeprecationMessage( - "process.EventEmitter is deprecated. Use require('events') instead.", - eeWarned - ); - return EventEmitter; - } - }); - - startup.setupProcessObject(); - - // do this good and early, since it handles errors. - startup.processFatal(); - - startup.globalVariables(); - startup.globalTimeouts(); - startup.globalConsole(); - - startup.processAssert(); - startup.processConfig(); - startup.processNextTick(); - startup.processPromises(); - startup.processStdio(); - startup.processKillAndExit(); - startup.processSignalHandlers(); - - // Do not initialize channel in debugger agent, it deletes env variable - // and the main thread won't see it. - if (process.argv[1] !== '--debug-agent') - startup.processChannel(); - - startup.processRawDebug(); - - process.argv[0] = process.execPath; - - // 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. - - if (NativeModule.exists('_third_party_main')) { - // 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. - process.nextTick(function() { - NativeModule.require('_third_party_main'); - }); - - } else if (process.argv[1] == 'debug') { - // Start the debugger agent - NativeModule.require('_debugger').start(); - - } else if (process.argv[1] == '--debug-agent') { - // Start the debugger agent - NativeModule.require('_debug_agent').start(); - - } else if (process.profProcess) { - NativeModule.require('internal/v8_prof_processor'); - - } else { - // There is user code to be run - - // 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) { - var cluster = NativeModule.require('cluster'); - cluster._setupWorker(); - - // Make sure it's not accidentally inherited by child processes. - delete process.env.NODE_UNIQUE_ID; - } - - if (process._eval != null && !process._forceRepl) { - // User passed '-e' or '--eval' arguments to Node without '-i' or - // '--interactive' - startup.preloadModules(); - evalScript('[eval]'); - } else if (process.argv[1]) { - // make process.argv[1] into a full path - var path = NativeModule.require('path'); - process.argv[1] = path.resolve(process.argv[1]); - - var Module = NativeModule.require('module'); - - // check if user passed `-c` or `--check` arguments to Node. - if (process._syntax_check_only != null) { - var vm = NativeModule.require('vm'); - var fs = NativeModule.require('fs'); - var internalModule = NativeModule.require('internal/module'); - // read the source - var filename = Module._resolveFilename(process.argv[1]); - var source = fs.readFileSync(filename, 'utf-8'); - // remove shebang and BOM - source = internalModule.stripBOM(source.replace(/^\#\!.*/, '')); - // wrap it - source = Module.wrap(source); - // compile the script, this will throw if it fails - new vm.Script(source, {filename: filename, displayErrors: true}); - process.exit(0); - } - - startup.preloadModules(); - if (global.v8debug && - process.execArgv.some(function(arg) { - return arg.match(/^--debug-brk(=[0-9]*)?$/); - })) { - - // XXX Fix this terrible hack! - // - // Give the client program a few ticks to connect. - // Otherwise, there's a race condition where `node debug foo.js` - // will not be able to connect in time to catch the first - // breakpoint message on line 1. - // - // A better fix would be to somehow get a message from the - // global.v8debug object about a connection, and runMain when - // that occurs. --isaacs - - var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50; - setTimeout(Module.runMain, debugTimeout); - - } else { - // Main entry point into most programs: - Module.runMain(); - } - - } else { - startup.preloadModules(); - // If -i or --interactive were passed, or stdin is a TTY. - if (process._forceRepl || NativeModule.require('tty').isatty(0)) { - // REPL - var cliRepl = NativeModule.require('internal/repl'); - cliRepl.createInternalRepl(process.env, function(err, repl) { - if (err) { - throw err; - } - repl.on('exit', function() { - if (repl._flushing) { - repl.pause(); - return repl.once('flushHistory', function() { - process.exit(); - }); - } - process.exit(); - }); - }); - - if (process._eval != null) { - // User passed '-e' or '--eval' - evalScript('[eval]'); - } - } else { - // Read all of stdin - execute it. - process.stdin.setEncoding('utf8'); - - var code = ''; - process.stdin.on('data', function(d) { - code += d; - }); - - process.stdin.on('end', function() { - process._eval = code; - evalScript('[stdin]'); - }); - } - } - } - } - - startup.setupProcessObject = function() { - const _hrtime = process.hrtime; - const hrValues = new Uint32Array(3); - - process._setupProcessObject(pushValueToArray); - - function pushValueToArray() { - for (var i = 0; i < arguments.length; i++) - this.push(arguments[i]); - } - - process.hrtime = function hrtime(ar) { - _hrtime(hrValues); - - if (typeof ar !== 'undefined') { - if (Array.isArray(ar)) { - const sec = (hrValues[0] * 0x100000000 + hrValues[1]) - ar[0]; - const nsec = hrValues[2] - ar[1]; - return [nsec < 0 ? sec - 1 : sec, nsec < 0 ? nsec + 1e9 : nsec]; - } - - throw new TypeError('process.hrtime() only accepts an Array tuple'); - } - - return [ - hrValues[0] * 0x100000000 + hrValues[1], - hrValues[2] - ]; - }; - }; - - startup.globalVariables = function() { - global.process = process; - global.global = global; - const util = NativeModule.require('util'); - - // Deprecate GLOBAL and root - ['GLOBAL', 'root'].forEach(function(name) { - // getter - const get = util.deprecate(function() { - return this; - }, `'${name}' is deprecated, use 'global'`); - // setter - const set = util.deprecate(function(value) { - Object.defineProperty(this, name, { - configurable: true, - writable: true, - enumerable: true, - value: value - }); - }, `'${name}' is deprecated, use 'global'`); - // define property - Object.defineProperty(global, name, { get, set, configurable: true }); - }); - - global.Buffer = NativeModule.require('buffer').Buffer; - process.domain = null; - process._exiting = false; - }; - - startup.globalTimeouts = function() { - 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; - }; - - startup.globalConsole = function() { - global.__defineGetter__('console', function() { - return NativeModule.require('console'); - }); - }; - - - startup._lazyConstants = null; - - startup.lazyConstants = function() { - if (!startup._lazyConstants) { - startup._lazyConstants = process.binding('constants'); - } - return startup._lazyConstants; - }; - - startup.processFatal = function() { - - process._fatalException = function(er) { - var caught; - - if (process.domain && process.domain._errorHandler) - caught = process.domain._errorHandler(er) || caught; - - if (!caught) - caught = 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 - if (!caught) { - try { - if (!process._exiting) { - process._exiting = true; - process.emit('exit', 1); - } - } catch (er) { - // nothing to be done about it at this point. - } - - // if we handled an error, then make sure any ticks get processed - } else { - NativeModule.require('timers').setImmediate(process._tickCallback); - } - - return caught; - }; - }; - - var assert; - startup.processAssert = function() { - assert = process.assert = function(x, msg) { - if (!x) throw new Error(msg || 'assertion error'); - }; - }; - - startup.processConfig = function() { - // used for `process.config`, but not a real module - var config = NativeModule._source.config; - delete NativeModule._source.config; - - // strip the gyp comment line at the beginning - config = config.split('\n') - .slice(1) - .join('\n') - .replace(/"/g, '\\"') - .replace(/'/g, '"'); - - process.config = JSON.parse(config, function(key, value) { - if (value === 'true') return true; - if (value === 'false') return false; - return value; - }); - }; - - var addPendingUnhandledRejection; - var hasBeenNotifiedProperty = new WeakMap(); - startup.processNextTick = function() { - var nextTickQueue = []; - var pendingUnhandledRejections = []; - var microtasksScheduled = false; - - // Used to run V8's micro task queue. - var _runMicrotasks = {}; - - // *Must* match Environment::TickInfo::Fields in src/env.h. - var kIndex = 0; - var kLength = 1; - - process.nextTick = nextTick; - // Needs to be accessible from beyond this scope. - process._tickCallback = _tickCallback; - process._tickDomainCallback = _tickDomainCallback; - - // This tickInfo thing is used so that the C++ code in src/node.cc - // can have easy access to our nextTick state, and avoid unnecessary - // calls into JS land. - const tickInfo = process._setupNextTick(_tickCallback, _runMicrotasks); - - _runMicrotasks = _runMicrotasks.runMicrotasks; - - function tickDone() { - if (tickInfo[kLength] !== 0) { - if (tickInfo[kLength] <= tickInfo[kIndex]) { - nextTickQueue = []; - tickInfo[kLength] = 0; - } else { - nextTickQueue.splice(0, tickInfo[kIndex]); - tickInfo[kLength] = nextTickQueue.length; - } - } - tickInfo[kIndex] = 0; - } - - function scheduleMicrotasks() { - if (microtasksScheduled) - return; - - nextTickQueue.push({ - callback: runMicrotasksCallback, - domain: null - }); - - tickInfo[kLength]++; - microtasksScheduled = true; - } - - function runMicrotasksCallback() { - microtasksScheduled = false; - _runMicrotasks(); - - if (tickInfo[kIndex] < tickInfo[kLength] || - emitPendingUnhandledRejections()) - scheduleMicrotasks(); - } - - function _combinedTickCallback(args, callback) { - if (args === undefined) { - callback(); - } else { - 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; - default: - callback.apply(null, args); - } - } - } - - // Run callbacks that have no domain. - // Using domains will cause this to be overridden. - function _tickCallback() { - var callback, args, tock; - - do { - while (tickInfo[kIndex] < tickInfo[kLength]) { - tock = nextTickQueue[tickInfo[kIndex]++]; - callback = tock.callback; - args = tock.args; - // Using separate callback execution functions allows direct - // callback invocation with small numbers of arguments to avoid the - // performance hit associated with using `fn.apply()` - _combinedTickCallback(args, callback); - if (1e4 < tickInfo[kIndex]) - tickDone(); - } - tickDone(); - _runMicrotasks(); - emitPendingUnhandledRejections(); - } while (tickInfo[kLength] !== 0); - } - - function _tickDomainCallback() { - var callback, domain, args, tock; - - do { - while (tickInfo[kIndex] < tickInfo[kLength]) { - tock = nextTickQueue[tickInfo[kIndex]++]; - callback = tock.callback; - domain = tock.domain; - args = tock.args; - if (domain) - domain.enter(); - // Using separate callback execution functions allows direct - // callback invocation with small numbers of arguments to avoid the - // performance hit associated with using `fn.apply()` - _combinedTickCallback(args, callback); - if (1e4 < tickInfo[kIndex]) - tickDone(); - if (domain) - domain.exit(); - } - tickDone(); - _runMicrotasks(); - emitPendingUnhandledRejections(); - } while (tickInfo[kLength] !== 0); - } - - function TickObject(c, args) { - this.callback = c; - this.domain = process.domain || null; - this.args = args; - } - - function nextTick(callback) { - if (typeof callback !== 'function') - throw new TypeError('callback is not a function'); - // on the way out, don't bother. it won't get fired anyway. - if (process._exiting) - return; - - var args; - if (arguments.length > 1) { - args = new Array(arguments.length - 1); - for (var i = 1; i < arguments.length; i++) - args[i - 1] = arguments[i]; - } - - nextTickQueue.push(new TickObject(callback, args)); - tickInfo[kLength]++; - } - - function emitPendingUnhandledRejections() { - var hadListeners = false; - while (pendingUnhandledRejections.length > 0) { - var promise = pendingUnhandledRejections.shift(); - var reason = pendingUnhandledRejections.shift(); - if (hasBeenNotifiedProperty.get(promise) === false) { - hasBeenNotifiedProperty.set(promise, true); - if (!process.emit('unhandledRejection', reason, promise)) { - // Nobody is listening. - // TODO(petkaantonov) Take some default action, see #830 - } else { - hadListeners = true; - } - } - } - return hadListeners; - } - - addPendingUnhandledRejection = function(promise, reason) { - pendingUnhandledRejections.push(promise, reason); - scheduleMicrotasks(); - }; - }; - - startup.processPromises = function() { - var promiseRejectEvent = process._promiseRejectEvent; - - function unhandledRejection(promise, reason) { - hasBeenNotifiedProperty.set(promise, false); - addPendingUnhandledRejection(promise, reason); - } - - function rejectionHandled(promise) { - var hasBeenNotified = hasBeenNotifiedProperty.get(promise); - if (hasBeenNotified !== undefined) { - hasBeenNotifiedProperty.delete(promise); - if (hasBeenNotified === true) { - process.nextTick(function() { - process.emit('rejectionHandled', promise); - }); - } - - } - } - - process._setupPromises(function(event, promise, reason) { - if (event === promiseRejectEvent.unhandled) - unhandledRejection(promise, reason); - else if (event === promiseRejectEvent.handled) - rejectionHandled(promise); - else - NativeModule.require('assert').fail('unexpected PromiseRejectEvent'); - }); - }; - - function evalScript(name) { - var Module = NativeModule.require('module'); - var path = NativeModule.require('path'); - - try { - var cwd = process.cwd(); - } catch (e) { - // 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? - cwd = path.dirname(process.execPath); - } - - var module = new Module(name); - module.filename = path.join(cwd, name); - module.paths = Module._nodeModulePaths(cwd); - var script = process._eval; - var body = script; - 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`; - // Defer evaluation for a tick. This is a workaround for deferred - // events not firing when evaluating scripts from the command line, - // see https://github.com/nodejs/node/issues/1600. - process.nextTick(function() { - var result = module._compile(script, `${name}-wrapper`); - if (process._print_eval) console.log(result); - }); - } - - function createWritableStdioStream(fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - var tty = NativeModule.require('tty'); - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - break; - - case 'FILE': - var fs = NativeModule.require('fs'); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = NativeModule.require('net'); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - stream._type = 'pipe'; - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; - } - - startup.processStdio = function() { - var stdin, stdout, stderr; - - process.__defineGetter__('stdout', function() { - if (stdout) return stdout; - stdout = createWritableStdioStream(1); - stdout.destroy = stdout.destroySoon = function(er) { - er = er || new Error('process.stdout cannot be closed.'); - stdout.emit('error', er); - }; - if (stdout.isTTY) { - process.on('SIGWINCH', function() { - stdout._refreshSize(); - }); - } - return stdout; - }); - - process.__defineGetter__('stderr', function() { - if (stderr) return stderr; - stderr = createWritableStdioStream(2); - stderr.destroy = stderr.destroySoon = function(er) { - er = er || new Error('process.stderr cannot be closed.'); - stderr.emit('error', er); - }; - if (stderr.isTTY) { - process.on('SIGWINCH', function() { - stderr._refreshSize(); - }); - } - return stderr; - }); - - process.__defineGetter__('stdin', function() { - if (stdin) return stdin; - - var tty_wrap = process.binding('tty_wrap'); - var fd = 0; - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - var tty = NativeModule.require('tty'); - stdin = new tty.ReadStream(fd, { - highWaterMark: 0, - readable: true, - writable: false - }); - break; - - case 'FILE': - var fs = NativeModule.require('fs'); - stdin = new fs.ReadStream(null, { fd: fd, autoClose: false }); - break; - - case 'PIPE': - case 'TCP': - var net = NativeModule.require('net'); - - // It could be that process has been started with an IPC channel - // sitting on fd=0, in such case the pipe for this fd is already - // present and creating a new one will lead to the assertion failure - // in libuv. - if (process._channel && process._channel.fd === fd) { - stdin = new net.Socket({ - handle: process._channel, - readable: true, - writable: false - }); - } else { - stdin = new net.Socket({ - fd: fd, - readable: true, - writable: false - }); - } - // Make sure the stdin can't be `.end()`-ed - stdin._writableState.ended = true; - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stdin file type!'); - } - - // For supporting legacy API we put the FD here. - stdin.fd = fd; - - // stdin starts out life in a paused state, but node doesn't - // know yet. Explicitly to readStop() it to put it in the - // not-reading state. - if (stdin._handle && stdin._handle.readStop) { - stdin._handle.reading = false; - stdin._readableState.reading = false; - stdin._handle.readStop(); - } - - // if the user calls stdin.pause(), then we need to stop reading - // immediately, so that the process can close down. - stdin.on('pause', function() { - if (!stdin._handle) - return; - stdin._readableState.reading = false; - stdin._handle.reading = false; - stdin._handle.readStop(); - }); - - return stdin; - }); - - process.openStdin = function() { - process.stdin.resume(); - return process.stdin; - }; - }; - - startup.processKillAndExit = function() { - - process.exit = function(code) { - if (code || code === 0) - process.exitCode = code; - - if (!process._exiting) { - process._exiting = true; - process.emit('exit', process.exitCode || 0); - } - process.reallyExit(process.exitCode || 0); - }; - - process.kill = function(pid, sig) { - var err; - - if (pid != (pid | 0)) { - throw new TypeError('invalid pid'); - } - - // preserve null signal - if (0 === sig) { - err = process._kill(pid, 0); - } else { - sig = sig || 'SIGTERM'; - if (startup.lazyConstants()[sig] && - sig.slice(0, 3) === 'SIG') { - err = process._kill(pid, startup.lazyConstants()[sig]); - } else { - throw new Error(`Unknown signal: ${sig}`); - } - } - - if (err) { - var errnoException = NativeModule.require('util')._errnoException; - throw errnoException(err, 'kill'); - } - - return true; - }; - }; - - startup.processSignalHandlers = function() { - // Load events module in order to access prototype elements on process like - // process.addListener. - var signalWraps = {}; - - function isSignal(event) { - return typeof event === 'string' && - event.slice(0, 3) === 'SIG' && - startup.lazyConstants().hasOwnProperty(event); - } - - // Detect presence of a listener for the special signal types - process.on('newListener', function(type, listener) { - if (isSignal(type) && - !signalWraps.hasOwnProperty(type)) { - var Signal = process.binding('signal_wrap').Signal; - var wrap = new Signal(); - - wrap.unref(); - - wrap.onsignal = function() { process.emit(type); }; - - var signum = startup.lazyConstants()[type]; - var err = wrap.start(signum); - if (err) { - wrap.close(); - var errnoException = NativeModule.require('util')._errnoException; - throw errnoException(err, 'uv_signal_start'); - } - - signalWraps[type] = wrap; - } - }); - - process.on('removeListener', function(type, listener) { - if (signalWraps.hasOwnProperty(type) && this.listenerCount(type) === 0) { - signalWraps[type].close(); - delete signalWraps[type]; - } - }); - }; - - - startup.processChannel = function() { - // If we were spawned with env NODE_CHANNEL_FD then load that up and - // start parsing data from that stream. - if (process.env.NODE_CHANNEL_FD) { - var fd = parseInt(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; - - var cp = NativeModule.require('child_process'); - - // Load tcp_wrap to avoid situation where we might immediately receive - // a message. - // FIXME is this really necessary? - process.binding('tcp_wrap'); - - cp._forkChild(fd); - assert(process.send); - } - }; - - - startup.processRawDebug = function() { - var format = NativeModule.require('util').format; - var rawDebug = process._rawDebug; - process._rawDebug = function() { - rawDebug(format.apply(null, arguments)); - }; - }; - - // Load preload modules - startup.preloadModules = function() { - if (process._preload_modules) { - NativeModule.require('module')._preloadModules(process._preload_modules); - } - }; - - // Below you find a minimal module system, which is used to load the node - // core modules found in lib/*.js. All core modules are compiled into the - // node binary, so they can be loaded faster. - - var ContextifyScript = process.binding('contextify').ContextifyScript; - function runInThisContext(code, options) { - var script = new ContextifyScript(code, options); - return script.runInThisContext(); - } - - function NativeModule(id) { - this.filename = `${id}.js`; - this.id = id; - this.exports = {}; - this.loaded = false; - } - - NativeModule._source = process.binding('natives'); - NativeModule._cache = {}; - - NativeModule.require = function(id) { - if (id == 'native_module') { - return NativeModule; - } - - var cached = NativeModule.getCached(id); - if (cached) { - return cached.exports; - } - - if (!NativeModule.exists(id)) { - throw new Error(`No such native module ${id}`); - } - - process.moduleLoadList.push(`NativeModule ${id}`); - - var nativeModule = new NativeModule(id); - - nativeModule.cache(); - nativeModule.compile(); - - return nativeModule.exports; - }; - - NativeModule.getCached = function(id) { - return NativeModule._cache[id]; - }; - - NativeModule.exists = function(id) { - return NativeModule._source.hasOwnProperty(id); - }; - - const EXPOSE_INTERNALS = process.execArgv.some(function(arg) { - return arg.match(/^--expose[-_]internals$/); - }); - - if (EXPOSE_INTERNALS) { - NativeModule.nonInternalExists = NativeModule.exists; - - NativeModule.isInternal = function(id) { - return false; - }; - } else { - NativeModule.nonInternalExists = function(id) { - return NativeModule.exists(id) && !NativeModule.isInternal(id); - }; - - NativeModule.isInternal = function(id) { - return id.startsWith('internal/'); - }; - } - - - 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, __filename, __dirname) { ', - '\n});' - ]; - - NativeModule.prototype.compile = function() { - var source = NativeModule.getSource(this.id); - source = NativeModule.wrap(source); - - var fn = runInThisContext(source, { - filename: this.filename, - lineOffset: 0, - displayErrors: true - }); - fn(this.exports, NativeModule.require, this, this.filename); - - this.loaded = true; - }; - - NativeModule.prototype.cache = function() { - NativeModule._cache[this.id] = this; - }; - - startup(); -}); diff --git a/src/node_javascript.cc b/src/node_javascript.cc index d5377047c0ec5c..6f445f76df2407 100644 --- a/src/node_javascript.cc +++ b/src/node_javascript.cc @@ -14,15 +14,17 @@ using v8::String; Local MainSource(Environment* env) { return String::NewFromUtf8( - env->isolate(), reinterpret_cast(node_native), - NewStringType::kNormal, sizeof(node_native)).ToLocalChecked(); + env->isolate(), + reinterpret_cast(internal_bootstrap_node_native), + NewStringType::kNormal, + sizeof(internal_bootstrap_node_native)).ToLocalChecked(); } void DefineJavaScript(Environment* env, Local target) { HandleScope scope(env->isolate()); for (auto native : natives) { - if (native.source != node_native) { + if (native.source != internal_bootstrap_node_native) { Local name = String::NewFromUtf8(env->isolate(), native.name); Local source = String::NewFromUtf8( diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out index c299ec3ae1345c..62f330725606b2 100644 --- a/test/message/eval_messages.out +++ b/test/message/eval_messages.out @@ -7,8 +7,8 @@ SyntaxError: Strict mode code may not include a with statement at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) 42 42 [eval]:1 @@ -20,8 +20,8 @@ Error: hello at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) [eval]:1 throw new Error("hello") ^ @@ -31,8 +31,8 @@ Error: hello at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) 100 [eval]:1 var x = 100; y = x; @@ -43,8 +43,8 @@ ReferenceError: y is not defined at Object. ([eval]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) [eval]:1 var ______________________________________________; throw 10 ^ diff --git a/test/message/nexttick_throw.out b/test/message/nexttick_throw.out index 72f04b00936977..6504bd315da900 100644 --- a/test/message/nexttick_throw.out +++ b/test/message/nexttick_throw.out @@ -4,8 +4,8 @@ ^ ReferenceError: undefined_reference_error_maker is not defined at *test*message*nexttick_throw.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) at Function.Module.runMain (module.js:*:*) at startup (node.js:*:*) at node.js:*:* diff --git a/test/message/stdin_messages.out b/test/message/stdin_messages.out index 2e08a70cc46fbc..a7c45a1fbb33fb 100644 --- a/test/message/stdin_messages.out +++ b/test/message/stdin_messages.out @@ -8,8 +8,8 @@ SyntaxError: Strict mode code may not include a with statement at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) 42 42 @@ -22,8 +22,8 @@ Error: hello at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) [stdin]:1 throw new Error("hello") @@ -34,8 +34,8 @@ Error: hello at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) 100 [stdin]:1 @@ -47,8 +47,8 @@ ReferenceError: y is not defined at Object. ([stdin]-wrapper:*:*) at Module._compile (module.js:*:*) at node.js:*:* - at _combinedTickCallback (node.js:*:*) - at process._tickCallback (node.js:*:*) + at _combinedTickCallback (internal/process/next_tick.js:*:*) + at process._tickCallback (internal/process/next_tick.js:*:*) [stdin]:1 var ______________________________________________; throw 10