current commit
261014.1 · Use `const` in JS library code where values can be inlined (#27871)
/**
 * @license
 * Copyright 2010 The Emscripten Authors
 * SPDX-License-Identifier: MIT
 */
#if STRICT_JS && !MODULARIZE // MODULARIZE handles this itself
"use strict";
#endif

#include "minimum_runtime_check.js"

// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(moduleArg) => Promise<Module>
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define   var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
#if MODULARIZE
#if MODULARIZE == 'instance'
var Module = {};
#endif
#elif USE_CLOSURE_COMPILER
/** @type{Object} */
var Module;
// if (!Module) is crucial for Closure Compiler here as it will otherwise replace every `Module` occurrence with a string
if (!Module) /** @suppress{checkTypes}*/Module = {"__EMSCRIPTEN_PRIVATE_MODULE_EXPORT_NAME_SUBSTITUTION__":1};
#elif ENVIRONMENT_MAY_BE_AUDIO_WORKLET
var Module = globalThis.Module || (typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : {});
#else
var Module = typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : {};
#endif // USE_CLOSURE_COMPILER

#if WASM_WORKERS
// The way we signal to a worker that it is hosting a pthread is to construct
// it with a specific name.
var ENVIRONMENT_IS_WASM_WORKER = {{{ wasmWorkerDetection() }}};
#endif

#if ENVIRONMENT_MAY_BE_AUDIO_WORKLET
var ENVIRONMENT_IS_AUDIO_WORKLET = !!globalThis.AudioWorkletGlobalScope;
#endif

#if AUDIO_WORKLET
// Audio worklets behave as wasm workers.
if (ENVIRONMENT_IS_AUDIO_WORKLET) ENVIRONMENT_IS_WASM_WORKER = true;
#endif

// Determine the runtime environment we are in. You can customize this by
// setting the ENVIRONMENT setting at compile time (see settings.js).

#if ENVIRONMENT.length == 1 && !ASSERTIONS
const ENVIRONMENT_IS_WEB = {{{ ENVIRONMENT[0] === 'web' }}};
#if PTHREADS && ENVIRONMENT_MAY_BE_NODE
// node+pthreads always supports workers; detect which we are at runtime
var ENVIRONMENT_IS_WORKER = !!globalThis.WorkerGlobalScope;
#elif PTHREADS || WASM_WORKERS
var ENVIRONMENT_IS_WORKER = {{{ ENVIRONMENT[0] === 'worker' }}};
#else
const ENVIRONMENT_IS_WORKER = {{{ ENVIRONMENT[0] === 'worker' }}};
#endif
const ENVIRONMENT_IS_NODE = {{{ ENVIRONMENT[0] === 'node' }}};
const ENVIRONMENT_IS_SHELL = {{{ ENVIRONMENT[0] === 'shell' }}};
#else // ENVIRONMENT.length == 1 && !ASSERTIONS
// Attempt to auto-detect the environment
var ENVIRONMENT_IS_WEB = !!globalThis.window;
var ENVIRONMENT_IS_WORKER = !!globalThis.WorkerGlobalScope;
// N.b. Electron.js environment is simultaneously a NODE-environment, but
// also a web environment.
var ENVIRONMENT_IS_NODE = {{{ nodeDetectionCode() }}};
#if ENVIRONMENT_MAY_BE_AUDIO_WORKLET
var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER && !ENVIRONMENT_IS_AUDIO_WORKLET;
#else
var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
#endif
#endif // ENVIRONMENT.length == 1 && !ASSERTIONS

#if PTHREADS
// Three configurations we can be running in:
// 1) We could be the application main() thread running in the main JS UI thread. (ENVIRONMENT_IS_WORKER == false and ENVIRONMENT_IS_PTHREAD == false)
// 2) We could be the application main() running directly in a worker. (ENVIRONMENT_IS_WORKER == true, ENVIRONMENT_IS_PTHREAD == false)
// 3) We could be an application pthread running in a worker. (ENVIRONMENT_IS_WORKER == true and ENVIRONMENT_IS_PTHREAD == true)

// The way we signal to a worker that it is hosting a pthread is to construct
// it with a specific name.
var ENVIRONMENT_IS_PTHREAD = ENVIRONMENT_IS_WORKER && {{{ pthreadDetection() }}}

#if MODULARIZE && ASSERTIONS
if (ENVIRONMENT_IS_PTHREAD) {
  assert(!globalThis.moduleLoaded, 'module should only be loaded once on each pthread worker');
  globalThis.moduleLoaded = true;
}
#endif
#endif

#if ENVIRONMENT_MAY_BE_NODE && (EXPORT_ES6 || PTHREADS || WASM_WORKERS)
if (ENVIRONMENT_IS_NODE) {
#if EXPORT_ES6
  // When building an ES module `require` is not normally available.
  // We need to use `createRequire()` to construct the require()` function.
  const { createRequire } = await import('node:module');
  /** @suppress{duplicate} */
  var require = createRequire(import.meta.url);
#endif

#if PTHREADS || WASM_WORKERS
  var worker_threads = require('node:worker_threads');
  globalThis.Worker = worker_threads.Worker;
  ENVIRONMENT_IS_WORKER = !worker_threads.isMainThread;
#if PTHREADS
  // Under node we set `workerData` to `em-pthread` to signal that the worker
  // is hosting a pthread.
  ENVIRONMENT_IS_PTHREAD = ENVIRONMENT_IS_WORKER && worker_threads.workerData == 'em-pthread'
#endif // PTHREADS
#if WASM_WORKERS
  ENVIRONMENT_IS_WASM_WORKER = ENVIRONMENT_IS_WORKER && worker_threads.workerData == 'em-ww'
#endif
#endif // PTHREADS || WASM_WORKERS
}
#endif // ENVIRONMENT_MAY_BE_NODE && (EXPORT_ES6 || PTHREADS || WASM_WORKERS)

// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
{{{ preJS() }}}

var programArgs = [];
var thisProgram = './this.program';
var quit_ = (status, toThrow) => {
  throw toThrow;
};

#if EXPORT_ES6
var _scriptName = import.meta.url;
#else
#if ENVIRONMENT_MAY_BE_WEB
#if !MODULARIZE
// In MODULARIZE mode _scriptName needs to be captured already at the very top of the page immediately when the page is parsed, so it is generated there
// before the page load. In non-MODULARIZE modes generate it here.
#if SINGLE_FILE && OUTPUT_FORMAT == 'HTML'
var _scriptName = globalThis.document ? URL.createObjectURL(new Blob([document.getElementById('mainScript').textContent], { "type" : "text/javascript" })) : undefined;
#else
var _scriptName = globalThis.document?.currentScript?.src;
#endif
#endif // !MODULARIZE
#elif ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_WORKER
var _scriptName;
#endif // ENVIRONMENT_MAY_BE_WEB

#if ENVIRONMENT_MAY_BE_NODE
if (typeof __filename !== 'undefined') { // Node
  _scriptName = __filename;
} else
#endif // ENVIRONMENT_MAY_BE_NODE
#if ENVIRONMENT_MAY_BE_WORKER
if (ENVIRONMENT_IS_WORKER) {
  _scriptName = self.location.href;
}
#elif ENVIRONMENT_MAY_BE_NODE
  /*no-op*/{}
#endif // ENVIRONMENT_MAY_BE_WORKER
#endif // EXPORT_ES6

// `/` should be present at the end if `scriptDirectory` is not empty
var scriptDirectory = '';
function locateFile(path) {
#if RUNTIME_DEBUG
  dbg('locateFile:', path, 'scriptDirectory:', scriptDirectory);
#endif
#if expectToReceiveOnModule('locateFile')
  if (Module['locateFile']) {
    return Module['locateFile'](path, scriptDirectory);
  }
#endif
  return scriptDirectory + path;
}

// Hooks that are implemented differently in different runtime environments.
var readAsync, readBinary;

#if ENVIRONMENT_MAY_BE_NODE
if (ENVIRONMENT_IS_NODE) {
#if ENVIRONMENT.length && ASSERTIONS
  const isNode = {{{ nodeDetectionCode() }}};
  if (!isNode) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)');
#endif

  // These modules will usually be used on Node.js. Load them eagerly to avoid
  // the complexity of lazy-loading.
  var fs = require('node:fs');

#if EXPORT_ES6
  if (_scriptName.startsWith('file:')) {
    scriptDirectory = require('node:path').dirname(require('node:url').fileURLToPath(_scriptName)) + '/';
  }
#else
  scriptDirectory = __dirname + '/';
#endif

#include "node_shell_read.js"

  if (process.argv.length > 1) {
    thisProgram = process.argv[1].replace(/\\/g, '/');
  }

  programArgs = process.argv.slice(2);

#if !MODULARIZE
  // MODULARIZE will export the module in the proper place outside, we don't need to export here
  if (typeof module !== 'undefined') {
    module['exports'] = Module;
  }
#endif

  quit_ = (status, toThrow) => {
    process.exitCode = status;
    throw toThrow;
  };

#if WASM == 2
  // If target shell does not support Wasm, load the JS version of the code.
  if (!globalThis.WebAssembly) {
    eval(fs.readFileSync(locateFile('{{{ TARGET_BASENAME }}}.wasm.js'))+'');
  }
#endif

} else
#endif // ENVIRONMENT_MAY_BE_NODE
#if ENVIRONMENT_MAY_BE_SHELL || ASSERTIONS
if (ENVIRONMENT_IS_SHELL) {

#if ENVIRONMENT_MAY_BE_SHELL
  readBinary = (f) => {
    if (globalThis.readbuffer) {
      return new Uint8Array(readbuffer(f));
    }
    let data = read(f, 'binary');
    assert(typeof data === 'object');
    return data;
  };

  readAsync = async (f) => readBinary(f);

  globalThis.clearTimeout ??= (id) => {};

  // v8 and jsc both use `arguments`. spidermonkey uses `scriptArgs`
  programArgs = globalThis.arguments ?? globalThis.scriptArgs;

  if (globalThis.quit) {
    quit_ = (status, toThrow) => {
      // Unlike node which has process.exitCode, d8 has no such mechanism. So we
      // have no way to set the exit code and then let the program exit with
      // that code when it naturally stops running (say, when all setTimeouts
      // have completed). For that reason, we must call `quit` - the only way to
      // set the exit code - but quit also halts immediately.  To increase
      // consistency with node (and the web) we schedule the actual quit call
      // using a setTimeout to give the current stack and any exception handlers
      // a chance to run.  This enables features such as addOnPostRun (which
      // expected to be able to run code after main returns).
      setTimeout(() => {
        if (!(toThrow instanceof ExitStatus)) {
          let toLog = toThrow;
          if (toThrow && typeof toThrow === 'object' && toThrow.stack) {
            toLog = [toThrow, toThrow.stack];
          }
          err(`exiting due to exception: ${toLog}`);
        }
        quit(status);
      });
      throw toThrow;
    };
  }

  if (globalThis.print) {
    // Use `print` to implement console.log/error/warn as needed.
    globalThis.console ??= /** @type{!Console} */({});
    console.log ??= /** @type{!function(this:Console, ...*): undefined} */ (print);
    console.warn ??= console.error ??= /** @type{!function(this:Console, ...*): undefined} */ (globalThis.printErr ?? print);
  }

#if WASM == 2
  // If target shell does not support Wasm, load the JS version of the code.
  if (!globalThis.WebAssembly) {
    eval(read(locateFile('{{{ TARGET_BASENAME }}}.wasm.js'))+'');
  }
#endif
#endif // ENVIRONMENT_MAY_BE_SHELL

} else
#endif // ENVIRONMENT_MAY_BE_SHELL || ASSERTIONS

