/**
 * @license
 * Copyright 2010 The Emscripten Authors
 * SPDX-License-Identifier: MIT
 */

// === Preamble library stuff ===

// Documentation for the public APIs defined in this file must be updated in:
//    site/source/docs/api_reference/preamble.js.rst
// A prebuilt local version of the documentation is available at:
//    site/build/text/docs/api_reference/preamble.js.txt
// You can also build docs locally as HTML or other formats in site/
// An online HTML version (which may be of a different version of Emscripten)
//    is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html

#if MAIN_MODULE
{{{ makeModuleReceiveWithVar('dynamicLibraries', undefined, '[]') }}}
#endif

{{{ makeModuleReceiveWithVar('wasmBinary') }}}

#if WASM2JS
#if WASM != 2
// WASM == 2 includes wasm2js.js separately.
#include "wasm2js.js"
#endif

if (WebAssembly.isWasm2js) {
  // We don't need to actually download a wasm binary, mark it as present but
  // empty.
  wasmBinary = [];
}
#endif

#if ASSERTIONS && WASM == 1
if (!globalThis.WebAssembly) {
  err('no native wasm support detected');
}
#endif

// Wasm globals

#if SHARED_MEMORY
// For sending to workers.
var wasmModule;
#endif // SHARED_MEMORY

//========================================
// Runtime essentials
//========================================

// whether we are quitting the application. no code should run after this.
// set in exit() and abort()
var ABORT = false;

// set by exit() and abort().  Passed to 'onExit' handler.
// NOTE: This is also used as the process return code in shell environments
// but only when noExitRuntime is false.
var EXITSTATUS;

#if ASSERTIONS || !STRICT
// In STRICT mode, we only define assert() when ASSERTIONS is set.  i.e. we
// don't define it at all in release modes.  This matches the behaviour of
// MINIMAL_RUNTIME.
// TODO(sbc): Make this the default even without STRICT enabled.
/** @type {function(*, string=)} */
function assert(condition, text) {
  if (!condition) {
#if ASSERTIONS
    abort('Assertion failed' + (text ? ': ' + text : ''));
#else
    // This build was created without ASSERTIONS defined.  `assert()` should not
    // ever be called in this configuration but in case there are callers in
    // the wild leave this simple abort() implementation here for now.
    abort(text);
#endif
  }
}
#endif

#if ASSERTIONS
// We used to include malloc/free by default in the past. Show a helpful error in
// builds with assertions.
#if !hasExportedSymbol('malloc')
function _malloc() {
  abort('malloc() called but not included in the build - add `_malloc` to EXPORTED_FUNCTIONS');
}
#endif // malloc
#if !hasExportedSymbol('free')
function _free() {
  // Show a helpful error since we used to include free by default in the past.
  abort('free() called but not included in the build - add `_free` to EXPORTED_FUNCTIONS');
}
#endif // free
#endif // ASSERTIONS

/**
 * Indicates whether filename is delivered via file protocol (as opposed to http/https)
 * @noinline
 */
var isFileURI = (filename) => filename.startsWith('file://');

#include "runtime_common.js"

#if ASSERTIONS
assert(globalThis.Int32Array && globalThis.Float64Array && Int32Array.prototype.subarray && Int32Array.prototype.set,
       'JS engine does not provide full typed array support');
#endif

#if MAIN_MODULE
var __RELOC_FUNCS__ = [];
#endif

function preRun() {
#if ASSERTIONS && PTHREADS
  assert(!ENVIRONMENT_IS_PTHREAD); // PThreads reuse the runtime from the main thread.
#endif
#if expectToReceiveOnModule('preRun')
  if (Module['preRun']) {
    if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
    while (Module['preRun'].length) {
      addOnPreRun(Module['preRun'].shift());
    }
  }
#if ASSERTIONS
  consumedModuleProp('preRun');
#endif
#endif
  <<< ATPRERUNS >>>
}

