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

#if LOAD_SOURCE_MAP
#include "source_map_support.js"
#endif

// === Auto-generated postamble setup entry stuff ===
#if HAS_MAIN // Only if user is exporting a C main(), we will generate a run() function that can be used to launch main.

#if EXIT_RUNTIME
function exitRuntime(ret) {
  <<< ATEXITS >>>
#if PTHREADS
  PThread.terminateRuntime();
#endif

#if ASSERTIONS
  runtimeExited = true;
#endif

  _proc_exit(ret);

#if STACK_OVERFLOW_CHECK
  checkStackCookie();
#endif
}
#endif

{{{ globalThis.argc_argv = function(condition) {
    if (!MAIN_READS_PARAMS) return '';
    return `argc, ${to64('argv')}`;
  }
  globalThis.HEAPptr = MEMORY64 ? 'HEAPU64' : 'HEAPU32';
  null;
}}}

function run() {
#if MEMORYPROFILER
  emscriptenMemoryProfiler.onPreloadComplete();
#endif

  <<< ATMAINS >>>

#if MAIN_READS_PARAMS
  var args =
#if ENVIRONMENT_MAY_BE_NODE
    // Remove Node.js executable name from argc/argv to emulate C/C++ standards.
    ENVIRONMENT_IS_NODE ? process.argv.slice(1) :
#endif
    [location.href.split('?')[0], ...location.search.slice(1).split('&').map(decodeURIComponent)];

  // C standard (C17 §5.1.2.2.1/5): "The parameters argc and argv and the
  // strings pointed to by the argv array shall be modifiable by the program,
  // and retain their last-stored values between program startup and program
  // termination."
  // -> in particular this means that the stackAlloc() that we do below shall
  // never be undone, and ideally should no longer be considered to be part of
  // the stack. Though currently it will be. (TODO: figure if this will ever be
  // a problem)
  var arg,
    argc = args.length,
    argv = stackAlloc(argc * {{{ POINTER_SIZE }}} + {{{ POINTER_SIZE }}}),
    argvIndex = argv / {{{ POINTER_SIZE }}};

  for (arg of args) {{{ HEAPptr }}}[argvIndex++] = {{{ to64('stringToUTF8OnStack(arg)') }}};

  // C standard (C17 §5.1.2.2.1/2): "argv[argc] shall be a null pointer."
  {{{ HEAPptr }}}[argvIndex] = {{{ to64(0) }}};

#endif

#if PROXY_TO_PTHREAD
  // User requested the PROXY_TO_PTHREAD option, so call a stub main which
  // pthread_create()s a new thread that will call the user's real main() for
  // the application.
  __emscripten_proxy_main({{{ argc_argv() }}});
#elif ASYNCIFY == 2 && EXIT_RUNTIME
  // In JSPI-enabled build mode, the main() function will return a Promise,
  // which resolves to the process exit code.
  _main({{{ argc_argv() }}}).then(exitRuntime);
#elif EXIT_RUNTIME
  // In regular exitRuntime mode, exit with the given return code from main().
  try {
    exitRuntime(_main({{{ argc_argv() }}}));
  } catch(e) {
    var exitCode = e.match(/^exit\((\d+)\)$/);
    if (exitCode) {
#if RUNTIME_DEBUG
      dbg(`main() called ${e}.`); // e.g. "main() called exit(0)."
#endif
#if expectToReceiveOnModule('onExit')
      // Report to Module that the program exited.
      Module['onExit']?.(exitCode[1]|0);
#endif
    } else {
#if RUNTIME_DEBUG
      dbg(`main() threw an exception: ${e}.`);
#endif
      // Some other exception occurred - re-throw it.
      throw e;
    }
  }
#else
  // Run a persistent (never-exiting) application starting at main().
  _main({{{ argc_argv() }}});
#endif 

#if STACK_OVERFLOW_CHECK
  checkStackCookie();
#endif
  <<< ATPOSTRUNS >>>
}
#endif

function initRuntime(wasmExports) {
#if ASSERTIONS || SAFE_HEAP || USE_ASAN || MODULARIZE || PTHREADS
  runtimeInitialized = true;
#endif

#if PTHREADS
  PThread.tlsInitFunctions.push(wasmExports['_emscripten_tls_init']);
  if (ENVIRONMENT_IS_PTHREAD) return;
#endif

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

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

  <<< ATINITS >>>

#if hasExportedSymbol('__wasm_call_ctors')
  wasmExports['__wasm_call_ctors']();
#endif

  <<< ATPOSTCTORS >>>
}

// Initialize wasm (asynchronous)

#if MODULARIZE || AUDIO_WORKLET
var instantiatePromise;
#endif

#if SINGLE_FILE && SINGLE_FILE_BINARY_ENCODE && !WASM2JS
Module['wasm'] = binaryDecode("<<< WASM_BINARY_DATA >>>");
#elif SINGLE_FILE && WASM == 1 && !WASM2JS
Module['wasm'] = base64Decode('<<< WASM_BINARY_DATA >>>');
#endif

#if LibraryManager.has('libexports.js')
// emscripten_get_exported_function() requires wasmExports to be defined in the
// outer scope.
var wasmExports;
#endif

#if PTHREADS || WASM_WORKERS
var wasmModule;

