+// Hello, and welcome to hacking node.js!
+//
+// This file is invoked by node::Load in src/node.cc, and responsible for
+// bootstrapping the node.js core. Special caution is given to the performance
+// of the startup process, so many dependencies are invoked lazily.
(function(process) {
-
global = this;
- global.process = process;
- global.global = global;
- global.GLOBAL = global;
- global.root = global;
-
- /** deprecation errors ************************************************/
-
- function removed(reason) {
- return function() {
- throw new Error(reason);
- };
- }
-
- process.debug =
- removed('process.debug() use console.error() instead');
- process.error =
- removed('process.error() use console.error() instead');
- process.watchFile =
- removed('process.watchFile() has moved to fs.watchFile()');
- process.unwatchFile =
- removed('process.unwatchFile() has moved to fs.unwatchFile()');
- process.mixin =
- removed('process.mixin() has been removed.');
- process.createChildProcess =
- removed('childProcess API has changed. See doc/api.txt.');
- process.inherits =
- removed('process.inherits() has moved to sys.inherits.');
- process._byteLength =
- removed('process._byteLength() has moved to Buffer.byteLength');
-
- process.assert = function(x, msg) {
- if (!x) throw new Error(msg || 'assertion error');
- };
- var Script = process.binding('evals').Script;
- var runInThisContext = Script.runInThisContext;
+ function startup() {
+ startup.globalVariables();
+ startup.globalTimeouts();
+ startup.globalConsole();
- // lazy loaded.
- var constants;
- function lazyConstants() {
- if (!constants) constants = process.binding('constants');
- return constants;
- }
+ startup.processAssert();
+ startup.processNextTick();
+ startup.processStdio();
+ startup.processKillAndExit();
+ startup.processSignalHandlers();
+ startup.removedMethods();
- // nextTick()
+ startup.resolveArgv0();
- var nextTickQueue = [];
+ if (startup.runThirdPartyMain()) {
+ return;
+ }
- process._tickCallback = function() {
- var l = nextTickQueue.length;
- if (l === 0) return;
+ if (startup.runDebugger()) {
+ return;
+ }
- try {
- for (var i = 0; i < l; i++) {
- nextTickQueue[i]();
- }
+ if (startup.runScript()) {
+ return;
}
- catch (e) {
- nextTickQueue.splice(0, i + 1);
- if (i + 1 < l) {
- process._needTickCallback();
- }
- throw e; // process.nextTick error, or 'error' event on first tick
+
+ if (startup.runEval()) {
+ return;
}
- nextTickQueue.splice(0, l);
- };
+ startup.runRepl();
+ }
- process.nextTick = function(callback) {
- nextTickQueue.push(callback);
- process._needTickCallback();
+ startup.globalVariables = function() {
+ global.process = process;
+ global.global = global;
+ global.GLOBAL = global;
+ global.root = global;
+ global.Buffer = NativeModule.require('buffer').Buffer;
};
- // Native modules don't need a full require function. So we can bootstrap
- // most of the system with this mini module system.
- var NativeModule = (function() {
- function NativeModule(id) {
- this.filename = id + '.js';
- this.id = id;
- this.exports = {};
- this.loaded = false;
- }
+ startup.globalTimeouts = function() {
+ global.setTimeout = function() {
+ var t = NativeModule.require('timers');
+ return t.setTimeout.apply(this, arguments);
+ };
- NativeModule._source = process.binding('natives');
- NativeModule._cache = {};
+ global.setInterval = function() {
+ var t = NativeModule.require('timers');
+ return t.setInterval.apply(this, arguments);
+ };
- NativeModule.require = function(id) {
- if (id == 'native_module') {
- return NativeModule;
- }
+ global.clearTimeout = function() {
+ var t = NativeModule.require('timers');
+ return t.clearTimeout.apply(this, arguments);
+ };
- var cached = NativeModule.getCached(id);
- if (cached) {
- return cached.exports;
- }
+ global.clearInterval = function() {
+ var t = NativeModule.require('timers');
+ return t.clearInterval.apply(this, arguments);
+ };
+ };
- if (!NativeModule.exists(id)) {
- throw new Error('No such native module ' + id);
- }
+ startup.globalConsole = function() {
+ global.__defineGetter__('console', function() {
+ return NativeModule.require('console');
+ });
+ };
- var nativeModule = new NativeModule(id);
- nativeModule.compile();
- nativeModule.cache();
+ startup._lazyConstants = null;
+
+ startup.lazyConstants = function() {
+ if (!startup._lazyConstants) {
+ startup._lazyConstants = process.binding('constants');
+ }
+ return startup._lazyConstants;
+ };
- return nativeModule.exports;
+ startup.processAssert = function() {
+ process.assert = function(x, msg) {
+ if (!x) {
+ throw new Error(msg || 'assertion error');
+ }
};
+ };
- NativeModule.getCached = function(id) {
- return NativeModule._cache[id];
- }
+ startup.processNextTick = function() {
+ var nextTickQueue = [];
- NativeModule.exists = function(id) {
- return (id in NativeModule._source);
- }
+ process._tickCallback = function() {
+ var l = nextTickQueue.length;
+ if (l === 0) return;
- NativeModule.getSource = function(id) {
- return NativeModule._source[id];
- }
+ try {
+ for (var i = 0; i < l; i++) {
+ nextTickQueue[i]();
+ }
+ }
+ catch (e) {
+ nextTickQueue.splice(0, i + 1);
+ if (i + 1 < l) {
+ process._needTickCallback();
+ }
+ throw e; // process.nextTick error, or 'error' event on first tick
+ }
- NativeModule.wrap = function(script) {
- return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
+ nextTickQueue.splice(0, l);
};
- NativeModule.wrapper = [
- '(function (exports, require, module, __filename, __dirname) { ',
- '\n});'
- ];
+ process.nextTick = function(callback) {
+ nextTickQueue.push(callback);
+ process._needTickCallback();
+ };
+ };
- NativeModule.prototype.compile = function() {
- var source = NativeModule.getSource(this.id);
- source = NativeModule.wrap(source);
+ startup.processStdio = function() {
+ var stdout, stdin;
+
+ process.__defineGetter__('stdout', function() {
+ if (stdout) return stdout;
+
+ var binding = process.binding('stdio'),
+ net = NativeModule.require('net'),
+ fs = NativeModule.require('fs'),
+ tty = NativeModule.require('tty'),
+ fd = binding.stdoutFD;
+
+ if (binding.isatty(fd)) {
+ stdout = new tty.WriteStream(fd);
+ } else if (binding.isStdoutBlocking()) {
+ stdout = new fs.WriteStream(null, {fd: fd});
+ } else {
+ stdout = new net.Stream(fd);
+ // FIXME Should probably have an option in net.Stream to create a
+ // stream from an existing fd which is writable only. But for now
+ // we'll just add this hack and set the `readable` member to false.
+ // Test: ./node test/fixtures/echo.js < /etc/passwd
+ stdout.readable = false;
+ }
+
+ return stdout;
+ });
+
+ process.__defineGetter__('stdin', function() {
+ if (stdin) return stdin;
+
+ var binding = process.binding('stdio'),
+ net = NativeModule.require('net'),
+ fs = NativeModule.require('fs'),
+ tty = NativeModule.require('tty'),
+ fd = binding.openStdin();
+
+ if (binding.isatty(fd)) {
+ stdin = new tty.ReadStream(fd);
+ } else if (binding.isStdinBlocking()) {
+ stdin = new fs.ReadStream(null, {fd: fd});
+ } else {
+ stdin = new net.Stream(fd);
+ stdin.readable = true;
+ }
- var fn = runInThisContext(source, this.filename, true);
- fn(this.exports, NativeModule.require, this, this.filename);
+ return stdin;
+ });
- this.loaded = true;
+ process.openStdin = function() {
+ process.stdin.resume();
+ return process.stdin;
};
+ };
- NativeModule.prototype.cache = function() {
- NativeModule._cache[this.id] = this;
+ startup.processKillAndExit = function() {
+ process.exit = function(code) {
+ process.emit('exit', code || 0);
+ process.reallyExit(code || 0);
};
- return NativeModule;
- })();
+ process.kill = function(pid, sig) {
+ sig = sig || 'SIGTERM';
- var Module = NativeModule.require('module').Module;
+ if (!startup.lazyConstants()[sig]) {
+ throw new Error('Unknown signal: ' + sig);
+ }
- // Load events module in order to access prototype elements on process like
- // process.addListener.
- var events = NativeModule.require('events');
+ process._kill(pid, startup.lazyConstants()[sig]);
+ };
+ };
- // Signal Handlers
- (function() {
+ startup.processSignalHandlers = function() {
+ // Load events module in order to access prototype elements on process like
+ // process.addListener.
+ var events = NativeModule.require('events');
var signalWatchers = {};
var addListener = process.addListener;
var removeListener = process.removeListener;
function isSignal(event) {
- return event.slice(0, 3) === 'SIG' && lazyConstants()[event];
+ return event.slice(0, 3) === 'SIG' && startup.lazyConstants()[event];
}
// Wrap addListener for the special signal types
if (isSignal(type)) {
if (!signalWatchers.hasOwnProperty(type)) {
var b = process.binding('signal_watcher');
- var w = new b.SignalWatcher(lazyConstants()[type]);
+ var w = new b.SignalWatcher(startup.lazyConstants()[type]);
w.callback = function() { process.emit(type); };
signalWatchers[type] = w;
w.start();
return ret;
};
- })();
-
-
- global.setTimeout = function() {
- var t = NativeModule.require('timers');
- return t.setTimeout.apply(this, arguments);
};
- global.setInterval = function() {
- var t = NativeModule.require('timers');
- return t.setInterval.apply(this, arguments);
+ startup._removedProcessMethods = {
+ 'debug': 'process.debug() use console.error() instead',
+ 'error': 'process.error() use console.error() instead',
+ 'watchFile': 'process.watchFile() has moved to fs.watchFile()',
+ 'unwatchFile': 'process.unwatchFile() has moved to fs.unwatchFile()',
+ 'mixin': 'process.mixin() has been removed.',
+ 'createChildProcess': 'childProcess API has changed. See doc/api.txt.',
+ 'inherits': 'process.inherits() has moved to sys.inherits.',
+ '_byteLength': 'process._byteLength() has moved to Buffer.byteLength',
};
- global.clearTimeout = function() {
- var t = NativeModule.require('timers');
- return t.clearTimeout.apply(this, arguments);
+ startup.removedMethods = function() {
+ for (var method in startup._removedProcessMethods) {
+ var reason = startup._removedProcessMethods[method];
+ process[method] = startup._removedMethod(reason);
+ }
};
- global.clearInterval = function() {
- var t = NativeModule.require('timers');
- return t.clearInterval.apply(this, arguments);
+ startup._removedMethod = function(reason) {
+ return function() {
+ throw new Error(reason);
+ };
};
+ startup.resolveArgv0 = function() {
+ var cwd = process.cwd();
+ var isWindows = process.platform === 'win32';
+
+ // Make process.argv[0] into a full path, but only touch argv[0] if it's
+ // not a system $PATH lookup.
+ // TODO: Make this work on Windows as well. Note that "node" might
+ // execute cwd\node.exe, or some %PATH%\node.exe on Windows,
+ // and that every directory has its own cwd, so d:node.exe is valid.
+ var argv0 = process.argv[0];
+ if (!isWindows && argv0.indexOf('/') !== -1 && argv0.charAt(0) !== '/') {
+ var path = NativeModule.require('path');
+ process.argv[0] = path.join(cwd, process.argv[0]);
+ }
+ };
- var stdout, stdin;
+ startup.runThirdPartyMain = function() {
+ // 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')) {
+ return;
+ }
+ process.nextTick(function() {
+ NativeModule.require('_third_party_main');
+ });
+ return true;
+ };
- process.__defineGetter__('stdout', function() {
- if (stdout) return stdout;
+ startup.runDebugger = function() {
+ if (!(process.argv[1] == 'debug')) {
+ return;
+ }
- var binding = process.binding('stdio'),
- net = NativeModule.require('net'),
- fs = NativeModule.require('fs'),
- tty = NativeModule.require('tty'),
- fd = binding.stdoutFD;
+ // Start the debugger agent
+ var d = NativeModule.require('_debugger');
+ d.start();
+ return true;
+ };
- if (binding.isatty(fd)) {
- stdout = new tty.WriteStream(fd);
- } else if (binding.isStdoutBlocking()) {
- stdout = new fs.WriteStream(null, {fd: fd});
- } else {
- stdout = new net.Stream(fd);
- // FIXME Should probably have an option in net.Stream to create a
- // stream from an existing fd which is writable only. But for now
- // we'll just add this hack and set the `readable` member to false.
- // Test: ./node test/fixtures/echo.js < /etc/passwd
- stdout.readable = false;
+ startup.runScript = function() {
+ if (!process.argv[1]) {
+ return;
}
- return stdout;
- });
+ // make process.argv[1] into a full path
+ if (!(/^http:\/\//).exec(process.argv[1])) {
+ var path = NativeModule.require('path');
+ process.argv[1] = path.resolve(process.argv[1]);
+ }
+ var Module = NativeModule.require('module');
- process.__defineGetter__('stdin', function() {
- if (stdin) return stdin;
+ // REMOVEME: nextTick should not be necessary. This hack to get
+ // test/simple/test-exception-handler2.js working.
+ process.nextTick(Module.runMain);
- var binding = process.binding('stdio'),
- net = NativeModule.require('net'),
- fs = NativeModule.require('fs'),
- tty = NativeModule.require('tty'),
- fd = binding.openStdin();
+ return true;
+ };
- if (binding.isatty(fd)) {
- stdin = new tty.ReadStream(fd);
- } else if (binding.isStdinBlocking()) {
- stdin = new fs.ReadStream(null, {fd: fd});
- } else {
- stdin = new net.Stream(fd);
- stdin.readable = true;
+ startup.runEval = function() {
+ // -e, --eval
+ if (!process._eval) {
+ return;
}
- return stdin;
- });
+ var Module = NativeModule.require('module');
+ var rv = new Module()._compile('return eval(process._eval)', 'eval');
+ console.log(rv);
+ return true;
+ };
- process.openStdin = function() {
- process.stdin.resume();
- return process.stdin;
+ startup.runRepl = function() {
+ var Module = NativeModule.require('module');
+ // REPL
+ Module.requireRepl().start();
};
- // Lazy load console object
- global.__defineGetter__('console', function() {
- return NativeModule.require('console');
- });
+ // 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 Script = process.binding('evals').Script;
+ var runInThisContext = Script.runInThisContext;
- global.Buffer = NativeModule.require('buffer').Buffer;
+ function NativeModule(id) {
+ this.filename = id + '.js';
+ this.id = id;
+ this.exports = {};
+ this.loaded = false;
+ }
- process.exit = function(code) {
- process.emit('exit', code || 0);
- process.reallyExit(code || 0);
- };
+ NativeModule._source = process.binding('natives');
+ NativeModule._cache = {};
- process.kill = function(pid, sig) {
- sig = sig || 'SIGTERM';
- if (!lazyConstants()[sig]) throw new Error('Unknown signal: ' + sig);
- process._kill(pid, lazyConstants()[sig]);
- };
+ NativeModule.require = function(id) {
+ if (id == 'native_module') {
+ return NativeModule;
+ }
+ var cached = NativeModule.getCached(id);
+ if (cached) {
+ return cached.exports;
+ }
- var cwd = process.cwd();
- var path = NativeModule.require('path');
- var isWindows = process.platform === 'win32';
+ if (!NativeModule.exists(id)) {
+ throw new Error('No such native module ' + id);
+ }
- // Make process.argv[0] and process.argv[1] into full paths, but only
- // touch argv[0] if it's not a system $PATH lookup.
- // TODO: Make this work on Windows as well. Note that "node" might
- // execute cwd\node.exe, or some %PATH%\node.exe on Windows,
- // and that every directory has its own cwd, so d:node.exe is valid.
- var argv0 = process.argv[0];
- if (!isWindows && argv0.indexOf('/') !== -1 && argv0.charAt(0) !== '/') {
- process.argv[0] = path.join(cwd, process.argv[0]);
- }
+ var nativeModule = new NativeModule(id);
- // 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(function() {
- NativeModule.require('_third_party_main');
- });
- return;
- }
+ nativeModule.compile();
+ nativeModule.cache();
- if (process.argv[1]) {
- if (process.argv[1] == 'debug') {
- // Start the debugger agent
- var d = NativeModule.require('_debugger');
- d.start();
- return;
- }
+ return nativeModule.exports;
+ };
- // Load Module
- // make process.argv[1] into a full path
- if (!(/^http:\/\//).exec(process.argv[1])) {
- process.argv[1] = path.resolve(process.argv[1]);
- }
- // REMOVEME: nextTick should not be necessary. This hack to get
- // test/simple/test-exception-handler2.js working.
- process.nextTick(Module.runMain);
- return;
+ NativeModule.getCached = function(id) {
+ return NativeModule._cache[id];
}
- if (process._eval) {
- // -e, --eval
- var rv = new Module()._compile('return eval(process._eval)', 'eval');
- console.log(rv);
- return;
+ NativeModule.exists = function(id) {
+ return (id in NativeModule._source);
}
- // REPL
- Module.requireRepl().start();
+ 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, this.filename, true);
+ fn(this.exports, NativeModule.require, this, this.filename);
+
+ this.loaded = true;
+ };
+
+ NativeModule.prototype.cache = function() {
+ NativeModule._cache[this.id] = this;
+ };
+
+ startup();
});