diff --git a/ext/node/polyfills/02_init.js b/ext/node/polyfills/02_init.js index 85f924493a..752f518bf2 100644 --- a/ext/node/polyfills/02_init.js +++ b/ext/node/polyfills/02_init.js @@ -16,38 +16,32 @@ function initialize( runningOnMainThread, workerId, maybeWorkerMetadata, + warmup = false, ) { - if (initialized) { - throw Error("Node runtime already initialized"); - } - initialized = true; - if (usesLocalNodeModulesDir) { - requireImpl.setUsesLocalNodeModulesDir(); - } - const nativeModuleExports = requireImpl.nativeModuleExports; - nodeGlobals.Buffer = nativeModuleExports["buffer"].Buffer; - nodeGlobals.clearImmediate = nativeModuleExports["timers"].clearImmediate; - nodeGlobals.clearInterval = nativeModuleExports["timers"].clearInterval; - nodeGlobals.clearTimeout = nativeModuleExports["timers"].clearTimeout; - nodeGlobals.console = nativeModuleExports["console"]; - nodeGlobals.global = globalThis; - nodeGlobals.process = nativeModuleExports["process"]; - nodeGlobals.setImmediate = nativeModuleExports["timers"].setImmediate; - nodeGlobals.setInterval = nativeModuleExports["timers"].setInterval; - nodeGlobals.setTimeout = nativeModuleExports["timers"].setTimeout; - nodeGlobals.performance = nativeModuleExports["perf_hooks"].performance; + if (!warmup) { + if (initialized) { + throw Error("Node runtime already initialized"); + } + initialized = true; + if (usesLocalNodeModulesDir) { + requireImpl.setUsesLocalNodeModulesDir(); + } - // FIXME(bartlomieju): not nice to depend on `Deno` namespace here - // but it's the only way to get `args` and `version` and this point. - internals.__bootstrapNodeProcess(argv0, Deno.args, Deno.version); - internals.__initWorkerThreads( - runningOnMainThread, - workerId, - maybeWorkerMetadata, - ); - internals.__setupChildProcessIpcChannel(); - // `Deno[Deno.internal].requireImpl` will be unreachable after this line. - delete internals.requireImpl; + // FIXME(bartlomieju): not nice to depend on `Deno` namespace here + // but it's the only way to get `args` and `version` and this point. + internals.__bootstrapNodeProcess(argv0, Deno.args, Deno.version); + internals.__initWorkerThreads( + runningOnMainThread, + workerId, + maybeWorkerMetadata, + ); + internals.__setupChildProcessIpcChannel(); + // `Deno[Deno.internal].requireImpl` will be unreachable after this line. + delete internals.requireImpl; + } else { + // Warm up the process module + internals.__bootstrapNodeProcess(undefined, undefined, undefined, true); + } } function loadCjsModule(moduleName, isMain, inspectBrk) { @@ -63,3 +57,16 @@ internals.node = { initialize, loadCjsModule, }; + +const nativeModuleExports = requireImpl.nativeModuleExports; +nodeGlobals.Buffer = nativeModuleExports["buffer"].Buffer; +nodeGlobals.clearImmediate = nativeModuleExports["timers"].clearImmediate; +nodeGlobals.clearInterval = nativeModuleExports["timers"].clearInterval; +nodeGlobals.clearTimeout = nativeModuleExports["timers"].clearTimeout; +nodeGlobals.console = nativeModuleExports["console"]; +nodeGlobals.global = globalThis; +nodeGlobals.process = nativeModuleExports["process"]; +nodeGlobals.setImmediate = nativeModuleExports["timers"].setImmediate; +nodeGlobals.setInterval = nativeModuleExports["timers"].setInterval; +nodeGlobals.setTimeout = nativeModuleExports["timers"].setTimeout; +nodeGlobals.performance = nativeModuleExports["perf_hooks"].performance; diff --git a/ext/node/polyfills/_process/streams.mjs b/ext/node/polyfills/_process/streams.mjs index 09c53eb9a2..f50e205888 100644 --- a/ext/node/polyfills/_process/streams.mjs +++ b/ext/node/polyfills/_process/streams.mjs @@ -16,7 +16,7 @@ import * as io from "ext:deno_io/12_io.js"; import { guessHandleType } from "ext:deno_node/internal_binding/util.ts"; // https://github.com/nodejs/node/blob/00738314828074243c9a52a228ab4c68b04259ef/lib/internal/bootstrap/switches/is_main_thread.js#L41 -export function createWritableStdioStream(writer, name) { +export function createWritableStdioStream(writer, name, warmup = false) { const stream = new Writable({ emitClose: false, write(buf, enc, cb) { @@ -73,7 +73,9 @@ export function createWritableStdioStream(writer, name) { }, }); - if (writer?.isTerminal()) { + // If we're warming up, create a stdout/stderr stream that assumes a terminal (the most likely case). + // If we're wrong at boot time, we'll recreate it. + if (warmup || writer?.isTerminal()) { // These belong on tty.WriteStream(), but the TTY streams currently have // following problems: // 1. Using them here introduces a circular dependency. @@ -123,10 +125,11 @@ export function setReadStream(s) { /** https://nodejs.org/api/process.html#process_process_stdin */ // https://github.com/nodejs/node/blob/v18.12.1/lib/internal/bootstrap/switches/is_main_thread.js#L189 /** Create process.stdin */ -export const initStdin = () => { +export const initStdin = (warmup = false) => { const fd = io.stdin ? io.STDIN_RID : undefined; let stdin; - const stdinType = _guessStdinType(fd); + // Warmup assumes a TTY for all stdio + const stdinType = warmup ? "TTY" : _guessStdinType(fd); switch (stdinType) { case "FILE": { @@ -142,6 +145,11 @@ export const initStdin = () => { break; } case "TTY": { + // If it's a TTY, we know that the stdin we created during warmup is the correct one and + // just return null to re-use it. + if (!warmup) { + return null; + } stdin = new readStream(fd); break; } diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts index 44207e2f43..70c516c965 100644 --- a/ext/node/polyfills/process.ts +++ b/ext/node/polyfills/process.ts @@ -68,7 +68,7 @@ const notImplementedEvents = [ "worker", ]; -export const argv: string[] = []; +export const argv: string[] = ["", ""]; let globalProcessExitCode: number | undefined = undefined; /** https://nodejs.org/api/process.html#process_process_exit_code */ @@ -868,69 +868,91 @@ function synchronizeListeners() { } } +// Overwrites the 1st and 2nd items with getters. +Object.defineProperty(argv, "0", { get: () => argv0 }); +Object.defineProperty(argv, "1", { + get: () => { + if (Deno.mainModule?.startsWith("file:")) { + return pathFromURL(new URL(Deno.mainModule)); + } else { + return join(Deno.cwd(), "$deno$node.js"); + } + }, +}); + // Should be called only once, in `runtime/js/99_main.js` when the runtime is // bootstrapped. internals.__bootstrapNodeProcess = function ( argv0Val: string | undefined, args: string[], denoVersions: Record<string, string>, + warmup = false, ) { - // Overwrites the 1st item with getter. - if (typeof argv0Val === "string") { - argv0 = argv0Val; - Object.defineProperty(argv, "0", { - get: () => { - return argv0Val; - }, - }); + if (!warmup) { + argv0 = argv0Val || ""; + // Manually concatenate these arrays to avoid triggering the getter + for (let i = 0; i < args.length; i++) { + argv[i + 2] = args[i]; + } + + for (const [key, value] of Object.entries(denoVersions)) { + versions[key] = value; + } + + core.setNextTickCallback(processTicksAndRejections); + core.setMacrotaskCallback(runNextTicks); + enableNextTick(); + + // Replace stdin if it is not a terminal + const newStdin = initStdin(); + if (newStdin) { + stdin = process.stdin = newStdin; + } + + // Replace stdout/stderr if they are not terminals + if (!io.stdout.isTerminal()) { + /** https://nodejs.org/api/process.html#process_process_stdout */ + stdout = process.stdout = createWritableStdioStream( + io.stdout, + "stdout", + ); + } + + if (!io.stderr.isTerminal()) { + /** https://nodejs.org/api/process.html#process_process_stderr */ + stderr = process.stderr = createWritableStdioStream( + io.stderr, + "stderr", + ); + } + + process.setStartTime(Date.now()); + + arch = arch_(); + platform = isWindows ? "win32" : Deno.build.os; + pid = Deno.pid; + + // @ts-ignore Remove setStartTime and #startTime is not modifiable + delete process.setStartTime; + delete internals.__bootstrapNodeProcess; } else { - Object.defineProperty(argv, "0", { get: () => argv0 }); + // Warmup, assuming stdin/stdout/stderr are all terminals + stdin = process.stdin = initStdin(true); + + /** https://nodejs.org/api/process.html#process_process_stdout */ + stdout = process.stdout = createWritableStdioStream( + io.stdout, + "stdout", + true, + ); + + /** https://nodejs.org/api/process.html#process_process_stderr */ + stderr = process.stderr = createWritableStdioStream( + io.stderr, + "stderr", + true, + ); } - - // Overwrites the 2st item with getter. - Object.defineProperty(argv, "1", { - get: () => { - if (Deno.mainModule?.startsWith("file:")) { - return pathFromURL(new URL(Deno.mainModule)); - } else { - return join(Deno.cwd(), "$deno$node.js"); - } - }, - }); - for (let i = 0; i < args.length; i++) { - argv[i + 2] = args[i]; - } - - for (const [key, value] of Object.entries(denoVersions)) { - versions[key] = value; - } - - core.setNextTickCallback(processTicksAndRejections); - core.setMacrotaskCallback(runNextTicks); - enableNextTick(); - - stdin = process.stdin = initStdin(); - /** https://nodejs.org/api/process.html#process_process_stdout */ - stdout = process.stdout = createWritableStdioStream( - io.stdout, - "stdout", - ); - - /** https://nodejs.org/api/process.html#process_process_stderr */ - stderr = process.stderr = createWritableStdioStream( - io.stderr, - "stderr", - ); - - process.setStartTime(Date.now()); - - arch = arch_(); - platform = isWindows ? "win32" : Deno.build.os; - pid = Deno.pid; - - // @ts-ignore Remove setStartTime and #startTime is not modifiable - delete process.setStartTime; - delete internals.__bootstrapNodeProcess; }; export default process; diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 1a1f781190..a47a7163e1 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -628,6 +628,28 @@ const finalDenoNs = { bench: () => {}, }; +ObjectDefineProperties(finalDenoNs, { + pid: core.propGetterOnly(opPid), + // `ppid` should not be memoized. + // https://github.com/denoland/deno/issues/23004 + ppid: core.propGetterOnly(() => op_ppid()), + noColor: core.propGetterOnly(() => op_bootstrap_no_color()), + args: core.propGetterOnly(opArgs), + mainModule: core.propGetterOnly(() => op_main_module()), + // TODO(kt3k): Remove this export at v2 + // See https://github.com/denoland/deno/issues/9294 + customInspect: { + get() { + warnOnDeprecatedApi( + "Deno.customInspect", + new Error().stack, + 'Use `Symbol.for("Deno.customInspect")` instead.', + ); + return customInspect; + }, + }, +}); + const { denoVersion, tsVersion, @@ -635,155 +657,130 @@ const { target, } = op_snapshot_options(); -function bootstrapMainRuntime(runtimeOptions) { - if (hasBootstrapped) { - throw new Error("Worker runtime already bootstrapped"); - } - const nodeBootstrap = globalThis.nodeBootstrap; - - const { - 0: location_, - 1: unstableFlag, - 2: unstableFeatures, - 3: inspectFlag, - 5: hasNodeModulesDir, - 6: argv0, - 7: shouldDisableDeprecatedApiWarning, - 8: shouldUseVerboseDeprecatedApiWarning, - 9: future, - } = runtimeOptions; - - removeImportedOps(); - - deprecatedApiWarningDisabled = shouldDisableDeprecatedApiWarning; - verboseDeprecatedApiWarning = shouldUseVerboseDeprecatedApiWarning; - performance.setTimeOrigin(DateNow()); - globalThis_ = globalThis; - - // Remove bootstrapping data from the global scope - delete globalThis.__bootstrap; - delete globalThis.bootstrap; - delete globalThis.nodeBootstrap; - hasBootstrapped = true; - - // If the `--location` flag isn't set, make `globalThis.location` `undefined` and - // writable, so that they can mock it themselves if they like. If the flag was - // set, define `globalThis.location`, using the provided value. - if (location_ == null) { - mainRuntimeGlobalProperties.location = { - writable: true, - }; - } else { - location.setLocationHref(location_); - } - - exposeUnstableFeaturesForWindowOrWorkerGlobalScope({ - unstableFlag, - unstableFeatures, - }); - ObjectDefineProperties(globalThis, mainRuntimeGlobalProperties); - ObjectDefineProperties(globalThis, { - // TODO(bartlomieju): in the future we might want to change the - // behavior of setting `name` to actually update the process name. - // Empty string matches what browsers do. - name: core.propWritable(""), - close: core.propWritable(windowClose), - closed: core.propGetterOnly(() => windowIsClosing), - }); - ObjectSetPrototypeOf(globalThis, Window.prototype); - - if (inspectFlag) { - const consoleFromDeno = globalThis.console; - core.wrapConsole(consoleFromDeno, core.v8Console); - } - - event.setEventTargetData(globalThis); - event.saveGlobalThisReference(globalThis); - - event.defineEventHandler(globalThis, "error"); - event.defineEventHandler(globalThis, "load"); - event.defineEventHandler(globalThis, "beforeunload"); - event.defineEventHandler(globalThis, "unload"); - event.defineEventHandler(globalThis, "unhandledrejection"); - - runtimeStart( - denoVersion, - v8Version, - tsVersion, - target, - ); - - ObjectDefineProperties(finalDenoNs, { - pid: core.propGetterOnly(opPid), - // `ppid` should not be memoized. - // https://github.com/denoland/deno/issues/23004 - ppid: core.propGetterOnly(() => op_ppid()), - noColor: core.propGetterOnly(() => op_bootstrap_no_color()), - args: core.propGetterOnly(opArgs), - mainModule: core.propGetterOnly(() => op_main_module()), - // TODO(kt3k): Remove this export at v2 - // See https://github.com/denoland/deno/issues/9294 - customInspect: { - get() { - warnOnDeprecatedApi( - "Deno.customInspect", - new Error().stack, - 'Use `Symbol.for("Deno.customInspect")` instead.', - ); - return customInspect; - }, - }, - }); - - // TODO(bartlomieju): deprecate --unstable - if (unstableFlag) { - ObjectAssign(finalDenoNs, denoNsUnstable); - // TODO(bartlomieju): this is not ideal, but because we use `ObjectAssign` - // above any properties that are defined elsewhere using `Object.defineProperty` - // are lost. - let jupyterNs = undefined; - ObjectDefineProperty(finalDenoNs, "jupyter", { - get() { - if (jupyterNs) { - return jupyterNs; - } - throw new Error( - "Deno.jupyter is only available in `deno jupyter` subcommand.", - ); - }, - set(val) { - jupyterNs = val; - }, - }); - } else { - for (let i = 0; i <= unstableFeatures.length; i++) { - const id = unstableFeatures[i]; - ObjectAssign(finalDenoNs, denoNsUnstableById[id]); +function bootstrapMainRuntime(runtimeOptions, warmup = false) { + if (!warmup) { + if (hasBootstrapped) { + throw new Error("Worker runtime already bootstrapped"); } - } - if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.unsafeProto)) { - // Removes the `__proto__` for security reasons. - // https://tc39.es/ecma262/#sec-get-object.prototype.__proto__ - delete Object.prototype.__proto__; - } + const { + 0: location_, + 1: unstableFlag, + 2: unstableFeatures, + 3: inspectFlag, + 5: hasNodeModulesDir, + 6: argv0, + 7: shouldDisableDeprecatedApiWarning, + 8: shouldUseVerboseDeprecatedApiWarning, + 9: future, + } = runtimeOptions; - if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.temporal)) { - // Removes the `Temporal` API. - delete globalThis.Temporal; - delete globalThis.Date.prototype.toTemporalInstant; - } + removeImportedOps(); - // Setup `Deno` global - we're actually overriding already existing global - // `Deno` with `Deno` namespace from "./deno.ts". - ObjectDefineProperty(globalThis, "Deno", core.propReadOnly(finalDenoNs)); + deprecatedApiWarningDisabled = shouldDisableDeprecatedApiWarning; + verboseDeprecatedApiWarning = shouldUseVerboseDeprecatedApiWarning; + performance.setTimeOrigin(DateNow()); + globalThis_ = globalThis; - if (nodeBootstrap) { - nodeBootstrap(hasNodeModulesDir, argv0, /* runningOnMainThread */ true); - } + // Remove bootstrapping data from the global scope + delete globalThis.__bootstrap; + delete globalThis.bootstrap; + hasBootstrapped = true; - if (future) { - delete globalThis.window; + // If the `--location` flag isn't set, make `globalThis.location` `undefined` and + // writable, so that they can mock it themselves if they like. If the flag was + // set, define `globalThis.location`, using the provided value. + if (location_ == null) { + mainRuntimeGlobalProperties.location = { + writable: true, + }; + } else { + location.setLocationHref(location_); + } + + exposeUnstableFeaturesForWindowOrWorkerGlobalScope({ + unstableFlag, + unstableFeatures, + }); + ObjectDefineProperties(globalThis, mainRuntimeGlobalProperties); + ObjectDefineProperties(globalThis, { + // TODO(bartlomieju): in the future we might want to change the + // behavior of setting `name` to actually update the process name. + // Empty string matches what browsers do. + name: core.propWritable(""), + close: core.propWritable(windowClose), + closed: core.propGetterOnly(() => windowIsClosing), + }); + ObjectSetPrototypeOf(globalThis, Window.prototype); + + if (inspectFlag) { + const consoleFromDeno = globalThis.console; + core.wrapConsole(consoleFromDeno, core.v8Console); + } + + event.defineEventHandler(globalThis, "error"); + event.defineEventHandler(globalThis, "load"); + event.defineEventHandler(globalThis, "beforeunload"); + event.defineEventHandler(globalThis, "unload"); + + runtimeStart( + denoVersion, + v8Version, + tsVersion, + target, + ); + + // TODO(bartlomieju): deprecate --unstable + if (unstableFlag) { + ObjectAssign(finalDenoNs, denoNsUnstable); + // TODO(bartlomieju): this is not ideal, but because we use `ObjectAssign` + // above any properties that are defined elsewhere using `Object.defineProperty` + // are lost. + let jupyterNs = undefined; + ObjectDefineProperty(finalDenoNs, "jupyter", { + get() { + if (jupyterNs) { + return jupyterNs; + } + throw new Error( + "Deno.jupyter is only available in `deno jupyter` subcommand.", + ); + }, + set(val) { + jupyterNs = val; + }, + }); + } else { + for (let i = 0; i <= unstableFeatures.length; i++) { + const id = unstableFeatures[i]; + ObjectAssign(finalDenoNs, denoNsUnstableById[id]); + } + } + + if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.unsafeProto)) { + // Removes the `__proto__` for security reasons. + // https://tc39.es/ecma262/#sec-get-object.prototype.__proto__ + delete Object.prototype.__proto__; + } + + if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.temporal)) { + // Removes the `Temporal` API. + delete globalThis.Temporal; + delete globalThis.Date.prototype.toTemporalInstant; + } + + // Setup `Deno` global - we're actually overriding already existing global + // `Deno` with `Deno` namespace from "./deno.ts". + ObjectDefineProperty(globalThis, "Deno", core.propReadOnly(finalDenoNs)); + + if (nodeBootstrap) { + nodeBootstrap(hasNodeModulesDir, argv0, /* runningOnMainThread */ true); + } + if (future) { + delete globalThis.window; + } + } else { + // Warmup } } @@ -793,146 +790,153 @@ function bootstrapWorkerRuntime( internalName, workerId, maybeWorkerMetadata, + warmup = false, ) { - if (hasBootstrapped) { - throw new Error("Worker runtime already bootstrapped"); - } - - const nodeBootstrap = globalThis.nodeBootstrap; - - const { - 0: location_, - 1: unstableFlag, - 2: unstableFeatures, - 4: enableTestingFeaturesFlag, - 5: hasNodeModulesDir, - 6: argv0, - 7: shouldDisableDeprecatedApiWarning, - 8: shouldUseVerboseDeprecatedApiWarning, - 9: _future, - } = runtimeOptions; - - deprecatedApiWarningDisabled = shouldDisableDeprecatedApiWarning; - verboseDeprecatedApiWarning = shouldUseVerboseDeprecatedApiWarning; - performance.setTimeOrigin(DateNow()); - globalThis_ = globalThis; - - removeImportedOps(); - - // Remove bootstrapping data from the global scope - delete globalThis.__bootstrap; - delete globalThis.bootstrap; - delete globalThis.nodeBootstrap; - hasBootstrapped = true; - - exposeUnstableFeaturesForWindowOrWorkerGlobalScope({ - unstableFlag, - unstableFeatures, - }); - ObjectDefineProperties(globalThis, workerRuntimeGlobalProperties); - ObjectDefineProperties(globalThis, { - name: core.propWritable(name), - // TODO(bartlomieju): should be readonly? - close: core.propNonEnumerable(workerClose), - postMessage: core.propWritable(postMessage), - }); - if (enableTestingFeaturesFlag) { - ObjectDefineProperty( - globalThis, - "importScripts", - core.propWritable(importScripts), - ); - } - ObjectSetPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype); - - const consoleFromDeno = globalThis.console; - core.wrapConsole(consoleFromDeno, core.v8Console); - - event.setEventTargetData(globalThis); - event.saveGlobalThisReference(globalThis); - - event.defineEventHandler(self, "message"); - event.defineEventHandler(self, "error", undefined, true); - event.defineEventHandler(self, "unhandledrejection"); - - // `Deno.exit()` is an alias to `self.close()`. Setting and exit - // code using an op in worker context is a no-op. - os.setExitHandler((_exitCode) => { - workerClose(); - }); - - runtimeStart( - denoVersion, - v8Version, - tsVersion, - target, - internalName ?? name, - ); - - location.setLocationHref(location_); - - globalThis.pollForMessages = pollForMessages; - globalThis.hasMessageEventListener = hasMessageEventListener; - - // TODO(bartlomieju): deprecate --unstable - if (unstableFlag) { - ObjectAssign(finalDenoNs, denoNsUnstable); - } else { - for (let i = 0; i <= unstableFeatures.length; i++) { - const id = unstableFeatures[i]; - ObjectAssign(finalDenoNs, denoNsUnstableById[id]); + if (!warmup) { + if (hasBootstrapped) { + throw new Error("Worker runtime already bootstrapped"); } - } - if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.unsafeProto)) { - // Removes the `__proto__` for security reasons. - // https://tc39.es/ecma262/#sec-get-object.prototype.__proto__ - delete Object.prototype.__proto__; - } + const { + 0: location_, + 1: unstableFlag, + 2: unstableFeatures, + 4: enableTestingFeaturesFlag, + 5: hasNodeModulesDir, + 6: argv0, + 7: shouldDisableDeprecatedApiWarning, + 8: shouldUseVerboseDeprecatedApiWarning, + 9: _future, + } = runtimeOptions; - if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.temporal)) { - // Removes the `Temporal` API. - delete globalThis.Temporal; - delete globalThis.Date.prototype.toTemporalInstant; - } + deprecatedApiWarningDisabled = shouldDisableDeprecatedApiWarning; + verboseDeprecatedApiWarning = shouldUseVerboseDeprecatedApiWarning; + performance.setTimeOrigin(DateNow()); + globalThis_ = globalThis; - ObjectDefineProperties(finalDenoNs, { - pid: core.propGetterOnly(opPid), - noColor: core.propGetterOnly(() => op_bootstrap_no_color()), - args: core.propGetterOnly(opArgs), - // TODO(kt3k): Remove this export at v2 - // See https://github.com/denoland/deno/issues/9294 - customInspect: { - get() { - warnOnDeprecatedApi( - "Deno.customInspect", - new Error().stack, - 'Use `Symbol.for("Deno.customInspect")` instead.', - ); - return customInspect; - }, - }, - }); - // Setup `Deno` global - we're actually overriding already - // existing global `Deno` with `Deno` namespace from "./deno.ts". - ObjectDefineProperty(globalThis, "Deno", core.propReadOnly(finalDenoNs)); + // Remove bootstrapping data from the global scope + delete globalThis.__bootstrap; + delete globalThis.bootstrap; + hasBootstrapped = true; - const workerMetadata = maybeWorkerMetadata - ? messagePort.deserializeJsMessageData(maybeWorkerMetadata) - : undefined; + exposeUnstableFeaturesForWindowOrWorkerGlobalScope({ + unstableFlag, + unstableFeatures, + }); + ObjectDefineProperties(globalThis, workerRuntimeGlobalProperties); + ObjectDefineProperties(globalThis, { + name: core.propWritable(name), + // TODO(bartlomieju): should be readonly? + close: core.propNonEnumerable(workerClose), + postMessage: core.propWritable(postMessage), + }); + if (enableTestingFeaturesFlag) { + ObjectDefineProperty( + globalThis, + "importScripts", + core.propWritable(importScripts), + ); + } + ObjectSetPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype); - if (nodeBootstrap) { - nodeBootstrap( - hasNodeModulesDir, - argv0, - /* runningOnMainThread */ false, - workerId, - workerMetadata, + const consoleFromDeno = globalThis.console; + core.wrapConsole(consoleFromDeno, core.v8Console); + + event.defineEventHandler(self, "message"); + event.defineEventHandler(self, "error", undefined, true); + + // `Deno.exit()` is an alias to `self.close()`. Setting and exit + // code using an op in worker context is a no-op. + os.setExitHandler((_exitCode) => { + workerClose(); + }); + + runtimeStart( + denoVersion, + v8Version, + tsVersion, + target, + internalName ?? name, ); + + location.setLocationHref(location_); + + globalThis.pollForMessages = pollForMessages; + globalThis.hasMessageEventListener = hasMessageEventListener; + + // TODO(bartlomieju): deprecate --unstable + if (unstableFlag) { + ObjectAssign(finalDenoNs, denoNsUnstable); + } else { + for (let i = 0; i <= unstableFeatures.length; i++) { + const id = unstableFeatures[i]; + ObjectAssign(finalDenoNs, denoNsUnstableById[id]); + } + } + + // Not available in workers + delete finalDenoNs.mainModule; + + if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.unsafeProto)) { + // Removes the `__proto__` for security reasons. + // https://tc39.es/ecma262/#sec-get-object.prototype.__proto__ + delete Object.prototype.__proto__; + } + + if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.temporal)) { + // Removes the `Temporal` API. + delete globalThis.Temporal; + delete globalThis.Date.prototype.toTemporalInstant; + } + + // Setup `Deno` global - we're actually overriding already existing global + // `Deno` with `Deno` namespace from "./deno.ts". + ObjectDefineProperty(globalThis, "Deno", core.propReadOnly(finalDenoNs)); + + const workerMetadata = maybeWorkerMetadata + ? messagePort.deserializeJsMessageData(maybeWorkerMetadata) + : undefined; + + if (nodeBootstrap) { + nodeBootstrap( + hasNodeModulesDir, + argv0, + /* runningOnMainThread */ false, + workerId, + workerMetadata, + ); + } + } else { + // Warmup + return; } } +const nodeBootstrap = globalThis.nodeBootstrap; +delete globalThis.nodeBootstrap; + globalThis.bootstrap = { mainRuntime: bootstrapMainRuntime, workerRuntime: bootstrapWorkerRuntime, }; + +event.setEventTargetData(globalThis); +event.saveGlobalThisReference(globalThis); +event.defineEventHandler(globalThis, "unhandledrejection"); + +// Nothing listens to this, but it warms up the code paths for event dispatch +(new event.EventTarget()).dispatchEvent(new Event("warmup")); + +removeImportedOps(); + +// Run the warmup path through node and runtime/worker bootstrap functions +bootstrapMainRuntime(undefined, true); +bootstrapWorkerRuntime( + undefined, + undefined, + undefined, + undefined, + undefined, + true, +); +nodeBootstrap(undefined, undefined, undefined, undefined, undefined, true);