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