function initRuntime() {
#if RUNTIME_DEBUG
  dbg('initRuntime');
#endif
#if ASSERTIONS
  assert(!runtimeInitialized);
#endif
  runtimeInitialized = true;

#if WASM_WORKERS
  if (ENVIRONMENT_IS_WASM_WORKER) return _wasmWorkerInitializeRuntime();
#endif

#if PTHREADS
  if (ENVIRONMENT_IS_PTHREAD) return startWorker();
#endif

#if STACK_OVERFLOW_CHECK >= 2
  setStackLimits();
#endif

#if STACK_OVERFLOW_CHECK
  checkStackCookie();
#endif

#if MAIN_MODULE
  callRuntimeCallbacks(__RELOC_FUNCS__);
#endif

  <<< ATINITS >>>

#if hasExportedSymbol('__wasm_call_ctors')
#if WASM_ESM_INTEGRATION
  ___wasm_call_ctors();
#else
  wasmExports['__wasm_call_ctors']();
#endif
#if RUNTIME_DEBUG
  dbg('done __wasm_call_ctors');
#endif
#endif

  <<< ATPOSTCTORS >>>
#if RUNTIME_DEBUG
  dbg('done ATPOSTCTORS');
#endif
}

#if HAS_MAIN
function preMain() {
#if STACK_OVERFLOW_CHECK
  checkStackCookie();
#endif
  <<< ATMAINS >>>
}
#endif

#if EXIT_RUNTIME

#if ASSERTIONS
var runtimeExiting = false;
#endif

function exitRuntime() {
#if RUNTIME_DEBUG
  dbg('exitRuntime');
#endif
#if ASSERTIONS
  assert(!runtimeExited);
  assert(!runtimeExiting, 'Re-entrant call to exitRuntime()! This can happen if an atexit() registered callback throws an exception.');
  runtimeExiting = true;
#if PTHREADS || WASM_WORKERS
  assert(!{{{ ENVIRONMENT_IS_WORKER_THREAD() }}}, 'exitRuntime() should only be called from the main thread');
#endif
#endif
#if ASYNCIFY == 1 && ASSERTIONS
  // ASYNCIFY cannot be used once the runtime starts shutting down.
  Asyncify.state = Asyncify.State.Disabled;
#endif
#if STACK_OVERFLOW_CHECK
  checkStackCookie();
#endif
#if !STANDALONE_WASM
  ___funcs_on_exit(); // Native atexit() functions
#endif
  <<< ATEXITS >>>
#if PTHREADS
  PThread.terminateRuntime();
#endif
  runtimeExited = true;
}
#endif

function postRun() {
#if STACK_OVERFLOW_CHECK
  checkStackCookie();
#endif
  {{{ runIfWorkerThread('return;') }}} // PThreads reuse the runtime from the main thread.

#if expectToReceiveOnModule('postRun')
  if (Module['postRun']) {
    if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
    while (Module['postRun'].length) {
      addOnPostRun(Module['postRun'].shift());
    }
  }
#if ASSERTIONS
  consumedModuleProp('postRun');
#endif
#endif

  <<< ATPOSTRUNS >>>
}

/**
 * @param {string|number=} what
 */
function abort(what) {
#if expectToReceiveOnModule('onAbort')
  Module['onAbort']?.(what);
#endif

  what = `Aborted(${what})`;
  // TODO(sbc): Should we remove printing and leave it up to whoever
  // catches the exception?
  err(what);

  ABORT = true;

#if ASSERTIONS == 0
  what += '. Build with -sASSERTIONS for more info.';
#elif ASYNCIFY == 1
  if (what.search(/RuntimeError: [Uu]nreachable/) >= 0) {
    what += '. "unreachable" may be due to ASYNCIFY_STACK_SIZE not being large enough (try increasing it)';
  }
#endif // ASSERTIONS

  // Use a wasm runtime error, because a JS error might be seen as a foreign
  // exception, which means we'd run destructors on it. We need the error to
  // simply make the program stop.
  // FIXME This approach does not work in Wasm EH because it currently does not assume
  // all RuntimeErrors are from traps; it decides whether a RuntimeError is from
  // a trap or not based on a hidden field within the object. So at the moment
  // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that
  // allows this in the wasm spec.

  // Suppress closure compiler warning here. Closure compiler's builtin extern
  // definition for WebAssembly.RuntimeError claims it takes no arguments even
  // though it can.
  // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed.
#if WASM_EXCEPTIONS == 1
  // See above, in the meantime, we resort to wasm code for trapping.
  //
  // In case abort() is called before the module is initialized, wasmExports
  // and its exported '__trap' function is not available, in which case we throw
  // a RuntimeError.
  //
  // We trap instead of throwing RuntimeError to prevent infinite-looping in
  // Wasm EH code (because RuntimeError is considered as a foreign exception and
  // caught by 'catch_all'), but in case throwing RuntimeError is fine because
  // the module has not even been instantiated, even less running.
  if (runtimeInitialized) {
    ___trap();
  }
#endif
  /** @suppress {checkTypes} */
  var e = new WebAssembly.RuntimeError(what);

#if MODULARIZE
  readyPromiseReject?.(e);
#endif
  // Throw the error whether or not MODULARIZE is set because abort is used
  // in code paths apart from instantiation where an exception is expected
  // to be thrown when abort is called.
  throw e;
}

