fe2edabe830847fda0f5e7a28c80b0eba012a31d
[platform/upstream/nodejs.git] / src / node.js
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 // Hello, and welcome to hacking node.js!
23 //
24 // This file is invoked by node::Load in src/node.cc, and responsible for
25 // bootstrapping the node.js core. Special caution is given to the performance
26 // of the startup process, so many dependencies are invoked lazily.
27 (function(process) {
28   this.global = this;
29
30   function startup() {
31     var EventEmitter = NativeModule.require('events').EventEmitter;
32
33     process.__proto__ = Object.create(EventEmitter.prototype, {
34       constructor: {
35         value: process.constructor
36       }
37     });
38     EventEmitter.call(process);
39
40     process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated
41
42     // Setup the tracing module
43     NativeModule.require('tracing')._nodeInitialization(process);
44
45     // do this good and early, since it handles errors.
46     startup.processFatal();
47
48     startup.globalVariables();
49     startup.globalTimeouts();
50     startup.globalConsole();
51
52     startup.processAssert();
53     startup.processConfig();
54     startup.processNextTick();
55     startup.processStdio();
56     startup.processKillAndExit();
57     startup.processSignalHandlers();
58
59     // Do not initialize channel in debugger agent, it deletes env variable
60     // and the main thread won't see it.
61     if (process.argv[1] !== '--debug-agent')
62       startup.processChannel();
63
64     startup.processRawDebug();
65
66     startup.resolveArgv0();
67
68     // There are various modes that Node can run in. The most common two
69     // are running from a script and running the REPL - but there are a few
70     // others like the debugger or running --eval arguments. Here we decide
71     // which mode we run in.
72
73     if (NativeModule.exists('_third_party_main')) {
74       // To allow people to extend Node in different ways, this hook allows
75       // one to drop a file lib/_third_party_main.js into the build
76       // directory which will be executed instead of Node's normal loading.
77       process.nextTick(function() {
78         NativeModule.require('_third_party_main');
79       });
80
81     } else if (process.argv[1] == 'debug') {
82       // Start the debugger agent
83       var d = NativeModule.require('_debugger');
84       d.start();
85
86     } else if (process.argv[1] == '--debug-agent') {
87       // Start the debugger agent
88       var d = NativeModule.require('_debug_agent');
89       d.start();
90
91     } else if (process._eval != null) {
92       // User passed '-e' or '--eval' arguments to Node.
93       evalScript('[eval]');
94     } else if (process.argv[1]) {
95       // make process.argv[1] into a full path
96       var path = NativeModule.require('path');
97       process.argv[1] = path.resolve(process.argv[1]);
98
99       // If this is a worker in cluster mode, start up the communication
100       // channel.
101       if (process.env.NODE_UNIQUE_ID) {
102         var cluster = NativeModule.require('cluster');
103         cluster._setupWorker();
104
105         // Make sure it's not accidentally inherited by child processes.
106         delete process.env.NODE_UNIQUE_ID;
107       }
108
109       var Module = NativeModule.require('module');
110
111       if (global.v8debug &&
112           process.execArgv.some(function(arg) {
113             return arg.match(/^--debug-brk(=[0-9]*)?$/);
114           })) {
115
116         // XXX Fix this terrible hack!
117         //
118         // Give the client program a few ticks to connect.
119         // Otherwise, there's a race condition where `node debug foo.js`
120         // will not be able to connect in time to catch the first
121         // breakpoint message on line 1.
122         //
123         // A better fix would be to somehow get a message from the
124         // global.v8debug object about a connection, and runMain when
125         // that occurs.  --isaacs
126
127         var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50;
128         setTimeout(Module.runMain, debugTimeout);
129
130       } else {
131         // Main entry point into most programs:
132         Module.runMain();
133       }
134
135     } else {
136       var Module = NativeModule.require('module');
137
138       // If -i or --interactive were passed, or stdin is a TTY.
139       if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
140         // REPL
141         var opts = {
142           useGlobal: true,
143           ignoreUndefined: false
144         };
145         if (parseInt(process.env['NODE_NO_READLINE'], 10)) {
146           opts.terminal = false;
147         }
148         if (parseInt(process.env['NODE_DISABLE_COLORS'], 10)) {
149           opts.useColors = false;
150         }
151         var repl = Module.requireRepl().start(opts);
152         repl.on('exit', function() {
153           process.exit();
154         });
155
156       } else {
157         // Read all of stdin - execute it.
158         process.stdin.setEncoding('utf8');
159
160         var code = '';
161         process.stdin.on('data', function(d) {
162           code += d;
163         });
164
165         process.stdin.on('end', function() {
166           process._eval = code;
167           evalScript('[stdin]');
168         });
169       }
170     }
171   }
172
173   startup.globalVariables = function() {
174     global.process = process;
175     global.global = global;
176     global.GLOBAL = global;
177     global.root = global;
178     global.Buffer = NativeModule.require('buffer').Buffer;
179     process.domain = null;
180     process._exiting = false;
181   };
182
183   startup.globalTimeouts = function() {
184     global.setTimeout = function() {
185       var t = NativeModule.require('timers');
186       return t.setTimeout.apply(this, arguments);
187     };
188
189     global.setInterval = function() {
190       var t = NativeModule.require('timers');
191       return t.setInterval.apply(this, arguments);
192     };
193
194     global.clearTimeout = function() {
195       var t = NativeModule.require('timers');
196       return t.clearTimeout.apply(this, arguments);
197     };
198
199     global.clearInterval = function() {
200       var t = NativeModule.require('timers');
201       return t.clearInterval.apply(this, arguments);
202     };
203
204     global.setImmediate = function() {
205       var t = NativeModule.require('timers');
206       return t.setImmediate.apply(this, arguments);
207     };
208
209     global.clearImmediate = function() {
210       var t = NativeModule.require('timers');
211       return t.clearImmediate.apply(this, arguments);
212     };
213   };
214
215   startup.globalConsole = function() {
216     global.__defineGetter__('console', function() {
217       return NativeModule.require('console');
218     });
219   };
220
221
222   startup._lazyConstants = null;
223
224   startup.lazyConstants = function() {
225     if (!startup._lazyConstants) {
226       startup._lazyConstants = process.binding('constants');
227     }
228     return startup._lazyConstants;
229   };
230
231   startup.processFatal = function() {
232     var tracing = NativeModule.require('tracing');
233     var _errorHandler = tracing._errorHandler;
234     // Cleanup
235     delete tracing._errorHandler;
236
237     process._fatalException = function(er) {
238       // First run through error handlers from asyncListener.
239       var caught = _errorHandler(er);
240
241       if (process.domain && process.domain._errorHandler)
242         caught = process.domain._errorHandler(er) || caught;
243
244       if (!caught)
245         caught = process.emit('uncaughtException', er);
246
247       // If someone handled it, then great.  otherwise, die in C++ land
248       // since that means that we'll exit the process, emit the 'exit' event
249       if (!caught) {
250         try {
251           if (!process._exiting) {
252             process._exiting = true;
253             process.emit('exit', 1);
254           }
255         } catch (er) {
256           // nothing to be done about it at this point.
257         }
258
259       // if we handled an error, then make sure any ticks get processed
260       } else {
261         var t = setImmediate(process._tickCallback);
262         // Complete hack to make sure any errors thrown from async
263         // listeners don't cause an infinite loop.
264         if (t._asyncQueue)
265           t._asyncQueue = [];
266       }
267
268       return caught;
269     };
270   };
271
272   var assert;
273   startup.processAssert = function() {
274     assert = process.assert = function(x, msg) {
275       if (!x) throw new Error(msg || 'assertion error');
276     };
277   };
278
279   startup.processConfig = function() {
280     // used for `process.config`, but not a real module
281     var config = NativeModule._source.config;
282     delete NativeModule._source.config;
283
284     // strip the gyp comment line at the beginning
285     config = config.split('\n')
286                    .slice(1)
287                    .join('\n')
288                    .replace(/"/g, '\\"')
289                    .replace(/'/g, '"');
290
291     process.config = JSON.parse(config, function(key, value) {
292       if (value === 'true') return true;
293       if (value === 'false') return false;
294       return value;
295     });
296   };
297
298   startup.processNextTick = function() {
299     var tracing = NativeModule.require('tracing');
300     var nextTickQueue = [];
301     var asyncFlags = tracing._asyncFlags;
302     var _runAsyncQueue = tracing._runAsyncQueue;
303     var _loadAsyncQueue = tracing._loadAsyncQueue;
304     var _unloadAsyncQueue = tracing._unloadAsyncQueue;
305     var microtasksScheduled = false;
306
307     // Used to run V8's micro task queue.
308     var _runMicrotasks = {};
309
310     // This tickInfo thing is used so that the C++ code in src/node.cc
311     // can have easy accesss to our nextTick state, and avoid unnecessary
312     var tickInfo = {};
313
314     // *Must* match Environment::TickInfo::Fields in src/env.h.
315     var kIndex = 0;
316     var kLength = 1;
317
318     // For asyncFlags.
319     // *Must* match Environment::AsyncListeners::Fields in src/env.h
320     var kCount = 0;
321
322     process.nextTick = nextTick;
323     // Needs to be accessible from beyond this scope.
324     process._tickCallback = _tickCallback;
325     process._tickDomainCallback = _tickDomainCallback;
326
327     process._setupNextTick(tickInfo, _tickCallback, _runMicrotasks);
328
329     _runMicrotasks = _runMicrotasks.runMicrotasks;
330
331     function tickDone() {
332       if (tickInfo[kLength] !== 0) {
333         if (tickInfo[kLength] <= tickInfo[kIndex]) {
334           nextTickQueue = [];
335           tickInfo[kLength] = 0;
336         } else {
337           nextTickQueue.splice(0, tickInfo[kIndex]);
338           tickInfo[kLength] = nextTickQueue.length;
339         }
340       }
341       tickInfo[kIndex] = 0;
342     }
343
344     function scheduleMicrotasks() {
345       if (microtasksScheduled)
346         return;
347
348       nextTickQueue.push({
349         callback: runMicrotasksCallback,
350         domain: null
351       });
352
353       tickInfo[kLength]++;
354       microtasksScheduled = true;
355     }
356
357     function runMicrotasksCallback() {
358       microtasksScheduled = false;
359       _runMicrotasks();
360
361       if (tickInfo[kIndex] < tickInfo[kLength])
362         scheduleMicrotasks();
363     }
364
365     // Run callbacks that have no domain.
366     // Using domains will cause this to be overridden.
367     function _tickCallback() {
368       var callback, hasQueue, threw, tock;
369
370       scheduleMicrotasks();
371
372       while (tickInfo[kIndex] < tickInfo[kLength]) {
373         tock = nextTickQueue[tickInfo[kIndex]++];
374         callback = tock.callback;
375         threw = true;
376         hasQueue = !!tock._asyncQueue;
377         if (hasQueue)
378           _loadAsyncQueue(tock);
379         try {
380           callback();
381           threw = false;
382         } finally {
383           if (threw)
384             tickDone();
385         }
386         if (hasQueue)
387           _unloadAsyncQueue(tock);
388         if (1e4 < tickInfo[kIndex])
389           tickDone();
390       }
391
392       tickDone();
393     }
394
395     function _tickDomainCallback() {
396       var callback, domain, hasQueue, threw, tock;
397
398       scheduleMicrotasks();
399
400       while (tickInfo[kIndex] < tickInfo[kLength]) {
401         tock = nextTickQueue[tickInfo[kIndex]++];
402         callback = tock.callback;
403         domain = tock.domain;
404         hasQueue = !!tock._asyncQueue;
405         if (hasQueue)
406           _loadAsyncQueue(tock);
407         if (domain)
408           domain.enter();
409         threw = true;
410         try {
411           callback();
412           threw = false;
413         } finally {
414           if (threw)
415             tickDone();
416         }
417         if (hasQueue)
418           _unloadAsyncQueue(tock);
419         if (1e4 < tickInfo[kIndex])
420           tickDone();
421         if (domain)
422           domain.exit();
423       }
424
425       tickDone();
426     }
427
428     function nextTick(callback) {
429       // on the way out, don't bother. it won't get fired anyway.
430       if (process._exiting)
431         return;
432
433       var obj = {
434         callback: callback,
435         domain: process.domain || null,
436         _asyncQueue: undefined
437       };
438
439       if (asyncFlags[kCount] > 0)
440         _runAsyncQueue(obj);
441
442       nextTickQueue.push(obj);
443       tickInfo[kLength]++;
444     }
445   };
446
447   function evalScript(name) {
448     var Module = NativeModule.require('module');
449     var path = NativeModule.require('path');
450     var cwd = process.cwd();
451
452     var module = new Module(name);
453     module.filename = path.join(cwd, name);
454     module.paths = Module._nodeModulePaths(cwd);
455     var script = process._eval;
456     if (!Module._contextLoad) {
457       var body = script;
458       script = 'global.__filename = ' + JSON.stringify(name) + ';\n' +
459                'global.exports = exports;\n' +
460                'global.module = module;\n' +
461                'global.__dirname = __dirname;\n' +
462                'global.require = require;\n' +
463                'return require("vm").runInThisContext(' +
464                JSON.stringify(body) + ', { filename: ' +
465                JSON.stringify(name) + ' });\n';
466     }
467     var result = module._compile(script, name + '-wrapper');
468     if (process._print_eval) console.log(result);
469   }
470
471   function createWritableStdioStream(fd) {
472     var stream;
473     var tty_wrap = process.binding('tty_wrap');
474
475     // Note stream._type is used for test-module-load-list.js
476
477     switch (tty_wrap.guessHandleType(fd)) {
478       case 'TTY':
479         var tty = NativeModule.require('tty');
480         stream = new tty.WriteStream(fd);
481         stream._type = 'tty';
482
483         // Hack to have stream not keep the event loop alive.
484         // See https://github.com/joyent/node/issues/1726
485         if (stream._handle && stream._handle.unref) {
486           stream._handle.unref();
487         }
488         break;
489
490       case 'FILE':
491         var fs = NativeModule.require('fs');
492         stream = new fs.SyncWriteStream(fd, { autoClose: false });
493         stream._type = 'fs';
494         break;
495
496       case 'PIPE':
497       case 'TCP':
498         var net = NativeModule.require('net');
499         stream = new net.Socket({
500           fd: fd,
501           readable: false,
502           writable: true
503         });
504
505         // FIXME Should probably have an option in net.Socket to create a
506         // stream from an existing fd which is writable only. But for now
507         // we'll just add this hack and set the `readable` member to false.
508         // Test: ./node test/fixtures/echo.js < /etc/passwd
509         stream.readable = false;
510         stream.read = null;
511         stream._type = 'pipe';
512
513         // FIXME Hack to have stream not keep the event loop alive.
514         // See https://github.com/joyent/node/issues/1726
515         if (stream._handle && stream._handle.unref) {
516           stream._handle.unref();
517         }
518         break;
519
520       default:
521         // Probably an error on in uv_guess_handle()
522         throw new Error('Implement me. Unknown stream file type!');
523     }
524
525     // For supporting legacy API we put the FD here.
526     stream.fd = fd;
527
528     stream._isStdio = true;
529
530     return stream;
531   }
532
533   startup.processStdio = function() {
534     var stdin, stdout, stderr;
535
536     process.__defineGetter__('stdout', function() {
537       if (stdout) return stdout;
538       stdout = createWritableStdioStream(1);
539       stdout.destroy = stdout.destroySoon = function(er) {
540         er = er || new Error('process.stdout cannot be closed.');
541         stdout.emit('error', er);
542       };
543       if (stdout.isTTY) {
544         process.on('SIGWINCH', function() {
545           stdout._refreshSize();
546         });
547       }
548       return stdout;
549     });
550
551     process.__defineGetter__('stderr', function() {
552       if (stderr) return stderr;
553       stderr = createWritableStdioStream(2);
554       stderr.destroy = stderr.destroySoon = function(er) {
555         er = er || new Error('process.stderr cannot be closed.');
556         stderr.emit('error', er);
557       };
558       return stderr;
559     });
560
561     process.__defineGetter__('stdin', function() {
562       if (stdin) return stdin;
563
564       var tty_wrap = process.binding('tty_wrap');
565       var fd = 0;
566
567       switch (tty_wrap.guessHandleType(fd)) {
568         case 'TTY':
569           var tty = NativeModule.require('tty');
570           stdin = new tty.ReadStream(fd, {
571             highWaterMark: 0,
572             readable: true,
573             writable: false
574           });
575           break;
576
577         case 'FILE':
578           var fs = NativeModule.require('fs');
579           stdin = new fs.ReadStream(null, { fd: fd, autoClose: false });
580           break;
581
582         case 'PIPE':
583         case 'TCP':
584           var net = NativeModule.require('net');
585
586           // It could be that process has been started with an IPC channel
587           // sitting on fd=0, in such case the pipe for this fd is already
588           // present and creating a new one will lead to the assertion failure
589           // in libuv.
590           if (process._channel && process._channel.fd === fd) {
591             stdin = new net.Socket({
592               handle: process._channel,
593               readable: true,
594               writable: false
595             });
596           } else {
597             stdin = new net.Socket({
598               fd: fd,
599               readable: true,
600               writable: false
601             });
602           }
603           break;
604
605         default:
606           // Probably an error on in uv_guess_handle()
607           throw new Error('Implement me. Unknown stdin file type!');
608       }
609
610       // For supporting legacy API we put the FD here.
611       stdin.fd = fd;
612
613       // stdin starts out life in a paused state, but node doesn't
614       // know yet.  Explicitly to readStop() it to put it in the
615       // not-reading state.
616       if (stdin._handle && stdin._handle.readStop) {
617         stdin._handle.reading = false;
618         stdin._readableState.reading = false;
619         stdin._handle.readStop();
620       }
621
622       // if the user calls stdin.pause(), then we need to stop reading
623       // immediately, so that the process can close down.
624       stdin.on('pause', function() {
625         if (!stdin._handle)
626           return;
627         stdin._readableState.reading = false;
628         stdin._handle.reading = false;
629         stdin._handle.readStop();
630       });
631
632       return stdin;
633     });
634
635     process.openStdin = function() {
636       process.stdin.resume();
637       return process.stdin;
638     };
639   };
640
641   startup.processKillAndExit = function() {
642
643     process.exit = function(code) {
644       if (code || code === 0)
645         process.exitCode = code;
646
647       if (!process._exiting) {
648         process._exiting = true;
649         process.emit('exit', process.exitCode || 0);
650       }
651       process.reallyExit(process.exitCode || 0);
652     };
653
654     process.kill = function(pid, sig) {
655       var err;
656
657       if (typeof pid !== 'number' || !isFinite(pid)) {
658         throw new TypeError('pid must be a number');
659       }
660
661       // preserve null signal
662       if (0 === sig) {
663         err = process._kill(pid, 0);
664       } else {
665         sig = sig || 'SIGTERM';
666         if (startup.lazyConstants()[sig] &&
667             sig.slice(0, 3) === 'SIG') {
668           err = process._kill(pid, startup.lazyConstants()[sig]);
669         } else {
670           throw new Error('Unknown signal: ' + sig);
671         }
672       }
673
674       if (err) {
675         var errnoException = NativeModule.require('util')._errnoException;
676         throw errnoException(err, 'kill');
677       }
678
679       return true;
680     };
681   };
682
683   startup.processSignalHandlers = function() {
684     // Load events module in order to access prototype elements on process like
685     // process.addListener.
686     var signalWraps = {};
687     var addListener = process.addListener;
688     var removeListener = process.removeListener;
689
690     function isSignal(event) {
691       return event.slice(0, 3) === 'SIG' &&
692              startup.lazyConstants().hasOwnProperty(event);
693     }
694
695     // Wrap addListener for the special signal types
696     process.on = process.addListener = function(type, listener) {
697       if (isSignal(type) &&
698           !signalWraps.hasOwnProperty(type)) {
699         var Signal = process.binding('signal_wrap').Signal;
700         var wrap = new Signal();
701
702         wrap.unref();
703
704         wrap.onsignal = function() { process.emit(type); };
705
706         var signum = startup.lazyConstants()[type];
707         var err = wrap.start(signum);
708         if (err) {
709           wrap.close();
710           var errnoException = NativeModule.require('util')._errnoException;
711           throw errnoException(err, 'uv_signal_start');
712         }
713
714         signalWraps[type] = wrap;
715       }
716
717       return addListener.apply(this, arguments);
718     };
719
720     process.removeListener = function(type, listener) {
721       var ret = removeListener.apply(this, arguments);
722       if (isSignal(type)) {
723         assert(signalWraps.hasOwnProperty(type));
724
725         if (NativeModule.require('events').listenerCount(this, type) === 0) {
726           signalWraps[type].close();
727           delete signalWraps[type];
728         }
729       }
730
731       return ret;
732     };
733   };
734
735
736   startup.processChannel = function() {
737     // If we were spawned with env NODE_CHANNEL_FD then load that up and
738     // start parsing data from that stream.
739     if (process.env.NODE_CHANNEL_FD) {
740       var fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
741       assert(fd >= 0);
742
743       // Make sure it's not accidentally inherited by child processes.
744       delete process.env.NODE_CHANNEL_FD;
745
746       var cp = NativeModule.require('child_process');
747
748       // Load tcp_wrap to avoid situation where we might immediately receive
749       // a message.
750       // FIXME is this really necessary?
751       process.binding('tcp_wrap');
752
753       cp._forkChild(fd);
754       assert(process.send);
755     }
756   };
757
758
759   startup.processRawDebug = function() {
760     var format = NativeModule.require('util').format;
761     var rawDebug = process._rawDebug;
762     process._rawDebug = function() {
763       rawDebug(format.apply(null, arguments));
764     };
765   };
766
767
768   startup.resolveArgv0 = function() {
769     var cwd = process.cwd();
770     var isWindows = process.platform === 'win32';
771
772     // Make process.argv[0] into a full path, but only touch argv[0] if it's
773     // not a system $PATH lookup.
774     // TODO: Make this work on Windows as well.  Note that "node" might
775     // execute cwd\node.exe, or some %PATH%\node.exe on Windows,
776     // and that every directory has its own cwd, so d:node.exe is valid.
777     var argv0 = process.argv[0];
778     if (!isWindows && argv0.indexOf('/') !== -1 && argv0.charAt(0) !== '/') {
779       var path = NativeModule.require('path');
780       process.argv[0] = path.join(cwd, process.argv[0]);
781     }
782   };
783
784   // Below you find a minimal module system, which is used to load the node
785   // core modules found in lib/*.js. All core modules are compiled into the
786   // node binary, so they can be loaded faster.
787
788   var ContextifyScript = process.binding('contextify').ContextifyScript;
789   function runInThisContext(code, options) {
790     var script = new ContextifyScript(code, options);
791     return script.runInThisContext();
792   }
793
794   function NativeModule(id) {
795     this.filename = id + '.js';
796     this.id = id;
797     this.exports = {};
798     this.loaded = false;
799   }
800
801   NativeModule._source = process.binding('natives');
802   NativeModule._cache = {};
803
804   NativeModule.require = function(id) {
805     if (id == 'native_module') {
806       return NativeModule;
807     }
808
809     var cached = NativeModule.getCached(id);
810     if (cached) {
811       return cached.exports;
812     }
813
814     if (!NativeModule.exists(id)) {
815       throw new Error('No such native module ' + id);
816     }
817
818     process.moduleLoadList.push('NativeModule ' + id);
819
820     var nativeModule = new NativeModule(id);
821
822     nativeModule.cache();
823     nativeModule.compile();
824
825     return nativeModule.exports;
826   };
827
828   NativeModule.getCached = function(id) {
829     return NativeModule._cache[id];
830   }
831
832   NativeModule.exists = function(id) {
833     return NativeModule._source.hasOwnProperty(id);
834   }
835
836   NativeModule.getSource = function(id) {
837     return NativeModule._source[id];
838   }
839
840   NativeModule.wrap = function(script) {
841     return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
842   };
843
844   NativeModule.wrapper = [
845     '(function (exports, require, module, __filename, __dirname) { ',
846     '\n});'
847   ];
848
849   NativeModule.prototype.compile = function() {
850     var source = NativeModule.getSource(this.id);
851     source = NativeModule.wrap(source);
852
853     var fn = runInThisContext(source, { filename: this.filename });
854     fn(this.exports, NativeModule.require, this, this.filename);
855
856     this.loaded = true;
857   };
858
859   NativeModule.prototype.cache = function() {
860     NativeModule._cache[this.id] = this;
861   };
862
863   startup();
864 });