// Note that this includes Node.js workers when relevant (pthreads is enabled).
// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
// ENVIRONMENT_IS_NODE.
#if ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER
if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
  try {
    scriptDirectory = new URL('.', _scriptName).href; // includes trailing slash
  } catch {
    // Must be a `blob:` or `data:` URL (e.g. `blob:http://site.com/etc/etc`), we cannot
    // infer anything from them.
  }

#if ENVIRONMENT.length && ASSERTIONS
  if (!(globalThis.window || globalThis.WorkerGlobalScope)) throw new Error('not compiled for this environment (did you build to HTML and try to run it not on the web, or set ENVIRONMENT to something - like node - and run it someplace else - like on the web?)');
#endif

#if PTHREADS && ENVIRONMENT_MAY_BE_NODE
  // Differentiate the Web Worker from the Node Worker case, as reading must
  // be done differently.
  if (!ENVIRONMENT_IS_NODE)
#endif
  {
#include "web_or_worker_shell_read.js"
  }
} else
#endif // ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER
#if ENVIRONMENT_MAY_BE_AUDIO_WORKLET
#endif
#if ENVIRONMENT_MAY_BE_AUDIO_WORKLET && ASSERTIONS
if (!ENVIRONMENT_IS_AUDIO_WORKLET)
#endif
{
#if ASSERTIONS
  throw new Error('environment detection error');
#endif // ASSERTIONS
}