#if ASSERTIONS && !('$FS' in addedLibraryItems)
// show errors on likely calls to FS when it was not included
function fsMissing() {
  abort('Filesystem support (FS) was not included. The problem is that you are using files from JS, but files were not used from C/C++, so filesystem support was not auto-included. You can force-include filesystem support with -sFORCE_FILESYSTEM');
}
var FS = {
  init: fsMissing,
  createDataFile: fsMissing,
  createPreloadedFile: fsMissing,
  createLazyFile: fsMissing,
  open: fsMissing,
  mkdev: fsMissing,
  registerDevice:  fsMissing,
  analyzePath: fsMissing,
  ErrnoError: fsMissing,
};
{{{
addAtModule(`
Module['FS_createDataFile'] = FS.createDataFile;
Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
`);
}}}
#endif

#if ASSERTIONS
function createExportWrapper(name, nargs) {
  return (...args) => {
    assert(runtimeInitialized, `native function \`${name}\` called before runtime initialization`);
#if EXIT_RUNTIME
    assert(!runtimeExited, `native function \`${name}\` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)`);
#endif
    var f = wasmExports[name];
    assert(f, `exported native function \`${name}\` not found`);
    // Only assert for too many arguments. Too few can be valid since the missing arguments will be zero filled.
    assert(args.length <= nargs, `native function \`${name}\` called with ${args.length} args but expects ${nargs}`);
    return f(...args);
  };
}
#endif

#if ABORT_ON_WASM_EXCEPTIONS
// `abortWrapperDepth` counts the recursion level of the wrapper function so
// that we only handle exceptions at the top level letting the exception
// mechanics work uninterrupted at the inner level.  Additionally,
// `abortWrapperDepth` is also manually incremented in callMain so that we know
// to ignore exceptions from there since they're handled by callMain directly.
var abortWrapperDepth = 0;

function makeAbortWrapper(original) {
  return (...args) => {
    // Don't allow this function to be called if we're aborted!
    if (ABORT) {
      throw new Error('program has already aborted!');
    }

    abortWrapperDepth++;
    try {
      return original(...args);
    } catch (e) {
      if (
        ABORT // rethrow exception if abort() was called in the original function call above
        || abortWrapperDepth > 1 // rethrow exceptions not caught at the top level if exception catching is enabled; rethrow from exceptions from within callMain
#if SUPPORT_LONGJMP == 'emscripten' // Rethrow longjmp if enabled
        || e instanceof EmscriptenSjLj
#endif
        || e === 'unwind'
      ) {
        throw e;
      }

      abort('unhandled exception: ' + [e, e.stack]);
    }
    finally {
      abortWrapperDepth--;
    }
  }
}

// Instrument all the exported functions to:
// - abort if an unhandled exception occurs
// - throw an exception if someone tries to call them after the program has aborted
// See settings.ABORT_ON_WASM_EXCEPTIONS for more info.
function instrumentWasmExportsWithAbort(exports) {
  // Override the exported functions with the wrappers and copy over any other symbols
  var instExports = {};
  for (var name in exports) {
    var original = exports[name];
    if (typeof original == 'function') {
      instExports[name] = makeAbortWrapper(original);
    } else {
      instExports[name] = original;
    }
  }

  return instExports;
}

function instrumentWasmTableWithAbort() {
  // Override the wasmTable get function to return the wrappers
  var realGet = wasmTable.get;
  var wrapperCache = {};
  wasmTable.get = (i) => {
    var func = realGet.call(wasmTable, {{{ toIndexType('i') }}});
    var cached = wrapperCache[i];
    if (!cached || cached.func !== func) {
      cached = wrapperCache[i] = {
        func,
        wrapper: makeAbortWrapper(func)
      }
    }
    return cached.wrapper;
  };
}
#endif

#if !SOURCE_PHASE_IMPORTS && !WASM_ESM_INTEGRATION
var wasmBinaryFile;

#if WASM2JS && WASM != 2