function loadModule() {
  assignWasmImports();
#endif

#if ASYNCIFY
Asyncify.instrumentWasmImports(wasmImports);
#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 MINIMAL_RUNTIME_STREAMING_WASM_INSTANTIATION
{{{
#if EXPORT_ES6 && !ENVIRONMENT_MAY_BE_AUDIO_WORKLET
const moduleUrl = `new URL('${TARGET_BASENAME}.wasm', import.meta.url)`;
#elif !EXPORT_ES6 || AUDIO_WORKLET
const moduleUrl = `'${TARGET_BASENAME}.wasm'`;
#else
const moduleUrl = `ENVIRONMENT_IS_AUDIO_WORKLET ? '${TARGET_BASENAME}.wasm' : new URL('${TARGET_BASENAME}.wasm', import.meta.url)`;
#endif
}}}
// https://caniuse.com/#feat=wasm and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming
#if MIN_SAFARI_VERSION < 150000 || ENVIRONMENT_MAY_BE_NODE
#if ASSERTIONS && !WASM2JS
// Module['wasm'] should contain a typed array of the Wasm object data, or a
// precompiled WebAssembly Module.
assert(WebAssembly.instantiateStreaming || Module['wasm'], 'Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM');
#endif
#if MODULARIZE || AUDIO_WORKLET
instantiatePromise =
#endif
(WebAssembly.instantiateStreaming
#if ENVIRONMENT_MAY_BE_NODE
  // Node's fetch API cannot be used for local files, so we cannot use instantiateStreaming
  && !ENVIRONMENT_IS_NODE
#endif
  ? WebAssembly.instantiateStreaming(fetch({{{ moduleUrl }}}), imports)
  : WebAssembly.instantiate(Module['wasm'], imports)).then((output) => {
#else
#if MODULARIZE || AUDIO_WORKLET
instantiatePromise =
#endif
WebAssembly.instantiateStreaming(fetch({{{ moduleUrl }}}), imports).then((output) => {
#endif

#else // Non-streaming instantiation
#if ASSERTIONS && !WASM2JS
// Module['wasm'] should contain a typed array of the Wasm object data, or a
// precompiled WebAssembly Module.
assert(Module['wasm'], 'Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM');
#endif

<<< ATMODULES >>>

{{{ exportJSSymbols() }}}

// Add missingProperties supression here because closure compiler doesn't know that
// WebAssembly.instantiate is polymorphic in its return value.
#if MODULARIZE || AUDIO_WORKLET
instantiatePromise =
#endif
WebAssembly.instantiate(Module['wasm'], imports).then(/** @suppress {missingProperties} */ (output) => {
#endif

#if !LibraryManager.has('libexports.js') && ASYNCIFY != 1
  // If not using the emscripten_get_exported_function() API, keep the
  // `wasmExports` variable in local scope to this instantiate function to save
  // code size.  (otherwise access it without to export it to outer scope)
  var
#endif
  // WebAssembly instantiation API gotcha: if Module['wasm'] above was a typed
  // array, then the output object will have an output.instance and
  // output.module objects. But if Module['wasm'] is an already compiled
  // WebAssembly module, then output is the WebAssembly instance itself.
  // Depending on the build mode, Module['wasm'] can mean a different thing.
#if PTHREADS || WASM_WORKERS
  // In pthreads and wasm workers, Module['wasm'] is a compiled
  // WebAssembly.Module. In that case, 'output' is a WebAssembly.Instance.
  // In main thread, Module['wasm'] is either a typed array or a fetch stream.
  // In that case, 'output.instance' is the WebAssembly.Instance.
  wasmExports = (output.instance || output).exports;
  // Stash the Wasm module for future worker creation.
  wasmModule = output.module || Module['wasm'];
#elif MINIMAL_RUNTIME_STREAMING_WASM_COMPILATION
  // In MINIMAL_RUNTIME_STREAMING_WASM_COMPILATION mode, Module['wasm'] is the
  // compiled module so we just get the instance back.
  wasmExports = output.exports;
#else
  wasmExports = output.instance.exports;
#endif

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

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

  assignWasmExports(wasmExports);

#if !IMPORTED_MEMORY
  updateMemoryViews();
#endif
  <<< ATPRERUNS >>>

  initRuntime(wasmExports);

{{{ function waitOnStartupPromisesAndEmitReady() {
  var promises = [];
  if (PTHREADS && PTHREAD_POOL_SIZE) {
    promises.push('PThread.loadWasmModuleToAllWorkers()');
  }
  if (LOAD_SOURCE_MAP) {
    promises.push('getSourceMapAsync().then(json=>{receiveSourceMapJSON(json)})');
  }
  if (promises.length == 0) {
    return 'ready();'
  } else if (promises.length == 1) {
    return `${promises[0]}.then(ready);`;
  } else {
    return `Promise.all(${', '.join(promises)}).then(ready);`
  }
}
null;
}}}

#if PTHREADS && PTHREAD_POOL_SIZE && PTHREAD_POOL_DELAY_LOAD
  // In PTHREAD_POOL_DELAY_LOAD mode, we kick off loading Wasm Module to all
  // PThread Workers, but do not wait on it.
  PThread.loadWasmModuleToAllWorkers();
#endif

  return {{{ waitOnStartupPromisesAndEmitReady(); }}}

}

#if WASM == 2
, (error) => {
#if ASSERTIONS
  console.error(error);
#endif

#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) {
      location.href += (search ? search + '&' : '?') + '_rwasm=0';
    }
#if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL
  }
#endif
}
#endif // WASM == 2
);

#if PTHREADS || WASM_WORKERS
}

// When running in a background thread we delay module loading until we have
{{{ runIfMainThread('loadModule();') }}}
#endif

#if MODULARIZE
await instantiatePromise;
#endif