#if ENVIRONMENT_MAY_BE_NODE && (PTHREADS || WASM_WORKERS)
// Set up the out() and err() hooks, which are how we can print to stdout or
// stderr, respectively.
// Normally just binding console.log/console.error here works fine, but
// under node (with workers) we see missing/out-of-order messages so route
// directly to stdout and stderr.
// See https://github.com/emscripten-core/emscripten/issues/14804
var defaultPrint = console.log.bind(console);
var defaultPrintErr = console.error.bind(console);
if (ENVIRONMENT_IS_NODE) {
  var utils = require('node:util');
  var stringify = (a) => typeof a === 'object' ? utils.inspect(a) : a;
  defaultPrint = (...args) => fs.writeSync(1, args.map(stringify).join(' ') + '\n');
  defaultPrintErr = (...args) => fs.writeSync(2, args.map(stringify).join(' ') + '\n');
}
{{{ makeModuleReceiveWithVar('out', 'print',    'defaultPrint') }}}
{{{ makeModuleReceiveWithVar('err', 'printErr', 'defaultPrintErr') }}}
#else
{{{ makeModuleReceiveWithVar('out', 'print',    'console.log.bind(console)') }}}
{{{ makeModuleReceiveWithVar('err', 'printErr', 'console.error.bind(console)') }}}
#endif