// When building with wasm2js these 3 functions all no-ops.
function findWasmBinary(file) {}
function getBinarySync(file) {}
function getWasmBinary(file) {}

#else

function findWasmBinary() {
#if SINGLE_FILE && SINGLE_FILE_BINARY_ENCODE && !WASM2JS
  return binaryDecode("<<< WASM_BINARY_DATA >>>");
#elif SINGLE_FILE
  return base64Decode('<<< WASM_BINARY_DATA >>>');
#elif AUDIO_WORKLET || !EXPORT_ES6 // For an Audio Worklet, we cannot use `new URL()`.
  return locateFile('{{{ WASM_BINARY_FILE }}}');
#else

#if ENVIRONMENT_MAY_BE_SHELL
  if (ENVIRONMENT_IS_SHELL) {
    return '{{{ WASM_BINARY_FILE }}}';
  }
#endif

#if ENVIRONMENT_MAY_BE_AUDIO_WORKLET && !AUDIO_WORKLET // AUDIO_WORKLET handled above
  if (ENVIRONMENT_IS_AUDIO_WORKLET) {
    return '{{{ WASM_BINARY_FILE }}}';
  }
#endif

  if (Module['locateFile']) {
    return locateFile('{{{ WASM_BINARY_FILE }}}');
  }

  // Use bundler-friendly `new URL(..., import.meta.url)` pattern; works in browsers too.
  return new URL('{{{ WASM_BINARY_FILE }}}', import.meta.url).href;

#endif
}

function getBinarySync(file) {
#if SINGLE_FILE && SINGLE_FILE_BINARY_ENCODE
  return file;
#else
#if SINGLE_FILE
  if (ArrayBuffer.isView(file)) {
    return file;
  }
#endif
#if expectToReceiveOnModule('wasmBinary') || WASM2JS
  if (file == wasmBinaryFile && wasmBinary) {
    return new Uint8Array(wasmBinary);
  }
#endif
  if (readBinary) {
    return readBinary(file);
  }
  // Throwing a plain string here, even though it not normally advisable since
  // this gets turning into an `abort` in instantiateArrayBuffer.
#if WASM_ASYNC_COMPILATION
  throw 'both async and sync fetching of the wasm failed';
#else
  throw 'sync fetching of the wasm failed: you can preload it to Module["wasmBinary"] manually, or emcc.py will do that for you when generating HTML (but not JS)';
#endif
#endif
}

async function getWasmBinary(binaryFile) {
#if !SINGLE_FILE
  // If we don't have the binary yet, load it asynchronously using readAsync.
  if (!wasmBinary) {
    // Fetch the binary using readAsync
    try {
      var response = await readAsync(binaryFile);
      return new Uint8Array(response);
    } catch {
      // Fall back to getBinarySync below;
    }
  }
#endif

  // Otherwise, getBinarySync should be able to get it synchronously
  return getBinarySync(binaryFile);
}
#endif

#if SPLIT_MODULE
{{{ makeModuleReceiveWithVar('loadSplitModule', undefined, JSPI ? '(secondaryFile, imports) => instantiateAsync(null, secondaryFile, imports)' : 'instantiateSync') }}}
var splitModuleProxyHandler = {
  get(target, moduleName, receiver) {
    if (moduleName.startsWith('placeholder')) {
      let secondaryFile;
      if (moduleName == 'placeholder') { // old format
        secondaryFile = wasmBinaryFile.slice(0, -5) + '.deferred.wasm';
      } else { // new format
        let moduleID = moduleName.split('.')[1];
        secondaryFile = wasmBinaryFile.slice(0, -5) + '.' + moduleID + '.wasm';
      }
      return new Proxy({}, {
        get(target, base, receiver) {
          let ret = {{{ asyncIf(ASYNCIFY == 2) }}} (...args) => {
#if RUNTIME_DEBUG
            dbg(`placeholder function called: ${base}`);
#endif
            var imports = {'primary': wasmRawExports};
            // Replace '.wasm' suffix with '.deferred.wasm'.
            {{{ awaitIf(ASYNCIFY == 2) }}}loadSplitModule(secondaryFile, imports, base);
#if RUNTIME_DEBUG
            dbg('instantiated deferred module, continuing');
#endif
            return wasmTable.get({{{ toIndexType('base') }}})(...args);
          };
#if JSPI
          return new WebAssembly.Suspending(ret);
#else
          return ret;
#endif
        }
      });
    }
    return target[moduleName];
  }
};
#endif

