a5a26e96eae252c33e07a919eeaa9a50a4a3f11b
[platform/upstream/nodejs.git] / src / node.js
1 // Hello, and welcome to hacking node.js!
2 //
3 // This file is invoked by node::Load in src/node.cc, and responsible for
4 // bootstrapping the node.js core. Special caution is given to the performance
5 // of the startup process, so many dependencies are invoked lazily.
6
7 'use strict';
8
9 (function(process) {
10   this.global = this;
11
12   function startup() {
13     var EventEmitter = NativeModule.require('events').EventEmitter;
14
15     process.__proto__ = Object.create(EventEmitter.prototype, {
16       constructor: {
17         value: process.constructor
18       }
19     });
20     EventEmitter.call(process);
21
22     process.EventEmitter = EventEmitter; // process.EventEmitter is deprecated
23
24     // do this good and early, since it handles errors.
25     startup.processFatal();
26
27     startup.globalVariables();
28     startup.globalTimeouts();
29     startup.globalConsole();
30
31     startup.processAssert();
32     startup.processConfig();
33     startup.processNextTick();
34     startup.processPromises();
35     startup.processStdio();
36     startup.processKillAndExit();
37     startup.processSignalHandlers();
38
39     // Do not initialize channel in debugger agent, it deletes env variable
40     // and the main thread won't see it.
41     if (process.argv[1] !== '--debug-agent')
42       startup.processChannel();
43
44     startup.processRawDebug();
45
46     startup.resolveArgv0();
47
48     // There are various modes that Node can run in. The most common two
49     // are running from a script and running the REPL - but there are a few
50     // others like the debugger or running --eval arguments. Here we decide
51     // which mode we run in.
52
53     if (NativeModule.exists('_third_party_main')) {
54       // To allow people to extend Node in different ways, this hook allows
55       // one to drop a file lib/_third_party_main.js into the build
56       // directory which will be executed instead of Node's normal loading.
57       process.nextTick(function() {
58         NativeModule.require('_third_party_main');
59       });
60
61     } else if (process.argv[1] == 'debug') {
62       // Start the debugger agent
63       var d = NativeModule.require('_debugger');
64       d.start();
65
66     } else if (process.argv[1] == '--debug-agent') {
67       // Start the debugger agent
68       var d = NativeModule.require('_debug_agent');
69       d.start();
70
71     } else if (process._eval != null) {
72       // User passed '-e' or '--eval' arguments to Node.
73       evalScript('[eval]');
74     } else if (process.argv[1]) {
75       // make process.argv[1] into a full path
76       var path = NativeModule.require('path');
77       process.argv[1] = path.resolve(process.argv[1]);
78
79       // If this is a worker in cluster mode, start up the communication
80       // channel.
81       if (process.env.NODE_UNIQUE_ID) {
82         var cluster = NativeModule.require('cluster');
83         cluster._setupWorker();
84
85         // Make sure it's not accidentally inherited by child processes.
86         delete process.env.NODE_UNIQUE_ID;
87       }
88
89       var Module = NativeModule.require('module');
90
91       if (global.v8debug &&
92           process.execArgv.some(function(arg) {
93             return arg.match(/^--debug-brk(=[0-9]*)?$/);
94           })) {
95
96         // XXX Fix this terrible hack!
97         //
98         // Give the client program a few ticks to connect.
99         // Otherwise, there's a race condition where `node debug foo.js`
100         // will not be able to connect in time to catch the first
101         // breakpoint message on line 1.
102         //
103         // A better fix would be to somehow get a message from the
104         // global.v8debug object about a connection, and runMain when
105         // that occurs.  --isaacs
106
107         var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50;
108         setTimeout(Module.runMain, debugTimeout);
109
110       } else {
111         // Main entry point into most programs:
112         Module.runMain();
113       }
114
115     } else {
116       var Module = NativeModule.require('module');
117
118       // If -i or --interactive were passed, or stdin is a TTY.
119       if (process._forceRepl || NativeModule.require('tty').isatty(0)) {
120         // REPL
121         var opts = {
122           useGlobal: true,
123           ignoreUndefined: false
124         };
125         if (parseInt(process.env['NODE_NO_READLINE'], 10)) {
126           opts.terminal = false;
127         }
128         if (parseInt(process.env['NODE_DISABLE_COLORS'], 10)) {
129           opts.useColors = false;
130         }
131         var repl = Module.requireRepl().start(opts);
132         repl.on('exit', function() {
133           process.exit();
134         });
135
136       } else {
137         // Read all of stdin - execute it.
138         process.stdin.setEncoding('utf8');
139
140         var code = '';
141         process.stdin.on('data', function(d) {
142           code += d;
143         });
144
145         process.stdin.on('end', function() {
146           process._eval = code;
147           evalScript('[stdin]');
148         });
149       }
150     }
151   }
152
153   startup.globalVariables = function() {
154     global.process = process;
155     global.global = global;
156     global.GLOBAL = global;
157     global.root = global;
158     global.Buffer = NativeModule.require('buffer').Buffer;
159     process.domain = null;
160     process._exiting = false;
161   };
162
163   startup.globalTimeouts = function() {
164     global.setTimeout = function() {
165       var t = NativeModule.require('timers');
166       return t.setTimeout.apply(this, arguments);
167     };
168
169     global.setInterval = function() {
170       var t = NativeModule.require('timers');
171       return t.setInterval.apply(this, arguments);
172     };
173
174     global.clearTimeout = function() {
175       var t = NativeModule.require('timers');
176       return t.clearTimeout.apply(this, arguments);
177     };
178
179     global.clearInterval = function() {
180       var t = NativeModule.require('timers');
181       return t.clearInterval.apply(this, arguments);
182     };
183
184     global.setImmediate = function() {
185       var t = NativeModule.require('timers');
186       return t.setImmediate.apply(this, arguments);
187     };
188
189     global.clearImmediate = function() {
190       var t = NativeModule.require('timers');
191       return t.clearImmediate.apply(this, arguments);
192     };
193   };
194
195   startup.globalConsole = function() {
196     global.__defineGetter__('console', function() {
197       return NativeModule.require('console');
198     });
199   };
200
201
202   startup._lazyConstants = null;
203
204   startup.lazyConstants = function() {
205     if (!startup._lazyConstants) {
206       startup._lazyConstants = process.binding('constants');
207     }
208     return startup._lazyConstants;
209   };
210
211   startup.processFatal = function() {
212     process._makeCallbackAbortOnUncaught = function() {
213       try {
214         return this[1].apply(this[0], arguments);
215       } catch (err) {
216         process._fatalException(err);
217       }
218     };
219
220     process._fatalException = function(er) {
221       var caught;
222
223       if (process.domain && process.domain._errorHandler)
224         caught = process.domain._errorHandler(er) || caught;
225
226       if (!caught)
227         caught = process.emit('uncaughtException', er);
228
229       // If someone handled it, then great.  otherwise, die in C++ land
230       // since that means that we'll exit the process, emit the 'exit' event
231       if (!caught) {
232         try {
233           if (!process._exiting) {
234             process._exiting = true;
235             process.emit('exit', 1);
236           }
237         } catch (er) {
238           // nothing to be done about it at this point.
239         }
240
241       // if we handled an error, then make sure any ticks get processed
242       } else {
243         NativeModule.require('timers').setImmediate(process._tickCallback);
244       }
245
246       return caught;
247     };
248   };
249
250   var assert;
251   startup.processAssert = function() {
252     assert = process.assert = function(x, msg) {
253       if (!x) throw new Error(msg || 'assertion error');
254     };
255   };
256
257   startup.processConfig = function() {
258     // used for `process.config`, but not a real module
259     var config = NativeModule._source.config;
260     delete NativeModule._source.config;
261
262     // strip the gyp comment line at the beginning
263     config = config.split('\n')
264         .slice(1)
265         .join('\n')
266         .replace(/"/g, '\\"')
267         .replace(/'/g, '"');
268
269     process.config = JSON.parse(config, function(key, value) {
270       if (value === 'true') return true;
271       if (value === 'false') return false;
272       return value;
273     });
274   };
275
276   var addPendingUnhandledRejection;
277   var hasBeenNotifiedProperty = new WeakMap();
278   startup.processNextTick = function() {
279     var nextTickQueue = [];
280     var pendingUnhandledRejections = [];
281     var microtasksScheduled = false;
282
283     // Used to run V8's micro task queue.
284     var _runMicrotasks = {};
285
286     // This tickInfo thing is used so that the C++ code in src/node.cc
287     // can have easy accesss to our nextTick state, and avoid unnecessary
288     var tickInfo = {};
289
290     // *Must* match Environment::TickInfo::Fields in src/env.h.
291     var kIndex = 0;
292     var kLength = 1;
293
294     process.nextTick = nextTick;
295     // Needs to be accessible from beyond this scope.
296     process._tickCallback = _tickCallback;
297     process._tickDomainCallback = _tickDomainCallback;
298
299     process._setupNextTick(tickInfo, _tickCallback, _runMicrotasks);
300
301     _runMicrotasks = _runMicrotasks.runMicrotasks;
302
303     function tickDone() {
304       if (tickInfo[kLength] !== 0) {
305         if (tickInfo[kLength] <= tickInfo[kIndex]) {
306           nextTickQueue = [];
307           tickInfo[kLength] = 0;
308         } else {
309           nextTickQueue.splice(0, tickInfo[kIndex]);
310           tickInfo[kLength] = nextTickQueue.length;
311         }
312       }
313       tickInfo[kIndex] = 0;
314     }
315
316     function scheduleMicrotasks() {
317       if (microtasksScheduled)
318         return;
319
320       nextTickQueue.push({
321         callback: runMicrotasksCallback,
322         domain: null
323       });
324
325       tickInfo[kLength]++;
326       microtasksScheduled = true;
327     }
328
329     function runMicrotasksCallback() {
330       microtasksScheduled = false;
331       _runMicrotasks();
332
333       if (tickInfo[kIndex] < tickInfo[kLength] ||
334           emitPendingUnhandledRejections())
335         scheduleMicrotasks();
336     }
337
338     // Run callbacks that have no domain.
339     // Using domains will cause this to be overridden.
340     function _tickCallback() {
341       var callback, threw, tock;
342
343       scheduleMicrotasks();
344
345       while (tickInfo[kIndex] < tickInfo[kLength]) {
346         tock = nextTickQueue[tickInfo[kIndex]++];
347         callback = tock.callback;
348         threw = true;
349         try {
350           callback();
351           threw = false;
352         } finally {
353           if (threw)
354             tickDone();
355         }
356         if (1e4 < tickInfo[kIndex])
357           tickDone();
358       }
359
360       tickDone();
361     }
362
363     function _tickDomainCallback() {
364       var callback, domain, threw, tock;
365
366       scheduleMicrotasks();
367
368       while (tickInfo[kIndex] < tickInfo[kLength]) {
369         tock = nextTickQueue[tickInfo[kIndex]++];
370         callback = tock.callback;
371         domain = tock.domain;
372         if (domain)
373           domain.enter();
374         threw = true;
375         try {
376           callback();
377           threw = false;
378         } finally {
379           if (threw)
380             tickDone();
381         }
382         if (1e4 < tickInfo[kIndex])
383           tickDone();
384         if (domain)
385           domain.exit();
386       }
387
388       tickDone();
389     }
390
391     function nextTick(callback) {
392       // on the way out, don't bother. it won't get fired anyway.
393       if (process._exiting)
394         return;
395
396       var obj = {
397         callback: callback,
398         domain: process.domain || null
399       };
400
401       nextTickQueue.push(obj);
402       tickInfo[kLength]++;
403     }
404
405     function emitPendingUnhandledRejections() {
406       var hadListeners = false;
407       while (pendingUnhandledRejections.length > 0) {
408         var promise = pendingUnhandledRejections.shift();
409         var reason = pendingUnhandledRejections.shift();
410         if (hasBeenNotifiedProperty.get(promise) === false) {
411           hasBeenNotifiedProperty.set(promise, true);
412           if (!process.emit('unhandledRejection', reason, promise)) {
413             // Nobody is listening.
414             // TODO(petkaantonov) Take some default action, see #830
415           } else
416             hadListeners = true;
417         }
418       }
419       return hadListeners;
420     }
421
422     addPendingUnhandledRejection = function(promise, reason) {
423       pendingUnhandledRejections.push(promise, reason);
424       scheduleMicrotasks();
425     };
426   };
427
428   startup.processPromises = function() {
429     var promiseRejectEvent = process._promiseRejectEvent;
430
431     function unhandledRejection(promise, reason) {
432       hasBeenNotifiedProperty.set(promise, false);
433       addPendingUnhandledRejection(promise, reason);
434     }
435
436     function rejectionHandled(promise) {
437       var hasBeenNotified = hasBeenNotifiedProperty.get(promise);
438       if (hasBeenNotified !== undefined) {
439         hasBeenNotifiedProperty.delete(promise);
440         if (hasBeenNotified === true)
441           process.emit('rejectionHandled', promise);
442       }
443     }
444
445     process._setupPromises(function(event, promise, reason) {
446       if (event === promiseRejectEvent.unhandled)
447         unhandledRejection(promise, reason);
448       else if (event === promiseRejectEvent.handled)
449         process.nextTick(function() {
450           rejectionHandled(promise);
451         });
452       else
453         NativeModule.require('assert').fail('unexpected PromiseRejectEvent');
454     });
455   };
456
457   function evalScript(name) {
458     var Module = NativeModule.require('module');
459     var path = NativeModule.require('path');
460     var cwd = process.cwd();
461
462     var module = new Module(name);
463     module.filename = path.join(cwd, name);
464     module.paths = Module._nodeModulePaths(cwd);
465     var script = process._eval;
466     if (!Module._contextLoad) {
467       var body = script;
468       script = 'global.__filename = ' + JSON.stringify(name) + ';\n' +
469                'global.exports = exports;\n' +
470                'global.module = module;\n' +
471                'global.__dirname = __dirname;\n' +
472                'global.require = require;\n' +
473                'return require("vm").runInThisContext(' +
474                JSON.stringify(body) + ', { filename: ' +
475                JSON.stringify(name) + ' });\n';
476     }
477     var result = module._compile(script, name + '-wrapper');
478     if (process._print_eval) console.log(result);
479   }
480
481   function createWritableStdioStream(fd) {
482     var stream;
483     var tty_wrap = process.binding('tty_wrap');
484
485     // Note stream._type is used for test-module-load-list.js
486
487     switch (tty_wrap.guessHandleType(fd)) {
488       case 'TTY':
489         var tty = NativeModule.require('tty');
490         stream = new tty.WriteStream(fd);
491         stream._type = 'tty';
492
493         // Hack to have stream not keep the event loop alive.
494         // See https://github.com/joyent/node/issues/1726
495         if (stream._handle && stream._handle.unref) {
496           stream._handle.unref();
497         }
498         break;
499
500       case 'FILE':
501         var fs = NativeModule.require('fs');
502         stream = new fs.SyncWriteStream(fd, { autoClose: false });
503         stream._type = 'fs';
504         break;
505
506       case 'PIPE':
507       case 'TCP':
508         var net = NativeModule.require('net');
509         stream = new net.Socket({
510           fd: fd,
511           readable: false,
512           writable: true
513         });
514
515         // FIXME Should probably have an option in net.Socket to create a
516         // stream from an existing fd which is writable only. But for now
517         // we'll just add this hack and set the `readable` member to false.
518         // Test: ./node test/fixtures/echo.js < /etc/passwd
519         stream.readable = false;
520         stream.read = null;
521         stream._type = 'pipe';
522
523         // FIXME Hack to have stream not keep the event loop alive.
524         // See https://github.com/joyent/node/issues/1726
525         if (stream._handle && stream._handle.unref) {
526           stream._handle.unref();
527         }
528         break;
529
530       default:
531         // Probably an error on in uv_guess_handle()
532         throw new Error('Implement me. Unknown stream file type!');
533     }
534
535     // For supporting legacy API we put the FD here.
536     stream.fd = fd;
537
538     stream._isStdio = true;
539
540     return stream;
541   }
542
543   startup.processStdio = function() {
544     var stdin, stdout, stderr;
545
546     process.__defineGetter__('stdout', function() {
547       if (stdout) return stdout;
548       stdout = createWritableStdioStream(1);
549       stdout.destroy = stdout.destroySoon = function(er) {
550         er = er || new Error('process.stdout cannot be closed.');
551         stdout.emit('error', er);
552       };
553       if (stdout.isTTY) {
554         process.on('SIGWINCH', function() {
555           stdout._refreshSize();
556         });
557       }
558       return stdout;
559     });
560
561     process.__defineGetter__('stderr', function() {
562       if (stderr) return stderr;
563       stderr = createWritableStdioStream(2);
564       stderr.destroy = stderr.destroySoon = function(er) {
565         er = er || new Error('process.stderr cannot be closed.');
566         stderr.emit('error', er);
567       };
568       return stderr;
569     });
570
571     process.__defineGetter__('stdin', function() {
572       if (stdin) return stdin;
573
574       var tty_wrap = process.binding('tty_wrap');
575       var fd = 0;
576
577       switch (tty_wrap.guessHandleType(fd)) {
578         case 'TTY':
579           var tty = NativeModule.require('tty');
580           stdin = new tty.ReadStream(fd, {
581             highWaterMark: 0,
582             readable: true,
583             writable: false
584           });
585           break;
586
587         case 'FILE':
588           var fs = NativeModule.require('fs');
589           stdin = new fs.ReadStream(null, { fd: fd, autoClose: false });
590           break;
591
592         case 'PIPE':
593         case 'TCP':
594           var net = NativeModule.require('net');
595
596           // It could be that process has been started with an IPC channel
597           // sitting on fd=0, in such case the pipe for this fd is already
598           // present and creating a new one will lead to the assertion failure
599           // in libuv.
600           if (process._channel && process._channel.fd === fd) {
601             stdin = new net.Socket({
602               handle: process._channel,
603               readable: true,
604               writable: false
605             });
606           } else {
607             stdin = new net.Socket({
608               fd: fd,
609               readable: true,
610               writable: false
611             });
612           }
613           break;
614
615         default:
616           // Probably an error on in uv_guess_handle()
617           throw new Error('Implement me. Unknown stdin file type!');
618       }
619
620       // For supporting legacy API we put the FD here.
621       stdin.fd = fd;
622
623       // stdin starts out life in a paused state, but node doesn't
624       // know yet.  Explicitly to readStop() it to put it in the
625       // not-reading state.
626       if (stdin._handle && stdin._handle.readStop) {
627         stdin._handle.reading = false;
628         stdin._readableState.reading = false;
629         stdin._handle.readStop();
630       }
631
632       // if the user calls stdin.pause(), then we need to stop reading
633       // immediately, so that the process can close down.
634       stdin.on('pause', function() {
635         if (!stdin._handle)
636           return;
637         stdin._readableState.reading = false;
638         stdin._handle.reading = false;
639         stdin._handle.readStop();
640       });
641
642       return stdin;
643     });
644
645     process.openStdin = function() {
646       process.stdin.resume();
647       return process.stdin;
648     };
649   };
650
651   startup.processKillAndExit = function() {
652
653     process.exit = function(code) {
654       if (code || code === 0)
655         process.exitCode = code;
656
657       if (!process._exiting) {
658         process._exiting = true;
659         process.emit('exit', process.exitCode || 0);
660       }
661       process.reallyExit(process.exitCode || 0);
662     };
663
664     process.kill = function(pid, sig) {
665       var err;
666
667       if (pid != (pid | 0)) {
668         throw new TypeError('invalid pid');
669       }
670
671       // preserve null signal
672       if (0 === sig) {
673         err = process._kill(pid, 0);
674       } else {
675         sig = sig || 'SIGTERM';
676         if (startup.lazyConstants()[sig] &&
677             sig.slice(0, 3) === 'SIG') {
678           err = process._kill(pid, startup.lazyConstants()[sig]);
679         } else {
680           throw new Error('Unknown signal: ' + sig);
681         }
682       }
683
684       if (err) {
685         var errnoException = NativeModule.require('util')._errnoException;
686         throw errnoException(err, 'kill');
687       }
688
689       return true;
690     };
691   };
692
693   startup.processSignalHandlers = function() {
694     // Load events module in order to access prototype elements on process like
695     // process.addListener.
696     var signalWraps = {};
697
698     function isSignal(event) {
699       return event.slice(0, 3) === 'SIG' &&
700              startup.lazyConstants().hasOwnProperty(event);
701     }
702
703     // Detect presence of a listener for the special signal types
704     process.on('newListener', function(type, listener) {
705       if (isSignal(type) &&
706           !signalWraps.hasOwnProperty(type)) {
707         var Signal = process.binding('signal_wrap').Signal;
708         var wrap = new Signal();
709
710         wrap.unref();
711
712         wrap.onsignal = function() { process.emit(type); };
713
714         var signum = startup.lazyConstants()[type];
715         var err = wrap.start(signum);
716         if (err) {
717           wrap.close();
718           var errnoException = NativeModule.require('util')._errnoException;
719           throw errnoException(err, 'uv_signal_start');
720         }
721
722         signalWraps[type] = wrap;
723       }
724     });
725
726     process.on('removeListener', function(type, listener) {
727       if (signalWraps.hasOwnProperty(type) &&
728           NativeModule.require('events').listenerCount(this, type) === 0) {
729         signalWraps[type].close();
730         delete signalWraps[type];
731       }
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 });