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