#if SPLIT_MODULE || !WASM_ASYNC_COMPILATION
function instantiateSync(file, info) {
  var module;
  var binary = getBinarySync(file);
#if NODE_CODE_CACHING
  if (ENVIRONMENT_IS_NODE) {
    var v8 = require('node:v8');
    // Include the V8 version in the cache name, so that we don't try to
    // load cached code from another version, which fails silently (it seems
    // to load ok, but we do actually recompile the binary every time).
    var cachedCodeFile = '{{{ WASM_BINARY_FILE }}}.' + v8.cachedDataVersionTag() + '.cached';
    cachedCodeFile = locateFile(cachedCodeFile);
    var hasCached = fs.existsSync(cachedCodeFile);
    if (hasCached) {
#if RUNTIME_DEBUG
      dbg('NODE_CODE_CACHING: loading module');
#endif
      try {
        module = v8.deserialize(fs.readFileSync(cachedCodeFile));
      } catch (e) {
        err(`NODE_CODE_CACHING: failed to deserialize, bad cache file? (${cachedCodeFile})`);
        // Save the new compiled code when we have it.
        hasCached = false;
      }
    }
  }
  module ||= new WebAssembly.Module(binary);
  if (ENVIRONMENT_IS_NODE && !hasCached) {
#if RUNTIME_DEBUG
    dbg('NODE_CODE_CACHING: saving module');
#endif
    fs.writeFileSync(cachedCodeFile, v8.serialize(module));
  }
#else // NODE_CODE_CACHING
  module = new WebAssembly.Module(binary);
#endif // NODE_CODE_CACHING
  var instance = new WebAssembly.Instance(module, info);
  return [instance, module];
}
#endif

#if WASM_ASYNC_COMPILATION
async function instantiateArrayBuffer(binaryFile, imports) {
  try {
    var binary = await getWasmBinary(binaryFile);
    var instance = await WebAssembly.instantiate(binary, imports);
    return instance;
  } catch (reason) {
    err(`failed to asynchronously prepare wasm: ${reason}`);
#if WASM == 2
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
    if (globalThis.location) {
#endif
      // WebAssembly compilation failed, try running the JS fallback instead.
      var search = location.search;
      if (search.indexOf('_rwasm=0') < 0) {
        // Reload the page with the `_rwasm=0` argument
        location.href += (search ? search + '&' : '?') + '_rwasm=0';
        // Return a promise that never resolves.  We don't want to
        // call abort below, or return an error to our caller.
        return new Promise(() => {});
      }
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
    }
#endif
#endif // WASM == 2

#if ASSERTIONS
    // Warn on some common problems.
    if (isFileURI(binaryFile)) {
      err(`warning: Loading from a file URI (${binaryFile}) is not supported in most browsers. See https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-run-a-local-webserver-for-testing-why-does-my-program-stall-in-downloading-or-preparing`);
    }
#endif
    abort(reason);
  }
}

async function instantiateAsync(binary, binaryFile, imports) {
#if !SINGLE_FILE
  if (!binary
#if MIN_SAFARI_VERSION < 150000
      // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming
      && WebAssembly.instantiateStreaming
#endif
#if ENVIRONMENT_MAY_BE_WEBVIEW
      // Don't use streaming for file:// delivered objects in a webview, fetch them synchronously.
      && !isFileURI(binaryFile)
#endif
#if ENVIRONMENT_MAY_BE_NODE
      // Avoid instantiateStreaming() on Node.js environment for now, as while
      // Node.js v18.1.0 implements it, it does not have a full fetch()
      // implementation yet.
      //
      // Reference:
      //   https://github.com/emscripten-core/emscripten/pull/16917
      && !ENVIRONMENT_IS_NODE
#endif
#if ENVIRONMENT_MAY_BE_SHELL
      // Shell environments don't have fetch.
      && !ENVIRONMENT_IS_SHELL
#endif
     ) {
    try {
      var response = fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}});
      var instantiationResult = await WebAssembly.instantiateStreaming(response, imports);
      return instantiationResult;
    } catch (reason) {
      // We expect the most common failure cause to be a bad MIME type for the binary,
      // in which case falling back to ArrayBuffer instantiation should work.
      err(`wasm streaming compile failed: ${reason}`);
      err('falling back to ArrayBuffer instantiation');
      // fall back of instantiateArrayBuffer below
    };
  }
