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

#include "runtime_stack_check.js"
#include "runtime_exceptions.js"
#include "runtime_debug.js"

#if SAFE_HEAP
#include "runtime_safe_heap.js"
#endif

#if SHARED_MEMORY && ALLOW_MEMORY_GROWTH && !GROWABLE_ARRAYBUFFERS
// Support for growable heap + pthreads, where the buffer may change, so JS views
// must be updated.
function growMemViews() {
  // `updateMemoryViews` updates all the views simultaneously, so it's enough to check any of them.
  if (wasmMemory.buffer != HEAP8.buffer) {
    updateMemoryViews();
  }
}
#endif

#if USE_ASAN
#include "runtime_asan.js"
#endif

#if SINGLE_FILE && SINGLE_FILE_BINARY_ENCODE && !WASM2JS
#include "binaryDecode.js"
#endif

#if (PTHREADS || WASM_WORKERS) && (ENVIRONMENT_MAY_BE_NODE && !WASM_ESM_INTEGRATION)
if (ENVIRONMENT_IS_NODE && {{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) {
  // Create as web-worker-like an environment as we can.
  globalThis.self = globalThis;
  var parentPort = worker_threads.parentPort;
  // Deno and Bun already have `postMessage` defined on the global scope and
  // deliver messages to `globalThis.onmessage`, so we must not duplicate that
  // behavior here if `postMessage` is already present.
  if (!globalThis.postMessage) {
    parentPort.on('message', (msg) => globalThis.onmessage?.({ data: msg }));
    globalThis.postMessage = (msg) => parentPort.postMessage(msg);
  }
  // Node.js Workers do not pass postMessage()s and uncaught exception events to the parent
  // thread necessarily in the same order where they were generated in sequential program order.
  // See https://github.com/nodejs/node/issues/59617
  // To remedy this, capture all uncaughtExceptions in the Worker, and sequentialize those over
  // to the same postMessage pipe that other messages use.
  process.on("uncaughtException", (err) => {
#if PTHREADS_DEBUG
    dbg(`uncaughtException on worker thread: ${err.message}`);
#endif
    postMessage({ cmd: {{{ CMD_UNCAUGHT_EXN }}}, error: err });
    // Also shut down the Worker to match the same semantics as if this uncaughtException
    // handler was not registered.
    // (n.b. this will not shut down the whole Node.js app process, but just the Worker)
    process.exit(1);
  });
}
#endif // (PTHREADS || WASM_WORKERS) && (ENVIRONMENT_MAY_BE_NODE && !WASM_ESM_INTEGRATION)

#if PTHREADS
#include "runtime_pthread.js"
#endif

#if WASM_WORKERS
#include "wasm_worker.js"
#endif

#if AUDIO_WORKLET
#include "audio_worklet.js"
#endif

// Memory management

#if SUPPORT_BIG_ENDIAN
/** @type {!DataView} */
var HEAP_DATA_VIEW;
#endif

#if !MINIMAL_RUNTIME || ASSERTIONS || SAFE_HEAP || USE_ASAN || MODULARIZE || PTHREADS
var runtimeInitialized = false;
#endif

#if EXIT_RUNTIME
var runtimeExited = false;
#endif

{{{
  // Helper function to export a heap symbol on the module object,
  // if requested.
  const shouldExportHeap = (x) => {
    let shouldExport = false;
    if (MODULARIZE && EXPORT_ALL) {
      shouldExport = true;
    } else if (EXPORTED_RUNTIME_METHODS.has(x)) {
      shouldExport = true;
    }
    return shouldExport;
  }
  const maybeExportHeap = (x) => {
    if (shouldExportHeap(x) && MODULARIZE != 'instance') {
      return `Module['${x}'] = `;
    }
    return '';
  };
}}}

function updateMemoryViews() {
#if RUNTIME_DEBUG
  dbg(`updateMemoryViews: first=${!HEAP8} size=${wasmMemory.buffer.byteLength}`);
#endif
#if !ALLOW_MEMORY_GROWTH && ASSERTIONS
  // When memory growth is disabled this function should be called exactly once.
  assert(!HEAP8, 'updateMemoryViews should only be called once when ALLOW_MEMORY_GROWTH=0');
#endif
#if GROWABLE_ARRAYBUFFERS
  var b = wasmMemory.toResizableBuffer();
#else
  var b = wasmMemory.buffer;
#endif
  {{{ maybeExportHeap('HEAP8')   }}}HEAP8 = new Int8Array(b);
  {{{ maybeExportHeap('HEAP16')  }}}HEAP16 = new Int16Array(b);
  {{{ maybeExportHeap('HEAPU8')  }}}HEAPU8 = new Uint8Array(b);
  {{{ maybeExportHeap('HEAPU16') }}}HEAPU16 = new Uint16Array(b);
  {{{ maybeExportHeap('HEAP32')  }}}HEAP32 = new Int32Array(b);
  {{{ maybeExportHeap('HEAPU32') }}}HEAPU32 = new Uint32Array(b);
  {{{ maybeExportHeap('HEAPF32') }}}HEAPF32 = new Float32Array(b);
  {{{ maybeExportHeap('HEAPF64') }}}HEAPF64 = new Float64Array(b);
#if WASM_BIGINT
  {{{ maybeExportHeap('HEAP64')  }}}HEAP64 = new BigInt64Array(b);
  {{{ maybeExportHeap('HEAPU64') }}}HEAPU64 = new BigUint64Array(b);
#endif
#if SUPPORT_BIG_ENDIAN
  {{{ maybeExportHeap('HEAP_DATA_VIEW') }}} HEAP_DATA_VIEW = new DataView(b);
  LE_HEAP_UPDATE();
#endif
}

#if IMPORTED_MEMORY
// In non-standalone/normal mode, we create the memory here.
#include "runtime_init_memory.js"
#endif // !IMPORTED_MEMORY && ASSERTIONS

#include "memoryprofiler.js"

#if !DECLARE_ASM_MODULE_EXPORTS
function exportAliases(wasmExports) {
{{{ makeExportAliases() }}}
}
#endif
