• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Hello, and welcome to hacking node.js!
2//
3// This file is invoked by `node::RunBootstrapping()` in `src/node.cc`, and is
4// responsible for setting up node.js core before executing main scripts
5// under `lib/internal/main/`.
6//
7// This file is expected not to perform any asynchronous operations itself
8// when being executed - those should be done in either
9// `lib/internal/bootstrap/pre_execution.js` or in main scripts. The majority
10// of the code here focuses on setting up the global proxy and the process
11// object in a synchronous manner.
12// As special caution is given to the performance of the startup process,
13// many dependencies are invoked lazily.
14//
15// Scripts run before this file:
16// - `lib/internal/per_context/primordials.js`: to save copies of JavaScript
17//   builtins that won't be affected by user land monkey-patching for internal
18//   modules to use.
19// - `lib/internal/bootstrap/loaders.js`: to setup internal binding and
20//   module loaders, including `process.binding()`, `process._linkedBinding()`,
21//   `internalBinding()` and `NativeModule`.
22//
23// This file is run to bootstrap both the main thread and the worker threads.
24// After this file is run, certain properties are setup according to the
25// configuration of the Node.js instance using the files in
26// `lib/internal/bootstrap/switches/`.
27//
28// Then, depending on how the Node.js instance is launched, one of the main
29// scripts in `lib/internal/main` will be selected by C++ to start the actual
30// execution. They may run additional setups exported by
31// `lib/internal/bootstrap/pre_execution.js` depending on the runtime states.
32
33'use strict';
34
35// This file is compiled as if it's wrapped in a function with arguments
36// passed by node::RunBootstrapping()
37/* global process, require, internalBinding, primordials */
38
39setupPrepareStackTrace();
40
41const {
42  JSONParse,
43  ObjectDefineProperties,
44  ObjectDefineProperty,
45  ObjectGetPrototypeOf,
46  ObjectSetPrototypeOf,
47  SymbolToStringTag,
48} = primordials;
49const config = internalBinding('config');
50const { deprecate } = require('internal/util');
51
52setupProcessObject();
53
54setupGlobalProxy();
55setupBuffer();
56
57process.domain = null;
58process._exiting = false;
59
60// process.config is serialized config.gypi
61process.config = JSONParse(internalBinding('native_module').config);
62require('internal/worker/js_transferable').setup();
63
64// Bootstrappers for all threads, including worker threads and main thread
65const perThreadSetup = require('internal/process/per_thread');
66const rawMethods = internalBinding('process_methods');
67
68// Set up methods on the process object for all threads
69{
70  process.dlopen = rawMethods.dlopen;
71  process.uptime = rawMethods.uptime;
72
73  // TODO(joyeecheung): either remove them or make them public
74  process._getActiveRequests = rawMethods._getActiveRequests;
75  process._getActiveHandles = rawMethods._getActiveHandles;
76
77  // TODO(joyeecheung): remove these
78  process.reallyExit = rawMethods.reallyExit;
79  process._kill = rawMethods._kill;
80
81  const wrapped = perThreadSetup.wrapProcessMethods(rawMethods);
82  process._rawDebug = wrapped._rawDebug;
83  process.hrtime = wrapped.hrtime;
84  process.hrtime.bigint = wrapped.hrtimeBigInt;
85  process.cpuUsage = wrapped.cpuUsage;
86  process.resourceUsage = wrapped.resourceUsage;
87  process.memoryUsage = wrapped.memoryUsage;
88  process.kill = wrapped.kill;
89  process.exit = wrapped.exit;
90
91  process.openStdin = function() {
92    process.stdin.resume();
93    return process.stdin;
94  };
95}
96
97const credentials = internalBinding('credentials');
98if (credentials.implementsPosixCredentials) {
99  process.getuid = credentials.getuid;
100  process.geteuid = credentials.geteuid;
101  process.getgid = credentials.getgid;
102  process.getegid = credentials.getegid;
103  process.getgroups = credentials.getgroups;
104}
105
106// Setup the callbacks that node::AsyncWrap will call when there are hooks to
107// process. They use the same functions as the JS embedder API. These callbacks
108// are setup immediately to prevent async_wrap.setupHooks() from being hijacked
109// and the cost of doing so is negligible.
110const { nativeHooks } = require('internal/async_hooks');
111internalBinding('async_wrap').setupHooks(nativeHooks);
112
113const {
114  setupTaskQueue,
115  queueMicrotask
116} = require('internal/process/task_queues');
117
118if (!config.noBrowserGlobals) {
119  // Override global console from the one provided by the VM
120  // to the one implemented by Node.js
121  // https://console.spec.whatwg.org/#console-namespace
122  exposeNamespace(global, 'console', createGlobalConsole(global.console));
123
124  const { URL, URLSearchParams } = require('internal/url');
125  // https://url.spec.whatwg.org/#url
126  exposeInterface(global, 'URL', URL);
127  // https://url.spec.whatwg.org/#urlsearchparams
128  exposeInterface(global, 'URLSearchParams', URLSearchParams);
129
130  const {
131    TextEncoder, TextDecoder
132  } = require('internal/encoding');
133  // https://encoding.spec.whatwg.org/#textencoder
134  exposeInterface(global, 'TextEncoder', TextEncoder);
135  // https://encoding.spec.whatwg.org/#textdecoder
136  exposeInterface(global, 'TextDecoder', TextDecoder);
137
138  // https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope
139  const timers = require('timers');
140  defineOperation(global, 'clearInterval', timers.clearInterval);
141  defineOperation(global, 'clearTimeout', timers.clearTimeout);
142  defineOperation(global, 'setInterval', timers.setInterval);
143  defineOperation(global, 'setTimeout', timers.setTimeout);
144
145  defineOperation(global, 'queueMicrotask', queueMicrotask);
146
147  // Non-standard extensions:
148  defineOperation(global, 'clearImmediate', timers.clearImmediate);
149  defineOperation(global, 'setImmediate', timers.setImmediate);
150}
151
152// Set the per-Environment callback that will be called
153// when the TrackingTraceStateObserver updates trace state.
154// Note that when NODE_USE_V8_PLATFORM is true, the observer is
155// attached to the per-process TracingController.
156const { setTraceCategoryStateUpdateHandler } = internalBinding('trace_events');
157setTraceCategoryStateUpdateHandler(perThreadSetup.toggleTraceCategoryState);
158
159// process.allowedNodeEnvironmentFlags
160ObjectDefineProperty(process, 'allowedNodeEnvironmentFlags', {
161  get() {
162    const flags = perThreadSetup.buildAllowedFlags();
163    process.allowedNodeEnvironmentFlags = flags;
164    return process.allowedNodeEnvironmentFlags;
165  },
166  // If the user tries to set this to another value, override
167  // this completely to that value.
168  set(value) {
169    ObjectDefineProperty(this, 'allowedNodeEnvironmentFlags', {
170      value,
171      configurable: true,
172      enumerable: true,
173      writable: true
174    });
175  },
176  enumerable: true,
177  configurable: true
178});
179
180// process.assert
181process.assert = deprecate(
182  perThreadSetup.assert,
183  'process.assert() is deprecated. Please use the `assert` module instead.',
184  'DEP0100');
185
186// TODO(joyeecheung): this property has not been well-maintained, should we
187// deprecate it in favor of a better API?
188const { isDebugBuild, hasOpenSSL, hasInspector } = config;
189ObjectDefineProperty(process, 'features', {
190  enumerable: true,
191  writable: false,
192  configurable: false,
193  value: {
194    inspector: hasInspector,
195    debug: isDebugBuild,
196    uv: true,
197    ipv6: true,  // TODO(bnoordhuis) ping libuv
198    tls_alpn: hasOpenSSL,
199    tls_sni: hasOpenSSL,
200    tls_ocsp: hasOpenSSL,
201    tls: hasOpenSSL,
202    cached_builtins: config.hasCachedBuiltins,
203  }
204});
205
206{
207  const {
208    onGlobalUncaughtException,
209    setUncaughtExceptionCaptureCallback,
210    hasUncaughtExceptionCaptureCallback
211  } = require('internal/process/execution');
212
213  // For legacy reasons this is still called `_fatalException`, even
214  // though it is now a global uncaught exception handler.
215  // The C++ land node::errors::TriggerUncaughtException grabs it
216  // from the process object because it has been monkey-patchable.
217  // TODO(joyeecheung): investigate whether process._fatalException
218  // can be deprecated.
219  process._fatalException = onGlobalUncaughtException;
220  process.setUncaughtExceptionCaptureCallback =
221    setUncaughtExceptionCaptureCallback;
222  process.hasUncaughtExceptionCaptureCallback =
223    hasUncaughtExceptionCaptureCallback;
224}
225
226const { emitWarning } = require('internal/process/warning');
227process.emitWarning = emitWarning;
228
229// We initialize the tick callbacks and the timer callbacks last during
230// bootstrap to make sure that any operation done before this are synchronous.
231// If any ticks or timers are scheduled before this they are unlikely to work.
232{
233  const { nextTick, runNextTicks } = setupTaskQueue();
234  process.nextTick = nextTick;
235  // Used to emulate a tick manually in the JS land.
236  // A better name for this function would be `runNextTicks` but
237  // it has been exposed to the process object so we keep this legacy name
238  // TODO(joyeecheung): either remove it or make it public
239  process._tickCallback = runNextTicks;
240
241  const { getTimerCallbacks } = require('internal/timers');
242  const { setupTimers } = internalBinding('timers');
243  const { processImmediate, processTimers } = getTimerCallbacks(runNextTicks);
244  // Sets two per-Environment callbacks that will be run from libuv:
245  // - processImmediate will be run in the callback of the per-Environment
246  //   check handle.
247  // - processTimers will be run in the callback of the per-Environment timer.
248  setupTimers(processImmediate, processTimers);
249  // Note: only after this point are the timers effective
250}
251
252function setupPrepareStackTrace() {
253  const {
254    setEnhanceStackForFatalException,
255    setPrepareStackTraceCallback
256  } = internalBinding('errors');
257  const {
258    prepareStackTrace,
259    fatalExceptionStackEnhancers: {
260      beforeInspector,
261      afterInspector
262    }
263  } = require('internal/errors');
264  // Tell our PrepareStackTraceCallback passed to the V8 API
265  // to call prepareStackTrace().
266  setPrepareStackTraceCallback(prepareStackTrace);
267  // Set the function used to enhance the error stack for printing
268  setEnhanceStackForFatalException(beforeInspector, afterInspector);
269}
270
271function setupProcessObject() {
272  const EventEmitter = require('events');
273  const origProcProto = ObjectGetPrototypeOf(process);
274  ObjectSetPrototypeOf(origProcProto, EventEmitter.prototype);
275  EventEmitter.call(process);
276  ObjectDefineProperty(process, SymbolToStringTag, {
277    enumerable: false,
278    writable: true,
279    configurable: false,
280    value: 'process'
281  });
282  // Make process globally available to users by putting it on the global proxy
283  ObjectDefineProperty(global, 'process', {
284    value: process,
285    enumerable: false,
286    writable: true,
287    configurable: true
288  });
289}
290
291function setupGlobalProxy() {
292  ObjectDefineProperty(global, SymbolToStringTag, {
293    value: 'global',
294    writable: false,
295    enumerable: false,
296    configurable: true
297  });
298
299  function makeGetter(name) {
300    return deprecate(function() {
301      return this;
302    }, `'${name}' is deprecated, use 'global'`, 'DEP0016');
303  }
304
305  function makeSetter(name) {
306    return deprecate(function(value) {
307      ObjectDefineProperty(this, name, {
308        configurable: true,
309        writable: true,
310        enumerable: true,
311        value: value
312      });
313    }, `'${name}' is deprecated, use 'global'`, 'DEP0016');
314  }
315
316  ObjectDefineProperties(global, {
317    GLOBAL: {
318      configurable: true,
319      get: makeGetter('GLOBAL'),
320      set: makeSetter('GLOBAL')
321    },
322    root: {
323      configurable: true,
324      get: makeGetter('root'),
325      set: makeSetter('root')
326    }
327  });
328}
329
330function setupBuffer() {
331  const { Buffer } = require('buffer');
332  const bufferBinding = internalBinding('buffer');
333
334  // Only after this point can C++ use Buffer::New()
335  bufferBinding.setBufferPrototype(Buffer.prototype);
336  delete bufferBinding.setBufferPrototype;
337  delete bufferBinding.zeroFill;
338
339  ObjectDefineProperty(global, 'Buffer', {
340    value: Buffer,
341    enumerable: false,
342    writable: true,
343    configurable: true
344  });
345}
346
347function createGlobalConsole(consoleFromVM) {
348  const consoleFromNode =
349    require('internal/console/global');
350  if (config.hasInspector) {
351    const inspector = require('internal/util/inspector');
352    // This will be exposed by `require('inspector').console` later.
353    inspector.consoleFromVM = consoleFromVM;
354    // TODO(joyeecheung): postpone this until the first time inspector
355    // is activated.
356    inspector.wrapConsole(consoleFromNode, consoleFromVM);
357    const { setConsoleExtensionInstaller } = internalBinding('inspector');
358    // Setup inspector command line API.
359    setConsoleExtensionInstaller(inspector.installConsoleExtensions);
360  }
361  return consoleFromNode;
362}
363
364// https://heycam.github.io/webidl/#es-namespaces
365function exposeNamespace(target, name, namespaceObject) {
366  ObjectDefineProperty(target, name, {
367    writable: true,
368    enumerable: false,
369    configurable: true,
370    value: namespaceObject
371  });
372}
373
374// https://heycam.github.io/webidl/#es-interfaces
375function exposeInterface(target, name, interfaceObject) {
376  ObjectDefineProperty(target, name, {
377    writable: true,
378    enumerable: false,
379    configurable: true,
380    value: interfaceObject
381  });
382}
383
384// https://heycam.github.io/webidl/#define-the-operations
385function defineOperation(target, name, method) {
386  ObjectDefineProperty(target, name, {
387    writable: true,
388    enumerable: true,
389    configurable: true,
390    value: method
391  });
392}
393