#endif
  return instantiateArrayBuffer(binaryFile, imports);
}
#endif // WASM_ASYNC_COMPILATION
#endif // SOURCE_PHASE_IMPORTS

#if !WASM_ESM_INTEGRATION
function getWasmImports() {
#if PTHREADS || WASM_WORKERS || (IMPORTED_MEMORY && MODULARIZE == 'instance')
  assignWasmImports();
#endif
#if ASYNCIFY && (ASSERTIONS || ASYNCIFY == 2)
  // instrumenting imports is used in asyncify in two ways: to add assertions
  // that check for proper import use, and for JSPI we use them to set up
  // the Promise API on the import side.
#if PTHREADS
  // In pthreads builds getWasmImports is called more than once but we only
  // and the instrument the imports once.
  if (!wasmImports.__instrumented) {
    wasmImports.__instrumented = true;
    Asyncify.instrumentWasmImports(wasmImports);
  }
#else
  Asyncify.instrumentWasmImports(wasmImports);
#endif
#endif
  // prepare imports
#if MAIN_MODULE
  var GOTProxyHandler = new Proxy(new Set({{{ JSON.stringify(Array.from(WEAK_IMPORTS)) }}}), GOTHandler);
#endif
  var imports = {
#if MINIFY_WASM_IMPORTED_MODULES
    'a': wasmImports,
#else // MINIFY_WASM_IMPORTED_MODULES
    'env': wasmImports,
    '{{{ WASI_MODULE_NAME }}}': wasmImports,
#endif // MINIFY_WASM_IMPORTED_MODULES
#if MAIN_MODULE
    'GOT.mem': GOTProxyHandler,
    'GOT.func': GOTProxyHandler,
#endif
  };
#if SPLIT_MODULE
  imports = new Proxy(imports, splitModuleProxyHandler);
#endif
  return imports;
}