#if ASSERTIONS

{{{ makeRemovedFSAssert('IDBFS') }}}
{{{ makeRemovedFSAssert('PROXYFS') }}}
{{{ makeRemovedFSAssert('WORKERFS') }}}
{{{ makeRemovedFSAssert('FETCHFS') }}}
{{{ makeRemovedFSAssert('ICASEFS') }}}
{{{ makeRemovedFSAssert('JSFILEFS') }}}
{{{ makeRemovedFSAssert('OPFS') }}}

#if !NODERAWFS
{{{ makeRemovedFSAssert('NODEFS') }}}
#endif

// perform assertions in shell.js after we set up out() and err(), as otherwise
// if an assertion fails it cannot print the message
#if PTHREADS
assert(
#if ENVIRONMENT_MAY_BE_AUDIO_WORKLET
  ENVIRONMENT_IS_AUDIO_WORKLET ||
#endif
  ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER || ENVIRONMENT_IS_NODE, 'pthreads do not work in this environment yet (need Web Workers, or an alternative to them)');
#else
#endif // PTHREADS

#if !ENVIRONMENT_MAY_BE_WEB
assert(!ENVIRONMENT_IS_WEB, 'web environment detected but not enabled at build time (add `web` to `-sENVIRONMENT` to enable)');
#endif

#if !ENVIRONMENT_MAY_BE_WORKER
assert(!ENVIRONMENT_IS_WORKER, 'worker environment detected but not enabled at build time (add `worker` to `-sENVIRONMENT` to enable)');
#endif

#if !ENVIRONMENT_MAY_BE_NODE
assert(!ENVIRONMENT_IS_NODE, 'node environment detected but not enabled at build time (add `node` to `-sENVIRONMENT` to enable)');
#endif

#if !ENVIRONMENT_MAY_BE_SHELL
assert(!ENVIRONMENT_IS_SHELL, 'shell environment detected but not enabled at build time (add `shell` to `-sENVIRONMENT` to enable)');
#endif

#endif // ASSERTIONS