diff --git a/eng/native.wasm.targets b/eng/native.wasm.targets
index c72c24ff6df2d1..734349ba2f1d34 100644
--- a/eng/native.wasm.targets
+++ b/eng/native.wasm.targets
@@ -147,14 +147,46 @@
+
+
+
+ <_EmccIncomingModuleJSAPI Include="ENVIRONMENT" />
+ <_EmccIncomingModuleJSAPI Include="arguments" />
+ <_EmccIncomingModuleJSAPI Include="canvas" />
+ <_EmccIncomingModuleJSAPI Include="dynamicLibraries" />
+ <_EmccIncomingModuleJSAPI Include="elementPointerLock" />
+ <_EmccIncomingModuleJSAPI Include="instantiateWasm" />
+ <_EmccIncomingModuleJSAPI Include="locateFile" />
+ <_EmccIncomingModuleJSAPI Include="monitorRunDependencies" />
+ <_EmccIncomingModuleJSAPI Include="noExitRuntime" />
+ <_EmccIncomingModuleJSAPI Include="noInitialRun" />
+ <_EmccIncomingModuleJSAPI Include="onAbort" />
+ <_EmccIncomingModuleJSAPI Include="onExit" />
+ <_EmccIncomingModuleJSAPI Include="onRuntimeInitialized" />
+ <_EmccIncomingModuleJSAPI Include="postRun" />
+ <_EmccIncomingModuleJSAPI Include="preInit" />
+ <_EmccIncomingModuleJSAPI Include="preRun" />
+ <_EmccIncomingModuleJSAPI Include="print" />
+ <_EmccIncomingModuleJSAPI Include="printErr" />
+ <_EmccIncomingModuleJSAPI Include="setStatus" />
+ <_EmccIncomingModuleJSAPI Include="statusMessage" />
+ <_EmccIncomingModuleJSAPI Include="stderr" />
+ <_EmccIncomingModuleJSAPI Include="stdin" />
+ <_EmccIncomingModuleJSAPI Include="stdout" />
+ <_EmccIncomingModuleJSAPI Include="thisProgram" />
+ <_EmccIncomingModuleJSAPI Include="wasm" />
+ <_EmccIncomingModuleJSAPI Include="websocket" />
+
<_EmccExportedRuntimeMethods>@(EmccExportedRuntimeMethod -> '%(Identity)',',')
<_EmccExportedFunctions>@(EmccExportedFunction -> '%(Identity)',',')
+ <_EmccIncomingModuleJSAPIs>@(_EmccIncomingModuleJSAPI -> '%(Identity)',',')
+
diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj
index 710a36801a553b..87f40c18f6ec01 100644
--- a/src/mono/browser/browser.proj
+++ b/src/mono/browser/browser.proj
@@ -208,9 +208,43 @@
+
+
+ <_EmccIncomingModuleJSAPI Include="ENVIRONMENT" />
+ <_EmccIncomingModuleJSAPI Include="arguments" />
+ <_EmccIncomingModuleJSAPI Include="canvas" />
+ <_EmccIncomingModuleJSAPI Include="dynamicLibraries" />
+ <_EmccIncomingModuleJSAPI Include="elementPointerLock" />
+ <_EmccIncomingModuleJSAPI Include="instantiateWasm" />
+ <_EmccIncomingModuleJSAPI Include="locateFile" />
+ <_EmccIncomingModuleJSAPI Include="monitorRunDependencies" />
+ <_EmccIncomingModuleJSAPI Include="noExitRuntime" />
+ <_EmccIncomingModuleJSAPI Include="noInitialRun" />
+ <_EmccIncomingModuleJSAPI Include="onAbort" />
+ <_EmccIncomingModuleJSAPI Include="onExit" />
+ <_EmccIncomingModuleJSAPI Include="onRuntimeInitialized" />
+ <_EmccIncomingModuleJSAPI Include="postRun" />
+ <_EmccIncomingModuleJSAPI Include="preInit" />
+ <_EmccIncomingModuleJSAPI Include="preRun" />
+ <_EmccIncomingModuleJSAPI Include="print" />
+ <_EmccIncomingModuleJSAPI Include="printErr" />
+ <_EmccIncomingModuleJSAPI Include="setStatus" />
+ <_EmccIncomingModuleJSAPI Include="statusMessage" />
+ <_EmccIncomingModuleJSAPI Include="stderr" />
+ <_EmccIncomingModuleJSAPI Include="stdin" />
+ <_EmccIncomingModuleJSAPI Include="stdout" />
+ <_EmccIncomingModuleJSAPI Include="thisProgram" />
+ <_EmccIncomingModuleJSAPI Include="wasm" />
+ <_EmccIncomingModuleJSAPI Include="websocket" />
+
+
+
+ <_EmccIncomingModuleJSAPI Include="wasmMemory" />
+
<_EmccExportedLibraryFunction>"[@(EmccExportedLibraryFunction -> '%27%(Identity)%27', ',')]"
<_EmccExportedRuntimeMethods>"[@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]"
+ <_EmccIncomingModuleJSAPIs>"[@(_EmccIncomingModuleJSAPI -> '%27%(Identity)%27', ',')]"
<_EmccExportedFunctions>@(EmccExportedFunction -> '%(Identity)',',')
33554432
@@ -232,6 +266,8 @@
<_EmccLinkFlags Include="-s FORCE_FILESYSTEM=1" />
<_EmccLinkFlags Condition="'$(_EmccExportedLibraryFunction)' != ''" Include="-s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$(_EmccExportedLibraryFunction)" />
<_EmccLinkFlags Include="-s EXPORTED_RUNTIME_METHODS=$(_EmccExportedRuntimeMethods)" />
+
+ <_EmccLinkFlags Condition="'$(Configuration)' == 'Debug'" Include="-s INCOMING_MODULE_JS_API=$(_EmccIncomingModuleJSAPIs)" />
<_EmccLinkFlags Include="-s EXPORTED_FUNCTIONS=$(_EmccExportedFunctions)" />
<_EmccLinkFlags Include="--source-map-base http://example.com" />
<_EmccLinkFlags Include="-s WASM_BIGINT=1" />
@@ -271,6 +307,7 @@
"WasmOptConfigurationFlags": [@(WasmOptConfigurationFlags -> '%22%(Identity)%22', ',')],
"EmccDefaultExportedFunctions": [@(EmccExportedFunction -> '%22%(Identity)%22', ',')],
"EmccDefaultExportedRuntimeMethods": [@(EmccExportedRuntimeMethod -> '%22%(Identity)%22', ',')],
+ "EmccDefaultIncomingModuleJSAPI": [@(_EmccIncomingModuleJSAPI -> '%22%(Identity)%22', ',')],
"PropertiesThatTriggerRelinking": [
{ "identity": "InvariantTimezone", "defaultValueInRuntimePack": "$(InvariantTimezone)" },
{ "identity": "InvariantGlobalization", "defaultValueInRuntimePack": "$(InvariantGlobalization)" },
diff --git a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
index 9d4dc3b1394726..d586baabf9d99b 100644
--- a/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
+++ b/src/mono/browser/build/BrowserWasmApp.CoreCLR.targets
@@ -112,65 +112,15 @@
TaskFactory="TaskHostFactory"
Condition="'$(WasmAppBuilderTasksAssemblyPath)' != ''" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
@@ -856,6 +806,7 @@
<_EmccExportedRuntimeMethods>"[BROWSER_HOST,@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]"
+ <_EmccIncomingModuleJSAPIs>"[@(_EmccIncomingModuleJSAPI -> '%27%(Identity)%27', ',')]"
<_EmccExportedFunctions>@(EmccExportedFunction -> '%(Identity)',',')
@@ -935,6 +886,8 @@
<_EmccLinkStepArgs Include="-s EXPORTED_RUNTIME_METHODS=$(_EmccExportedRuntimeMethods)" />
+
+ <_EmccLinkStepArgs Condition="'$(Configuration)' == 'Debug'" Include="-s INCOMING_MODULE_JS_API=$(_EmccIncomingModuleJSAPIs)" />
<_EmccLinkStepArgs Include="-s EXPORTED_FUNCTIONS=$(_EmccExportedFunctions)" />
diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets
index 4afa05842060c2..f4b70c287b7d7c 100644
--- a/src/mono/browser/build/BrowserWasmApp.targets
+++ b/src/mono/browser/build/BrowserWasmApp.targets
@@ -313,6 +313,8 @@
+
<_WasmEHLib Condition="'$(WasmEnableExceptionHandling)' == 'true'">libmono-wasm-eh-wasm.a
@@ -325,6 +327,7 @@
<_WasmSIMDLibToExclude Condition="'$(WasmEnableSIMD)' == 'true'">libmono-wasm-nosimd.a
<_EmccExportedLibraryFunction>"[@(EmccExportedLibraryFunction -> '%27%(Identity)%27', ',')]"
<_EmccExportedRuntimeMethods>"[@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]"
+ <_EmccIncomingModuleJSAPIs>"[@(_EmccIncomingModuleJSAPI -> '%27%(Identity)%27', ',')]"
<_EmccExportedFunctions>@(EmccExportedFunction -> '%(Identity)',',')
@@ -373,6 +376,8 @@
<_EmccLinkStepArgs Include="-s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$(_EmccExportedLibraryFunction)" Condition="'$(_EmccExportedLibraryFunction)' != ''" />
<_EmccLinkStepArgs Include="-s EXPORTED_RUNTIME_METHODS=$(_EmccExportedRuntimeMethods)" />
+
+ <_EmccLinkStepArgs Condition="'$(Configuration)' == 'Debug'" Include="-s INCOMING_MODULE_JS_API=$(_EmccIncomingModuleJSAPIs)" />
<_EmccLinkStepArgs Include="-s EXPORTED_FUNCTIONS=$(_EmccExportedFunctions)" />
<_EmccLinkStepArgs Include="$(EmccExtraLDFlags)" />
diff --git a/src/mono/mono/utils/mono-threads-wasm.c b/src/mono/mono/utils/mono-threads-wasm.c
index 9874cb3934e8c3..8151170e0216b2 100644
--- a/src/mono/mono/utils/mono-threads-wasm.c
+++ b/src/mono/mono/utils/mono-threads-wasm.c
@@ -198,7 +198,7 @@ mono_threads_platform_get_stack_bounds (guint8 **staddr, size_t *stsize)
if (G_UNLIKELY (res != 0))
g_error ("%s: pthread_attr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res);
- g_assert (*staddr != NULL);
+ // emscripten links with --stack-first at -O0, which puts the stack at the start of the linear memory, so staddr can legitimately be NULL
g_assert (*stsize != (size_t)-1);
#elif defined(HOST_WASI) && !defined(DISABLE_THREADS)
// TODO: this will need changes for WASI multithreading as the stack will be allocated per thread at different addresses
diff --git a/src/mono/wasm/build/WasmApp.Common.targets b/src/mono/wasm/build/WasmApp.Common.targets
index d592ec19a2a55e..8ba6b8e8302743 100644
--- a/src/mono/wasm/build/WasmApp.Common.targets
+++ b/src/mono/wasm/build/WasmApp.Common.targets
@@ -399,6 +399,7 @@
+
@@ -408,6 +409,7 @@
+
diff --git a/src/native/corehost/browserhost/CMakeLists.txt b/src/native/corehost/browserhost/CMakeLists.txt
index 49876ab799114d..00403d00d3e517 100644
--- a/src/native/corehost/browserhost/CMakeLists.txt
+++ b/src/native/corehost/browserhost/CMakeLists.txt
@@ -117,6 +117,10 @@ if (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
-sASSERTIONS=1
-sLLD_REPORT_UNDEFINED
-sERROR_ON_UNDEFINED_SYMBOLS=1
+ # Emscripten's default INCOMING_MODULE_JS_API, kept explicit so a Module property we don't declare
+ # aborts the build early. This is only meaningful with ASSERTIONS=1, so it is Debug-only. The value
+ # comes from GenerateEmccExports in eng/native.wasm.targets.
+ -sINCOMING_MODULE_JS_API=${CMAKE_EMCC_INCOMING_MODULE_JS_API}
)
endif ()
diff --git a/src/native/libs/Common/JavaScript/types/internal.ts b/src/native/libs/Common/JavaScript/types/internal.ts
index 7307d336ee6772..cdf67e75aca812 100644
--- a/src/native/libs/Common/JavaScript/types/internal.ts
+++ b/src/native/libs/Common/JavaScript/types/internal.ts
@@ -51,9 +51,9 @@ export type EmscriptenModuleInternal = EmscriptenModule & DotnetModuleConfig & {
instantiateWasm?: InstantiateWasmCallBack;
onAbort?: (reason: any, extraJson?: string) => void;
onExit?: (code: number) => void;
- preInit?: (() => any)[];
- preRun?: (() => any)[];
- postRun?: (() => any)[];
+ preInit?: (() => any)[] | (() => any);
+ preRun?: (() => any)[] | (() => any);
+ postRun?: (() => any)[] | (() => any);
}
export interface AssetEntryInternal extends AssetEntry {
diff --git a/src/native/libs/System.Native.Browser/native/index.ts b/src/native/libs/System.Native.Browser/native/index.ts
index 60347ab790c727..c85fa44fc286f8 100644
--- a/src/native/libs/System.Native.Browser/native/index.ts
+++ b/src/native/libs/System.Native.Browser/native/index.ts
@@ -54,6 +54,11 @@ export function dotnetInitializeModule(internals: InternalExchange): void {
return _ems_.wasmTable;
}
+ function asCallbackArray(callbacks: undefined | (() => any) | (() => any)[]): (() => any)[] {
+ if (!callbacks) return [];
+ return typeof callbacks === "function" ? [callbacks] : callbacks;
+ }
+
function setupEmscripten() {
_ems_.Module.preInit = [() => {
if (_ems_.dotnetApi.getConfig) {
@@ -63,7 +68,7 @@ export function dotnetInitializeModule(internals: InternalExchange): void {
}
// SpecialFolder.CommonApplicationData maps to /usr/share
_ems_.FS.createPath("/", "usr/share", true, true);
- }, ...(_ems_.Module.preInit || [])];
+ }, ...asCallbackArray(_ems_.Module.preInit)];
// preInit runs before Emscripten assigns the native WASM exports.
_ems_.Module.preRun = [() => {
@@ -82,6 +87,6 @@ export function dotnetInitializeModule(internals: InternalExchange): void {
// silently ignore any error during shutdown
}
};
- }, ...(_ems_.Module.preRun || [])];
+ }, ...asCallbackArray(_ems_.Module.preRun)];
}
}
diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/http.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/http.ts
index 6e64216e031534..cc2ed758ba9e02 100644
--- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/http.ts
+++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/http.ts
@@ -97,7 +97,9 @@ export function httpAbort(controller: HttpController): void {
// Never resolves; rejects as soon as the fetch does. A failed fetch abandons the readable end of the
// TransformStream, which leaves an in-flight write() pending forever, so writes race against this.
function rejectWhenFetchFails(controller: HttpController): Promise {
- return controller.responsePromise!.then(() => new Promise(() => { }), (err) => { throw err; });
+ return controller.responsePromise!.then(() => new Promise(() => { }), (err) => {
+ throw err;
+ });
}
export function httpTransformStreamWrite(controller: HttpController, bufferPtr: VoidPtr, bufferLength: number): ControllablePromise {