// Create the wasm instance.
// Receives the wasm imports, returns the exports.
{{{ asyncIf(WASM_ASYNC_COMPILATION) }}}function createWasm() {
  // Load the wasm module and create an instance of using native support in the JS engine.
  // handle a generated wasm instance, receiving its exports and
  // performing other necessary setup
  /** @param {WebAssembly.Module=} module*/
  function receiveInstance(instance, module) {
#if RUNTIME_DEBUG
    dbg('receiveInstance')
#endif
    wasmExports = instance.exports;

#if MAIN_MODULE
    var origExports = wasmExports;
#endif
#if SPLIT_MODULE
    wasmRawExports = wasmExports;
#endif

#if ASYNCIFY
    wasmExports = Asyncify.instrumentWasmExports(wasmExports);
#endif

#if MAIN_MODULE
    mergeLibSymbols(wasmExports, 'main')
    var metadata = getDylinkMetadata(module);
#if AUTOLOAD_DYLIBS
    if (metadata.neededDynlibs) {
      dynamicLibraries = metadata.neededDynlibs.concat(dynamicLibraries);
    }
#endif
#endif

#if ABORT_ON_WASM_EXCEPTIONS
    wasmExports = instrumentWasmExportsWithAbort(wasmExports);
#endif

#if MEMORY64 || CAN_ADDRESS_2GB
    wasmExports = applySignatureConversions(wasmExports);
#endif

#if PTHREADS
#if MAIN_MODULE
    registerTLSInit(wasmExports['_emscripten_tls_init'], instance.exports, metadata);
#else
    registerTLSInit(wasmExports['_emscripten_tls_init']);
#endif
#endif

#if hasExportedSymbol('__wasm_apply_data_relocs')
    __RELOC_FUNCS__.push(wasmExports['__wasm_apply_data_relocs']);
#endif

#if RUNTIME_DEBUG
    dbg('assigning exports')
#endif
    assignWasmExports(wasmExports);

#if MAIN_MODULE
    updateGOT(origExports);
#endif

#if EXPORTED_RUNTIME_METHODS.has('wasmExports')
    Module['wasmExports'] = wasmExports;
#endif

#if MAIN_MODULE
#if '$LDSO' in addedLibraryItems
    LDSO.init();
#endif
    loadDylibs();
#endif

#if ABORT_ON_WASM_EXCEPTIONS
    instrumentWasmTableWithAbort();
#endif

#if !IMPORTED_MEMORY
    updateMemoryViews();
#endif

#if PTHREADS || WASM_WORKERS
    // We now have the Wasm module loaded up, keep a reference to the compiled module so we can post it to the workers.
    wasmModule = module;
#endif
#if WASM_ASYNC_COMPILATION && !MODULARIZE
    removeRunDependency('wasm-instantiate');
#endif
    return wasmExports;
  }
#if WASM_ASYNC_COMPILATION && !MODULARIZE
  addRunDependency('wasm-instantiate');
#endif

  // Prefer streaming instantiation if available.
#if WASM_ASYNC_COMPILATION
#if ASSERTIONS
  // Async compilation can be confusing when an error on the page overwrites Module
  // (for example, if the order of elements is wrong, and the one defining Module is
  // later), so we save Module and check it later.
  var trueModule = Module;
#endif
  function receiveInstantiationResult(result) {
    // 'result' is a ResultObject object which has both the module and instance.
    // receiveInstance() will swap in the exports (to Module.asm) so they can be called
#if ASSERTIONS
    assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?');
    trueModule = null;
#endif
#if SHARED_MEMORY || MAIN_MODULE
    return receiveInstance(result['instance'], result['module']);
#else
    // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line.
    // When the regression is fixed, can restore the above PTHREADS-enabled path.
    return receiveInstance(result['instance']);
#endif
  }
#endif // WASM_ASYNC_COMPILATION

  var info = getWasmImports();

#if expectToReceiveOnModule('instantiateWasm')
  // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
  // to manually instantiate the Wasm module themselves. This allows pages to
  // run the instantiation parallel to any other async startup actions they are
  // performing.
  // Also pthreads and wasm workers initialize the wasm instance through this
  // path.
  if (Module['instantiateWasm']) {
    return new Promise((resolve, reject) => {
#if ASSERTIONS
      try {
#endif
        Module['instantiateWasm'](info, (inst, mod) => {
          resolve(receiveInstance(inst, mod));
        });
#if ASSERTIONS
      } catch(e) {
        err(`Module.instantiateWasm callback failed with error: ${e}`);
        reject(e);
      }
#endif
    });
  }
#endif

#if PTHREADS || WASM_WORKERS
  if ({{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) {
    // Instantiate from the module that was received via postMessage from
    // the main thread. We can just use sync instantiation in the worker.
#if ASSERTIONS
    assert(wasmModule, "wasmModule should have been received via postMessage");
#endif
    var instance = new WebAssembly.Instance(wasmModule, getWasmImports());
    return receiveInstance(instance, wasmModule);
  }
#endif

#if SOURCE_PHASE_IMPORTS
  var instance = await WebAssembly.instantiate(wasmModule, info);
  var exports = receiveInstantiationResult({instance, 'module':wasmModule});
  return exports;
#else
  wasmBinaryFile ??= findWasmBinary();
#if WASM_ASYNC_COMPILATION
#if RUNTIME_DEBUG
  dbg('asynchronously preparing wasm');
#endif
  var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info);
  var exports = receiveInstantiationResult(result);
  return exports;
#else // WASM_ASYNC_COMPILATION
  var result = instantiateSync(wasmBinaryFile, info);
#if PTHREADS || MAIN_MODULE
  return receiveInstance(result[0], result[1]);
#else
  // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193,
  // the above line no longer optimizes out down to the following line.
  // When the regression is fixed, we can remove this if/else.
  return receiveInstance(result[0]);
#endif
#endif // WASM_ASYNC_COMPILATION
#endif // SOURCE_PHASE_IMPORTS
}
#endif // WASM_ESM_INTEGRATION

#if !WASM_BIGINT
// Globals used by JS i64 conversions (see makeSetValue)
var tempDouble;
var tempI64;
#endif

#if RETAIN_COMPILER_SETTINGS
var compilerSettings = {{{ JSON.stringify(makeRetainedCompilerSettings()) }}} ;

function getCompilerSetting(name) {
  if (!(name in compilerSettings)) return 'invalid compiler setting: ' + name;
  return compilerSettings[name];
}
#endif // RETAIN_COMPILER_SETTINGS

#if MAIN_MODULE && ASYNCIFY
// With MAIN_MODULE + ASYNCIFY the normal method of placing stub functions in
// wasmImports for as-yet-undefined symbols doesn't work since ASYNCIFY then
// wraps these stub functions and we can't then replace them directly.  Instead
// the stub functions call into `asyncifyStubs` which gets populated by the
// dynamic linker as symbols are loaded.
var asyncifyStubs = {};
#endif
