From f1b1fd30bbb15c667877726744ca0a78e0be2d81 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 30 Oct 2025 17:48:55 -0500 Subject: [PATCH 01/29] Make sure we treat tread the ptr as unsigned --- src/mono/browser/runtime/http.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/browser/runtime/http.ts b/src/mono/browser/runtime/http.ts index 149c3c05a473f6..a764a76b88ff67 100644 --- a/src/mono/browser/runtime/http.ts +++ b/src/mono/browser/runtime/http.ts @@ -95,7 +95,7 @@ export function http_wasm_transform_stream_write (controller: HttpController, bu if (BuildConfiguration === "Debug") commonAsserts(controller); mono_assert(bufferLength > 0, "expected bufferLength > 0"); // the bufferPtr is pinned by the caller - const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte); + const view = new Span(((bufferPtr as any) >>> 0), bufferLength, MemoryViewType.Byte); const copy = view.slice() as Uint8Array; return wrap_as_cancelable_promise(async () => { mono_assert(controller.streamWriter, "expected streamWriter"); @@ -136,7 +136,7 @@ export function http_wasm_fetch_stream (controller: HttpController, url: string, export function http_wasm_fetch_bytes (controller: HttpController, url: string, header_names: string[], header_values: string[], option_names: string[], option_values: any[], bodyPtr: VoidPtr, bodyLength: number): ControllablePromise { if (BuildConfiguration === "Debug") commonAsserts(controller); // the bodyPtr is pinned by the caller - const view = new Span(bodyPtr, bodyLength, MemoryViewType.Byte); + const view = new Span(((bodyPtr as any) >>> 0), bodyLength, MemoryViewType.Byte); const copy = view.slice() as Uint8Array; return http_wasm_fetch(controller, url, header_names, header_values, option_names, option_values, copy); } From 3ae2b939b0b47445d87e19dabbaf7ba203816d33 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 30 Oct 2025 18:54:14 -0500 Subject: [PATCH 02/29] fix streamed_response_bytes too --- src/mono/browser/runtime/http.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/browser/runtime/http.ts b/src/mono/browser/runtime/http.ts index a764a76b88ff67..9e8c755893aea6 100644 --- a/src/mono/browser/runtime/http.ts +++ b/src/mono/browser/runtime/http.ts @@ -95,7 +95,7 @@ export function http_wasm_transform_stream_write (controller: HttpController, bu if (BuildConfiguration === "Debug") commonAsserts(controller); mono_assert(bufferLength > 0, "expected bufferLength > 0"); // the bufferPtr is pinned by the caller - const view = new Span(((bufferPtr as any) >>> 0), bufferLength, MemoryViewType.Byte); + const view = new Span(((bufferPtr as any) >>> 0), bufferLength, MemoryViewType.Byte); const copy = view.slice() as Uint8Array; return wrap_as_cancelable_promise(async () => { mono_assert(controller.streamWriter, "expected streamWriter"); @@ -136,7 +136,7 @@ export function http_wasm_fetch_stream (controller: HttpController, url: string, export function http_wasm_fetch_bytes (controller: HttpController, url: string, header_names: string[], header_values: string[], option_names: string[], option_values: any[], bodyPtr: VoidPtr, bodyLength: number): ControllablePromise { if (BuildConfiguration === "Debug") commonAsserts(controller); // the bodyPtr is pinned by the caller - const view = new Span(((bodyPtr as any) >>> 0), bodyLength, MemoryViewType.Byte); + const view = new Span(((bodyPtr as any) >>> 0), bodyLength, MemoryViewType.Byte); const copy = view.slice() as Uint8Array; return http_wasm_fetch(controller, url, header_names, header_values, option_names, option_values, copy); } @@ -239,7 +239,7 @@ export function http_wasm_get_response_bytes (controller: HttpController, view: export function http_wasm_get_streamed_response_bytes (controller: HttpController, bufferPtr: VoidPtr, bufferLength: number): ControllablePromise { if (BuildConfiguration === "Debug") commonAsserts(controller); // the bufferPtr is pinned by the caller - const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte); + const view = new Span(((bufferPtr as any) >>> 0), bufferLength, MemoryViewType.Byte); return wrap_as_cancelable_promise(async () => { await controller.responsePromise; mono_assert(controller.response, "expected response"); From cd942747bfe28afcb1030ef1fa30d9c809a2c91b Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 7 Nov 2025 08:40:27 -0600 Subject: [PATCH 03/29] Add a few more defensive shifts --- src/mono/browser/runtime/marshal.ts | 1 + src/mono/browser/runtime/web-socket.ts | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mono/browser/runtime/marshal.ts b/src/mono/browser/runtime/marshal.ts index e2028be1a4f2fd..5b500999c2285e 100644 --- a/src/mono/browser/runtime/marshal.ts +++ b/src/mono/browser/runtime/marshal.ts @@ -468,6 +468,7 @@ export const enum MemoryViewType { abstract class MemoryView implements IMemoryView { protected constructor (public _pointer: VoidPtr, public _length: number, public _viewType: MemoryViewType) { + this._pointer = ((this._pointer as any) >>> 0); } abstract dispose(): void; diff --git a/src/mono/browser/runtime/web-socket.ts b/src/mono/browser/runtime/web-socket.ts index fd18955f68dc01..14a93af9fb1fb2 100644 --- a/src/mono/browser/runtime/web-socket.ts +++ b/src/mono/browser/runtime/web-socket.ts @@ -72,7 +72,7 @@ export function ws_wasm_create (uri: string, sub_protocols: string[] | null, rec ws[wasm_ws_pending_open_promise] = open_promise_control; ws[wasm_ws_pending_send_promises] = []; ws[wasm_ws_pending_close_promises] = []; - ws[wasm_ws_receive_status_ptr] = receive_status_ptr; + ws[wasm_ws_receive_status_ptr] = ((receive_status_ptr as any) >>> 0); ws.binaryType = "arraybuffer"; const local_on_open = () => { try { @@ -185,7 +185,7 @@ export function ws_wasm_send (ws: WebSocketExtension, buffer_ptr: VoidPtr, buffe return resolvedPromise(); } - const buffer_view = new Uint8Array(localHeapViewU8().buffer, buffer_ptr, buffer_length); + const buffer_view = new Uint8Array(localHeapViewU8().buffer, ((buffer_ptr as any) >>> 0), buffer_length); const whole_buffer = web_socket_send_buffering(ws, buffer_view, message_type, end_of_message); if (!end_of_message || !whole_buffer) { @@ -232,7 +232,7 @@ export function ws_wasm_receive (ws: WebSocketExtension, buffer_ptr: VoidPtr, bu const { promise, promise_control } = createPromiseController(); const receive_promise_control = promise_control as ReceivePromiseControl; - receive_promise_control.buffer_ptr = buffer_ptr; + receive_promise_control.buffer_ptr = ((buffer_ptr as any) >>> 0); receive_promise_control.buffer_length = buffer_length; receive_promise_queue.enqueue(receive_promise_control); @@ -402,7 +402,7 @@ function web_socket_receive_buffering (ws: WebSocketExtension, event_queue: Queu const count = Math.min(buffer_length, event.data.length - event.offset); if (count > 0) { const sourceView = event.data.subarray(event.offset, event.offset + count); - const bufferView = new Uint8Array(localHeapViewU8().buffer, buffer_ptr, buffer_length); + const bufferView = new Uint8Array(localHeapViewU8().buffer, ((buffer_ptr as any) >>> 0), buffer_length); bufferView.set(sourceView, 0); event.offset += count; } From 5071584793a684a7dd88a8f52c443240657d890c Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 7 Nov 2025 09:20:22 -0600 Subject: [PATCH 04/29] Use fixupPointer --- src/mono/browser/runtime/marshal.ts | 1 - src/mono/browser/runtime/web-socket.ts | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/mono/browser/runtime/marshal.ts b/src/mono/browser/runtime/marshal.ts index 5b500999c2285e..e2028be1a4f2fd 100644 --- a/src/mono/browser/runtime/marshal.ts +++ b/src/mono/browser/runtime/marshal.ts @@ -468,7 +468,6 @@ export const enum MemoryViewType { abstract class MemoryView implements IMemoryView { protected constructor (public _pointer: VoidPtr, public _length: number, public _viewType: MemoryViewType) { - this._pointer = ((this._pointer as any) >>> 0); } abstract dispose(): void; diff --git a/src/mono/browser/runtime/web-socket.ts b/src/mono/browser/runtime/web-socket.ts index 14a93af9fb1fb2..1f29488d36a8f1 100644 --- a/src/mono/browser/runtime/web-socket.ts +++ b/src/mono/browser/runtime/web-socket.ts @@ -6,7 +6,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads"; import { prevent_timer_throttling } from "./scheduling"; import { Queue } from "./queue"; import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, createPromiseController, loaderHelpers, mono_assert, Module } from "./globals"; -import { setI32, localHeapViewU8, forceThreadMemoryViewRefresh } from "./memory"; +import { setI32, localHeapViewU8, forceThreadMemoryViewRefresh, fixupPointer } from "./memory"; import { VoidPtr } from "./types/emscripten"; import { PromiseController } from "./types/internal"; import { mono_log_warn } from "./logging"; @@ -72,7 +72,7 @@ export function ws_wasm_create (uri: string, sub_protocols: string[] | null, rec ws[wasm_ws_pending_open_promise] = open_promise_control; ws[wasm_ws_pending_send_promises] = []; ws[wasm_ws_pending_close_promises] = []; - ws[wasm_ws_receive_status_ptr] = ((receive_status_ptr as any) >>> 0); + ws[wasm_ws_receive_status_ptr] = fixupPointer(receive_status_ptr, 0); ws.binaryType = "arraybuffer"; const local_on_open = () => { try { @@ -185,7 +185,7 @@ export function ws_wasm_send (ws: WebSocketExtension, buffer_ptr: VoidPtr, buffe return resolvedPromise(); } - const buffer_view = new Uint8Array(localHeapViewU8().buffer, ((buffer_ptr as any) >>> 0), buffer_length); + const buffer_view = new Uint8Array(localHeapViewU8().buffer, fixupPointer(buffer_ptr, 0), buffer_length); const whole_buffer = web_socket_send_buffering(ws, buffer_view, message_type, end_of_message); if (!end_of_message || !whole_buffer) { @@ -232,7 +232,7 @@ export function ws_wasm_receive (ws: WebSocketExtension, buffer_ptr: VoidPtr, bu const { promise, promise_control } = createPromiseController(); const receive_promise_control = promise_control as ReceivePromiseControl; - receive_promise_control.buffer_ptr = ((buffer_ptr as any) >>> 0); + receive_promise_control.buffer_ptr = fixupPointer(buffer_ptr, 0); receive_promise_control.buffer_length = buffer_length; receive_promise_queue.enqueue(receive_promise_control); @@ -402,7 +402,7 @@ function web_socket_receive_buffering (ws: WebSocketExtension, event_queue: Queu const count = Math.min(buffer_length, event.data.length - event.offset); if (count > 0) { const sourceView = event.data.subarray(event.offset, event.offset + count); - const bufferView = new Uint8Array(localHeapViewU8().buffer, ((buffer_ptr as any) >>> 0), buffer_length); + const bufferView = new Uint8Array(localHeapViewU8().buffer, fixupPointer(buffer_ptr, 0), buffer_length); bufferView.set(sourceView, 0); event.offset += count; } From 38a0c4c0d731143b5c14c670d1f4d5fab48e3aa7 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 7 Nov 2025 10:00:16 -0600 Subject: [PATCH 05/29] More defensive shifts --- src/mono/browser/runtime/marshal.ts | 3 ++- src/mono/browser/runtime/memory.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/mono/browser/runtime/marshal.ts b/src/mono/browser/runtime/marshal.ts index e2028be1a4f2fd..9431c3df1e405b 100644 --- a/src/mono/browser/runtime/marshal.ts +++ b/src/mono/browser/runtime/marshal.ts @@ -5,7 +5,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads"; import { js_owned_gc_handle_symbol, teardown_managed_proxy } from "./gc-handles"; import { Module, loaderHelpers, mono_assert, runtimeHelpers } from "./globals"; -import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8, localHeapViewF64, localHeapViewI32, localHeapViewU8, _zero_region, forceThreadMemoryViewRefresh, setB8, getB8 } from "./memory"; +import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8, localHeapViewF64, localHeapViewI32, localHeapViewU8, _zero_region, forceThreadMemoryViewRefresh, fixupPointer, setB8, getB8 } from "./memory"; import { mono_wasm_new_external_root } from "./roots"; import { GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot, MarshalerType, PThreadPtr, PThreadPtrNull, VoidPtrNull } from "./types/internal"; import { TypedArray, VoidPtr } from "./types/emscripten"; @@ -468,6 +468,7 @@ export const enum MemoryViewType { abstract class MemoryView implements IMemoryView { protected constructor (public _pointer: VoidPtr, public _length: number, public _viewType: MemoryViewType) { + this._pointer = fixupPointer(_pointer, 0); } abstract dispose(): void; diff --git a/src/mono/browser/runtime/memory.ts b/src/mono/browser/runtime/memory.ts index 3497f05b8b99bc..311151bb368663 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -82,13 +82,13 @@ export function setB8 (offset: MemOffset, value: number | boolean): void { if (typeof (value) === "number") assert_int_in_range(value, 0, 1); receiveWorkerHeapViews(); - Module.HEAPU8[offset] = boolValue ? 1 : 0; + Module.HEAPU8[offset >>> 0] = boolValue ? 1 : 0; } export function setU8 (offset: MemOffset, value: number): void { assert_int_in_range(value, 0, 0xFF); receiveWorkerHeapViews(); - Module.HEAPU8[offset] = value; + Module.HEAPU8[offset >>> 0] = value; } export function setU16 (offset: MemOffset, value: number): void { @@ -122,7 +122,7 @@ export function setU32 (offset: MemOffset, value: NumberOrPointer): void { export function setI8 (offset: MemOffset, value: number): void { assert_int_in_range(value, -0x80, 0x7F); receiveWorkerHeapViews(); - Module.HEAP8[offset] = value; + Module.HEAP8[offset >>> 0] = value; } export function setI16 (offset: MemOffset, value: number): void { @@ -210,12 +210,12 @@ export function getB32 (offset: MemOffset): boolean { export function getB8 (offset: MemOffset): boolean { receiveWorkerHeapViews(); - return !!(Module.HEAPU8[offset]); + return !!(Module.HEAPU8[offset] >>> 0); } export function getU8 (offset: MemOffset): number { receiveWorkerHeapViews(); - return Module.HEAPU8[offset]; + return Module.HEAPU8[offset >>> 0]; } export function getU16 (offset: MemOffset): number { @@ -256,7 +256,7 @@ export function getF64_unaligned (offset: MemOffset): number { export function getI8 (offset: MemOffset): number { receiveWorkerHeapViews(); - return Module.HEAP8[offset]; + return Module.HEAP8[offset >>> 0]; } export function getI16 (offset: MemOffset): number { From ba7a1c0c57c7d01d09f6a28656fd4b0fac2a8dc8 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 7 Nov 2025 10:02:18 -0600 Subject: [PATCH 06/29] remove the now redundant cast --- src/mono/browser/runtime/http.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/browser/runtime/http.ts b/src/mono/browser/runtime/http.ts index 9e8c755893aea6..149c3c05a473f6 100644 --- a/src/mono/browser/runtime/http.ts +++ b/src/mono/browser/runtime/http.ts @@ -95,7 +95,7 @@ export function http_wasm_transform_stream_write (controller: HttpController, bu if (BuildConfiguration === "Debug") commonAsserts(controller); mono_assert(bufferLength > 0, "expected bufferLength > 0"); // the bufferPtr is pinned by the caller - const view = new Span(((bufferPtr as any) >>> 0), bufferLength, MemoryViewType.Byte); + const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte); const copy = view.slice() as Uint8Array; return wrap_as_cancelable_promise(async () => { mono_assert(controller.streamWriter, "expected streamWriter"); @@ -136,7 +136,7 @@ export function http_wasm_fetch_stream (controller: HttpController, url: string, export function http_wasm_fetch_bytes (controller: HttpController, url: string, header_names: string[], header_values: string[], option_names: string[], option_values: any[], bodyPtr: VoidPtr, bodyLength: number): ControllablePromise { if (BuildConfiguration === "Debug") commonAsserts(controller); // the bodyPtr is pinned by the caller - const view = new Span(((bodyPtr as any) >>> 0), bodyLength, MemoryViewType.Byte); + const view = new Span(bodyPtr, bodyLength, MemoryViewType.Byte); const copy = view.slice() as Uint8Array; return http_wasm_fetch(controller, url, header_names, header_values, option_names, option_values, copy); } @@ -239,7 +239,7 @@ export function http_wasm_get_response_bytes (controller: HttpController, view: export function http_wasm_get_streamed_response_bytes (controller: HttpController, bufferPtr: VoidPtr, bufferLength: number): ControllablePromise { if (BuildConfiguration === "Debug") commonAsserts(controller); // the bufferPtr is pinned by the caller - const view = new Span(((bufferPtr as any) >>> 0), bufferLength, MemoryViewType.Byte); + const view = new Span(bufferPtr, bufferLength, MemoryViewType.Byte); return wrap_as_cancelable_promise(async () => { await controller.responsePromise; mono_assert(controller.response, "expected response"); From 886a06857614aed84e49fc3efbf35019a5d5d737 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 7 Nov 2025 11:30:35 -0600 Subject: [PATCH 07/29] More fixups --- src/mono/browser/runtime/startup.ts | 6 +++--- src/mono/browser/runtime/strings.ts | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mono/browser/runtime/startup.ts b/src/mono/browser/runtime/startup.ts index 7fc2cefef1ca7d..3eaae69ec3fe74 100644 --- a/src/mono/browser/runtime/startup.ts +++ b/src/mono/browser/runtime/startup.ts @@ -27,7 +27,7 @@ import { populateEmscriptenPool, mono_wasm_init_threads } from "./pthreads"; import { currentWorkerThreadEvents, dotnetPthreadCreated, initWorkerThreadEvents, monoThreadInfo } from "./pthreads"; import { mono_wasm_pthread_ptr, update_thread_info } from "./pthreads"; import { jiterpreter_allocate_tables } from "./jiterpreter-support"; -import { localHeapViewU8, malloc, setU32 } from "./memory"; +import { localHeapViewU8, malloc, setU32, fixupPointer } from "./memory"; import { assertNoProxies } from "./gc-handles"; import { runtimeList } from "./exports"; import { nativeAbort, nativeExit } from "./run"; @@ -594,12 +594,12 @@ export function mono_wasm_asm_loaded (assembly_name: CharPtr, assembly_ptr: numb return; const heapU8 = localHeapViewU8(); const assembly_name_str = assembly_name !== CharPtrNull ? utf8ToString(assembly_name).concat(".dll") : ""; - const assembly_data = new Uint8Array(heapU8.buffer, assembly_ptr, assembly_len); + const assembly_data = new Uint8Array(heapU8.buffer, fixupPointer(assembly_ptr, 0), assembly_len); const assembly_b64 = toBase64StringImpl(assembly_data); let pdb_b64; if (pdb_ptr) { - const pdb_data = new Uint8Array(heapU8.buffer, pdb_ptr, pdb_len); + const pdb_data = new Uint8Array(heapU8.buffer, fixupPointer(pdb_ptr, 0), pdb_len); pdb_b64 = toBase64StringImpl(pdb_data); } diff --git a/src/mono/browser/runtime/strings.ts b/src/mono/browser/runtime/strings.ts index 2b52f82b0320b8..67244a40637d9b 100644 --- a/src/mono/browser/runtime/strings.ts +++ b/src/mono/browser/runtime/strings.ts @@ -7,7 +7,7 @@ import { mono_wasm_new_root, mono_wasm_new_root_buffer } from "./roots"; import { MonoString, MonoStringNull, WasmRoot, WasmRootBuffer } from "./types/internal"; import { Module } from "./globals"; import cwraps from "./cwraps"; -import { isSharedArrayBuffer, localHeapViewU8, getU32_local, setU16_local, localHeapViewU32, getU16_local, localHeapViewU16, _zero_region, malloc, free } from "./memory"; +import { isSharedArrayBuffer, localHeapViewU8, getU32_local, setU16_local, localHeapViewU32, getU16_local, localHeapViewU16, _zero_region, malloc, free, fixupPointer } from "./memory"; import { NativePointer, CharPtr, VoidPtr } from "./types/emscripten"; export const interned_js_string_table = new Map(); @@ -69,6 +69,7 @@ export function utf8ToString (ptr: CharPtr): string { } export function utf8BufferToString (heapOrArray: Uint8Array, idx: number, maxBytesToRead: number): string { + idx = fixupPointer(idx, 0); const endIdx = idx + maxBytesToRead; let endPtr = idx; while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; @@ -83,6 +84,8 @@ export function utf8BufferToString (heapOrArray: Uint8Array, idx: number, maxByt } export function utf16ToString (startPtr: number, endPtr: number): string { + startPtr = fixupPointer(startPtr, 0); + endPtr = fixupPointer(endPtr, 0); if (_text_decoder_utf16) { const subArray = viewOrCopy(localHeapViewU8(), startPtr as any, endPtr as any); return _text_decoder_utf16.decode(subArray); From 01efff2a9c2eaba014de8ef94c0c043f05141507 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Mon, 17 Nov 2025 11:33:50 -0600 Subject: [PATCH 08/29] Fixup debugger offsets --- src/mono/browser/runtime/debug.ts | 6 +++--- src/mono/browser/runtime/marshal.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mono/browser/runtime/debug.ts b/src/mono/browser/runtime/debug.ts index 522c3c41158b28..45d1714cc84a17 100644 --- a/src/mono/browser/runtime/debug.ts +++ b/src/mono/browser/runtime/debug.ts @@ -6,7 +6,7 @@ import { toBase64StringImpl } from "./base64"; import cwraps from "./cwraps"; import { VoidPtr, CharPtr } from "./types/emscripten"; import { mono_log_warn } from "./logging"; -import { forceThreadMemoryViewRefresh, free, localHeapViewU8, malloc } from "./memory"; +import { forceThreadMemoryViewRefresh, fixupPointer, free, localHeapViewU8, malloc } from "./memory"; import { utf8ToString } from "./strings"; const commands_received: any = new Map(); commands_received.remove = function (key: number): CommandResponse { @@ -42,12 +42,12 @@ export function mono_wasm_fire_debugger_agent_message_with_data_to_pause (base64 } export function mono_wasm_fire_debugger_agent_message_with_data (data: number, len: number): void { - const base64String = toBase64StringImpl(new Uint8Array(localHeapViewU8().buffer, data, len)); + const base64String = toBase64StringImpl(new Uint8Array(localHeapViewU8().buffer, fixupPointer(data, 0), len)); mono_wasm_fire_debugger_agent_message_with_data_to_pause(base64String); } export function mono_wasm_add_dbg_command_received (res_ok: boolean, id: number, buffer: number, buffer_len: number): void { - const dbg_command = new Uint8Array(localHeapViewU8().buffer, buffer, buffer_len); + const dbg_command = new Uint8Array(localHeapViewU8().buffer, fixupPointer(buffer, 0), buffer_len); const base64String = toBase64StringImpl(dbg_command); const buffer_obj = { res_ok, diff --git a/src/mono/browser/runtime/marshal.ts b/src/mono/browser/runtime/marshal.ts index 9431c3df1e405b..e369da6418e9cd 100644 --- a/src/mono/browser/runtime/marshal.ts +++ b/src/mono/browser/runtime/marshal.ts @@ -94,7 +94,7 @@ export function is_receiver_should_free (args: JSMarshalerArguments): boolean { export function get_sync_done_semaphore_ptr (args: JSMarshalerArguments): VoidPtr { if (!WasmEnableThreads) return VoidPtrNull; mono_assert(args, "Null args"); - return getI32(args + JSMarshalerArgumentOffsets.SyncDoneSemaphorePtr) as any; + return getU32(args + JSMarshalerArgumentOffsets.SyncDoneSemaphorePtr) as any; } export function get_caller_native_tid (args: JSMarshalerArguments): PThreadPtr { From 1e1aa6ceb0cc312a80692d369638d76fcc70e4b6 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 13:31:31 +0100 Subject: [PATCH 09/29] more --- src/mono/browser/runtime/crypto.ts | 3 ++- src/mono/browser/runtime/strings.ts | 2 +- src/native/libs/System.Native.Browser/native/crypto.ts | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/browser/runtime/crypto.ts b/src/mono/browser/runtime/crypto.ts index 896783a40e3ad8..5fc14a4343a609 100644 --- a/src/mono/browser/runtime/crypto.ts +++ b/src/mono/browser/runtime/crypto.ts @@ -7,7 +7,7 @@ import { isSharedArrayBuffer, localHeapViewU8 } from "./memory"; const batchedQuotaMax = 65536; let warnOnce = true; -export function SystemJS_RandomBytes (bufferPtr: number, bufferLength: number): number { +export function SystemJS_RandomBytes(bufferPtr: number, bufferLength: number): number { if (!globalThis.crypto || !globalThis.crypto.getRandomValues) { if (warnOnce) { mono_log_warn("This engine doesn't support crypto.getRandomValues. Please use a modern version or provide polyfill for 'globalThis.crypto.getRandomValues'."); @@ -16,6 +16,7 @@ export function SystemJS_RandomBytes (bufferPtr: number, bufferLength: number): return -1; } + bufferPtr = bufferPtr >>> 0; const memoryView = localHeapViewU8(); const targetView = memoryView.subarray(bufferPtr, bufferPtr + bufferLength); diff --git a/src/mono/browser/runtime/strings.ts b/src/mono/browser/runtime/strings.ts index 67244a40637d9b..ae806ed472163b 100644 --- a/src/mono/browser/runtime/strings.ts +++ b/src/mono/browser/runtime/strings.ts @@ -65,7 +65,7 @@ export function utf8ToStringRelaxed (buffer: Uint8Array): string { export function utf8ToString (ptr: CharPtr): string { const heapU8 = localHeapViewU8(); - return utf8BufferToString(heapU8, ptr as any, heapU8.length - (ptr as any)); + return utf8BufferToString(heapU8, fixupPointer(ptr, 0), heapU8.length - (ptr as any)); } export function utf8BufferToString (heapOrArray: Uint8Array, idx: number, maxBytesToRead: number): string { diff --git a/src/native/libs/System.Native.Browser/native/crypto.ts b/src/native/libs/System.Native.Browser/native/crypto.ts index 325015efa4bc45..db2d03832513d2 100644 --- a/src/native/libs/System.Native.Browser/native/crypto.ts +++ b/src/native/libs/System.Native.Browser/native/crypto.ts @@ -17,6 +17,7 @@ export function SystemJS_RandomBytes(bufferPtr: number, bufferLength: number): n return -1; } + bufferPtr = bufferPtr >>> 0; const memoryView = dotnetApi.localHeapViewU8(); const targetView = memoryView.subarray(bufferPtr, bufferPtr + bufferLength); From 737e32add26378e2fe2901a4aa5a73030c4cd6da Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 14:06:48 +0100 Subject: [PATCH 10/29] more --- src/mono/browser/runtime/diagnostics/common.ts | 2 +- src/mono/browser/runtime/diagnostics/index.ts | 2 +- src/mono/browser/runtime/memory.ts | 1 + src/mono/browser/runtime/roots.ts | 4 ++-- src/mono/browser/runtime/strings.ts | 4 ++-- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mono/browser/runtime/diagnostics/common.ts b/src/mono/browser/runtime/diagnostics/common.ts index 53911d3e23ef63..d67e03e3204be3 100644 --- a/src/mono/browser/runtime/diagnostics/common.ts +++ b/src/mono/browser/runtime/diagnostics/common.ts @@ -51,7 +51,7 @@ export class DiagnosticConnectionBase { } const message = this.messagesReceived[0]!; const bytes_read = Math.min(message.length, bytes_to_read); - Module.HEAPU8.set(message.subarray(0, bytes_read), buffer as any); + Module.HEAPU8.set(message.subarray(0, bytes_read), buffer as any >>> 0); if (bytes_read === message.length) { this.messagesReceived.shift(); } else { diff --git a/src/mono/browser/runtime/diagnostics/index.ts b/src/mono/browser/runtime/diagnostics/index.ts index 660ac47d8dcc82..c46fbd7822f077 100644 --- a/src/mono/browser/runtime/diagnostics/index.ts +++ b/src/mono/browser/runtime/diagnostics/index.ts @@ -40,7 +40,7 @@ export function setRuntimeGlobals (globalObjects: GlobalObjects): void { if (!wrapper) { return -1; } - const message = (new Uint8Array(Module.HEAPU8.buffer, buffer as any, bytes_to_write)).slice(); + const message = (new Uint8Array(Module.HEAPU8.buffer, buffer as any >>> 0, bytes_to_write)).slice(); return wrapper.send(message); }; diff --git a/src/mono/browser/runtime/memory.ts b/src/mono/browser/runtime/memory.ts index 311151bb368663..60855e15cf2b3a 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -65,6 +65,7 @@ function assert_int_in_range (value: Number, min: Number, max: Number) { } export function _zero_region (byteOffset: VoidPtr, sizeBytes: number): void { + byteOffset = fixupPointer(byteOffset, 0); localHeapViewU8().fill(0, byteOffset, byteOffset + sizeBytes); } diff --git a/src/mono/browser/runtime/roots.ts b/src/mono/browser/runtime/roots.ts index 0afee175f4ae5c..42ef2325600057 100644 --- a/src/mono/browser/runtime/roots.ts +++ b/src/mono/browser/runtime/roots.ts @@ -171,7 +171,7 @@ export class WasmRootBufferImpl implements WasmRootBuffer { constructor (offset: VoidPtr, capacity: number, ownsAllocation: boolean, name?: string) { const capacityBytes = capacity * 4; - this.__offset = offset; + this.__offset = offset as any >>> 0 as any; this.__offset32 = offset >>> 2; this.__count = capacity; this.length = capacity; @@ -351,7 +351,7 @@ class WasmExternalRoot implements WasmRoot { } _set_address (address: NativePointer | ManagedPointer): void { - this.__external_address = address; + this.__external_address = address as any >>> 0 as any; this.__external_address_32 = address >>> 2; } diff --git a/src/mono/browser/runtime/strings.ts b/src/mono/browser/runtime/strings.ts index ae806ed472163b..d2d7b63c9eccc0 100644 --- a/src/mono/browser/runtime/strings.ts +++ b/src/mono/browser/runtime/strings.ts @@ -280,8 +280,8 @@ export function viewOrCopy (view: Uint8Array, start: CharPtr, end: CharPtr): Uin // this condition should be eliminated by rollup on non-threading builds const needsCopy = isSharedArrayBuffer(view.buffer); return needsCopy - ? view.slice(start, end) - : view.subarray(start, end); + ? view.slice(start >>> 0, end >>> 0) + : view.subarray(start >>> 0, end >>> 0); } // below is minimal legacy support for Blazor From 9a4cc2df1c228d41e3059ea942d3e2b4f6556435 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 14:07:56 +0100 Subject: [PATCH 11/29] whitespace --- src/mono/browser/runtime/crypto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/crypto.ts b/src/mono/browser/runtime/crypto.ts index 5fc14a4343a609..8d6cbd253f0a8b 100644 --- a/src/mono/browser/runtime/crypto.ts +++ b/src/mono/browser/runtime/crypto.ts @@ -7,7 +7,7 @@ import { isSharedArrayBuffer, localHeapViewU8 } from "./memory"; const batchedQuotaMax = 65536; let warnOnce = true; -export function SystemJS_RandomBytes(bufferPtr: number, bufferLength: number): number { +export function SystemJS_RandomBytes (bufferPtr: number, bufferLength: number): number { if (!globalThis.crypto || !globalThis.crypto.getRandomValues) { if (warnOnce) { mono_log_warn("This engine doesn't support crypto.getRandomValues. Please use a modern version or provide polyfill for 'globalThis.crypto.getRandomValues'."); From c33f324e4c47d29b289a77b1f95ddf3cb3a87e0d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 14:22:56 +0100 Subject: [PATCH 12/29] testing --- src/mono/browser/browser.proj | 2 +- src/mono/browser/build/BrowserWasmApp.targets | 2 +- src/mono/browser/test-main.js | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj index 2088d661ad7943..d1115965b27690 100644 --- a/src/mono/browser/browser.proj +++ b/src/mono/browser/browser.proj @@ -22,7 +22,7 @@ false true true - 2147483648 + 4294901760 true false false diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index b42a869f811f57..a7002b63621eac 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -314,7 +314,7 @@ <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> <_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" /> - <_EmccCommonFlags Include="-s MAXIMUM_MEMORY=$(EmccMaximumHeapSize)" Condition="'$(EmccMaximumHeapSize)' != ''" /> + <_EmccCommonFlags Include="-s MAXIMUM_MEMORY=4294901760" /> <_EmccIncludePaths Include="$(_WasmIntermediateOutputPath.TrimEnd('\/'))" /> <_EmccIncludePaths Include="$(_WasmRuntimePackIncludeDir)mono-2.0" /> diff --git a/src/mono/browser/test-main.js b/src/mono/browser/test-main.js index 872e14a2ce4cd9..7095bb49413ab8 100644 --- a/src/mono/browser/test-main.js +++ b/src/mono/browser/test-main.js @@ -349,6 +349,12 @@ async function run() { return; } + // waste memory + for (let i = 1; i <= 25; i++) { + const offset = App.runtime.Module._malloc(1024 * 1024 * 100); // 100 MB + console.log(`Allocated ${i * 100} MB at offset ${offset}, total linear memory ${App.runtime.Module.HEAPU8.length} bytes`); + } + if (runArgs.applicationArguments[0] == "--run") { // Run an exe if (runArgs.applicationArguments.length == 1) { From 8a73feda84c5741be9fcd6f203557c305aa0b239 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 19:01:18 +0100 Subject: [PATCH 13/29] feedback --- src/mono/browser/runtime/memory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/memory.ts b/src/mono/browser/runtime/memory.ts index 60855e15cf2b3a..06d2bbdda0cd7a 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -211,7 +211,7 @@ export function getB32 (offset: MemOffset): boolean { export function getB8 (offset: MemOffset): boolean { receiveWorkerHeapViews(); - return !!(Module.HEAPU8[offset] >>> 0); + return !!(Module.HEAPU8[offset >>> 0]); } export function getU8 (offset: MemOffset): number { From b146551df0ab9572b686420dc129d2318d047772 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 19:04:48 +0100 Subject: [PATCH 14/29] jiterpreter --- .../runtime/jiterpreter-interp-entry.ts | 6 ++++- .../browser/runtime/jiterpreter-jit-call.ts | 10 +++++++++ .../browser/runtime/jiterpreter-support.ts | 22 ++++++++++--------- .../runtime/jiterpreter-trace-generator.ts | 15 +++++++------ src/mono/browser/runtime/jiterpreter.ts | 9 +++++++- 5 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-interp-entry.ts b/src/mono/browser/runtime/jiterpreter-interp-entry.ts index 2280d81aad4b91..11a30edf0ab905 100644 --- a/src/mono/browser/runtime/jiterpreter-interp-entry.ts +++ b/src/mono/browser/runtime/jiterpreter-interp-entry.ts @@ -167,7 +167,7 @@ export function mono_jiterp_free_method_data_interp_entry (imethod: number) { // FIXME: move this counter into C and make it thread safe export function mono_interp_record_interp_entry (imethod: number) { // clear the unbox bit - imethod = imethod & ~0x1; + imethod = (imethod >>> 0) & ~0x1; const info = infoTable[imethod]; // This shouldn't happen but it's not worth crashing over @@ -199,6 +199,10 @@ export function mono_interp_jit_wasm_entry_trampoline ( if (argumentCount > maxInlineArgs) return 0; + imethod = imethod >>> 0; + method = method as any >>> 0 as any; + pParamTypes = pParamTypes as any >>> 0 as any; + const info = new TrampolineInfo( imethod, method, argumentCount, pParamTypes, unbox, hasThisReference, hasReturnValue, defaultImplementation diff --git a/src/mono/browser/runtime/jiterpreter-jit-call.ts b/src/mono/browser/runtime/jiterpreter-jit-call.ts index e14786d7ce40ef..0742e73886f73c 100644 --- a/src/mono/browser/runtime/jiterpreter-jit-call.ts +++ b/src/mono/browser/runtime/jiterpreter-jit-call.ts @@ -182,6 +182,11 @@ function getWasmTableEntry (index: number) { export function mono_interp_invoke_wasm_jit_call_trampoline ( thunkIndex: number, ret_sp: number, sp: number, ftndesc: number, thrown: NativePointer ) { + ret_sp = ret_sp as any >>> 0 as any; + sp = sp as any >>> 0 as any; + ftndesc = ftndesc as any >>> 0 as any; + thrown = thrown as any >>> 0 as any; + const thunk = getWasmTableEntry(thunkIndex); try { thunk(ret_sp, sp, ftndesc, thrown); @@ -234,6 +239,11 @@ export function mono_interp_jit_wasm_jit_call_trampoline ( method: MonoMethod, rmethod: VoidPtr, cinfo: VoidPtr, arg_offsets: VoidPtr, catch_exceptions: number ): void { + method = method as any >>> 0 as any; + rmethod = rmethod as any >>> 0 as any; + cinfo = cinfo as any >>> 0 as any; + arg_offsets = arg_offsets as any >>> 0 as any; + // multiple cinfos can share the same target function, so for that scenario we want to // use the same TrampolineInfo for all of them. if that info has already been jitted // we want to immediately store its pointer into the cinfo, otherwise we add it to diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index cc593b855c9ff3..bc0b4004db8853 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -334,7 +334,7 @@ export class WasmBuilder { (idx < 0) && (this.nextConstantSlot < this.constantSlots.length) ) { idx = this.nextConstantSlot++; - this.constantSlots[idx] = pointer; + this.constantSlots[idx] = pointer >>> 0; } if (idx >= 0) { @@ -342,13 +342,14 @@ export class WasmBuilder { this.appendLeb(idx); } else { // mono_log_info(`Warning: no constant slot for ${pointer} (${this.nextConstantSlot} slots used)`); - this.i32_const(pointer); + this.appendU8(WasmOpcode.i32_const); + this.appendULeb(pointer >>> 0 - this.base); } } ip_const (value: MintOpcodePtr) { this.appendU8(WasmOpcode.i32_const); - this.appendLeb(value - this.base); + this.appendULeb(value >>> 0 - this.base); } i52_const (value: number) { @@ -909,20 +910,21 @@ export class WasmBuilder { appendMemarg (offset: number, alignPower: number) { this.appendULeb(alignPower); - this.appendULeb(offset); + this.appendULeb(offset >>> 0); } /* generates either (u32)get_local(ptr) + offset or (u32)ptr1 + offset */ lea (ptr1: string | number, offset: number) { - if (typeof (ptr1) === "string") + if (typeof (ptr1) === "string") { this.local(ptr1); - else - this.i32_const(ptr1); + } else { + this.appendU8(WasmOpcode.i32_const); + this.appendULeb(ptr1 >>> 0); + } this.i32_const(offset); - // FIXME: How do we make sure this has correct semantics for pointers over 2gb? this.appendU8(WasmOpcode.i32_add); } @@ -1617,7 +1619,7 @@ export function append_profiler_event (builder: WasmBuilder, ip: MintOpcodePtr, throw new Error(`Unimplemented profiler event ${opcode}`); } builder.local("frame"); - builder.i32_const(ip); + builder.ptr_const(ip); builder.callImport(event_name); } @@ -1633,7 +1635,7 @@ export function append_safepoint (builder: WasmBuilder, ip: MintOpcodePtr) { builder.block(WasmValtype.void, WasmOpcode.if_); builder.local("frame"); // Not ip_const, because we can't pass relative IP to do_safepoint - builder.i32_const(ip); + builder.i32_const(ip);// builder.callImport("safepoint"); builder.endBlock(); } diff --git a/src/mono/browser/runtime/jiterpreter-trace-generator.ts b/src/mono/browser/runtime/jiterpreter-trace-generator.ts index f9938164b5e112..22a52bdd5b8d87 100644 --- a/src/mono/browser/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/browser/runtime/jiterpreter-trace-generator.ts @@ -1068,7 +1068,7 @@ export function generateWasmBody ( case MintOpcode.MINT_ISINST_COMMON: case MintOpcode.MINT_CASTCLASS: case MintOpcode.MINT_ISINST: { - const klass = get_imethod_data(frame, getArgU16(ip, 3)), + const klass = get_imethod_data(frame, getArgU16(ip, 3)) >>> 0, canDoFastCheck = (opcode === MintOpcode.MINT_CASTCLASS_COMMON) || (opcode === MintOpcode.MINT_ISINST_COMMON), bailoutOnFailure = (opcode === MintOpcode.MINT_CASTCLASS) || @@ -1115,7 +1115,7 @@ export function generateWasmBody ( // Stash obj->vtable->klass so we can do a fast has_parent check later if (canDoFastCheck) builder.local("src_ptr", WasmOpcode.tee_local); - builder.i32_const(klass); + builder.ptr_const(klass); builder.appendU8(WasmOpcode.i32_eq); builder.block(WasmValtype.void, WasmOpcode.if_); // if A @@ -1201,12 +1201,12 @@ export function generateWasmBody ( } case MintOpcode.MINT_UNBOX: { - const klass = get_imethod_data(frame, getArgU16(ip, 3)), + const klass = get_imethod_data(frame, getArgU16(ip, 3)) >>> 0, // The type check needs to examine the boxed value's rank and element class elementClassOffset = getMemberOffset(JiterpMember.ClassElementClass), destOffset = getArgU16(ip, 1), // Get the class's element class, which is what we will actually type-check against - elementClass = getU32_unaligned(klass + elementClassOffset); + elementClass = getU32_unaligned(klass + elementClassOffset) >>> 0; if (!klass || !elementClass) { record_abort(builder.traceIndex, ip, traceName, "null-klass"); @@ -1234,7 +1234,7 @@ export function generateWasmBody ( builder.local("src_ptr", WasmOpcode.tee_local); builder.appendU8(WasmOpcode.i32_load); builder.appendMemarg(elementClassOffset, 0); - builder.i32_const(elementClass); + builder.ptr_const(elementClass); builder.appendU8(WasmOpcode.i32_eq); // Check klass->rank == 0 @@ -1285,7 +1285,7 @@ export function generateWasmBody ( builder.block(); append_ldloca(builder, getArgU16(ip, 1), 4); const vtable = get_imethod_data(frame, getArgU16(ip, 3)); - builder.i32_const(vtable); + builder.ptr_const(vtable); append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.i32_load); builder.callImport("newarr"); // If the newarr operation succeeded, continue, otherwise bailout @@ -1973,6 +1973,7 @@ function append_stloc_tail (builder: WasmBuilder, offset: number, opcodeOrPrefix // This looks wrong but I assure you it's correct. builder.appendULeb(simdOpcode); } + offset = offset >>> 0; const alignment = computeMemoryAlignment(offset, opcodeOrPrefix, simdOpcode); builder.appendMemarg(offset, alignment); invalidate_local(offset); @@ -2335,7 +2336,7 @@ function emit_fieldop ( append_ldloc(builder, objectOffset, WasmOpcode.i32_load); append_ldloc(builder, objectOffset, WasmOpcode.i32_load); builder.i32_const(builder.traceIndex); - builder.i32_const(ip); + builder.ip_const(ip); builder.callImport("notnull"); } } diff --git a/src/mono/browser/runtime/jiterpreter.ts b/src/mono/browser/runtime/jiterpreter.ts index 7d4d2b374d2cc7..5d70c3b26519b8 100644 --- a/src/mono/browser/runtime/jiterpreter.ts +++ b/src/mono/browser/runtime/jiterpreter.ts @@ -117,7 +117,7 @@ export class TraceInfo { isVerbose: boolean; constructor (ip: MintOpcodePtr, index: number, isVerbose: number) { - this.ip = ip; + this.ip = ip as any >>> 0 as any; this.index = index; this.isVerbose = !!isVerbose; } @@ -1011,6 +1011,10 @@ export function mono_interp_tier_prepare_jiterpreter ( presetFunctionPointer: number ): number { mono_assert(ip, "expected instruction pointer"); + ip = ip as any >>> 0 as any; + frame = frame as any >>> 0 as any; + method = method as any >>> 0 as any; + startOfBody = startOfBody as any >>> 0 as any; if (!mostRecentOptions) mostRecentOptions = getOptions(); @@ -1084,6 +1088,9 @@ export function mono_interp_tier_prepare_jiterpreter ( export function mono_wasm_free_method_data ( method: MonoMethod, imethod: number, traceIndex: number ) { + method = method as any >>> 0 as any; + imethod = imethod >>> 0; + if (runtimeHelpers.emscriptenBuildOptions.enableDevToolsProfiler) { mono_wasm_profiler_free_method(method); } From 0c910224a5e470471626589790bc0a26f28432d3 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 19:04:56 +0100 Subject: [PATCH 15/29] testing --- src/mono/browser/browser.proj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj index d1115965b27690..8f767effc532d0 100644 --- a/src/mono/browser/browser.proj +++ b/src/mono/browser/browser.proj @@ -312,7 +312,8 @@ -O2 - $(CMakeConfigurationLinkFlags) -s EXPORT_ES6=1 -lexports.js + $(CMakeConfigurationLinkFlags) -s EXPORT_ES6=1 -lexports.js -s MAXIMUM_MEMORY=4294901760 + $(CMakeConfigurationLinkFlags) -msimd128 $(CMakeConfigurationLinkFlags) -Wno-pthreads-mem-growth $(CMakeConfigurationLinkFlags) --emit-symbol-map From da70a5549a0983d90a825f5a82219f658cace339 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 19:31:52 +0100 Subject: [PATCH 16/29] fix ptr_const --- src/mono/browser/runtime/jiterpreter-support.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index bc0b4004db8853..9b0fc9dba5d4b4 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -343,7 +343,7 @@ export class WasmBuilder { } else { // mono_log_info(`Warning: no constant slot for ${pointer} (${this.nextConstantSlot} slots used)`); this.appendU8(WasmOpcode.i32_const); - this.appendULeb(pointer >>> 0 - this.base); + this.appendULeb(pointer >>> 0); } } @@ -917,12 +917,10 @@ export class WasmBuilder { generates either (u32)get_local(ptr) + offset or (u32)ptr1 + offset */ lea (ptr1: string | number, offset: number) { - if (typeof (ptr1) === "string") { + if (typeof (ptr1) === "string") this.local(ptr1); - } else { - this.appendU8(WasmOpcode.i32_const); - this.appendULeb(ptr1 >>> 0); - } + else + this.ptr_const(ptr1); this.i32_const(offset); this.appendU8(WasmOpcode.i32_add); From 3a955e527aca2cb9fdc06f47f02839c0cab74533 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 19:45:12 +0100 Subject: [PATCH 17/29] fix --- src/mono/browser/runtime/jiterpreter-support.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index 9b0fc9dba5d4b4..ca4d3632ee477b 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -349,7 +349,7 @@ export class WasmBuilder { ip_const (value: MintOpcodePtr) { this.appendU8(WasmOpcode.i32_const); - this.appendULeb(value >>> 0 - this.base); + this.appendULeb(value >>> 0 - this.base >>> 0); } i52_const (value: number) { From 6d7f3a9af5ddc9b507a7c9a1cd296e91ab53e8e0 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 25 Nov 2025 21:35:49 +0100 Subject: [PATCH 18/29] fix --- src/mono/browser/runtime/jiterpreter-support.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index ca4d3632ee477b..169ffb636a2a62 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -343,13 +343,14 @@ export class WasmBuilder { } else { // mono_log_info(`Warning: no constant slot for ${pointer} (${this.nextConstantSlot} slots used)`); this.appendU8(WasmOpcode.i32_const); - this.appendULeb(pointer >>> 0); + // i32_const is always signed + this.appendLebRef((pointer as any | 0), true); } } ip_const (value: MintOpcodePtr) { this.appendU8(WasmOpcode.i32_const); - this.appendULeb(value >>> 0 - this.base >>> 0); + this.appendLeb(value - this.base); } i52_const (value: number) { @@ -910,7 +911,7 @@ export class WasmBuilder { appendMemarg (offset: number, alignPower: number) { this.appendULeb(alignPower); - this.appendULeb(offset >>> 0); + this.appendLeb(offset | 0); } /* @@ -1633,7 +1634,7 @@ export function append_safepoint (builder: WasmBuilder, ip: MintOpcodePtr) { builder.block(WasmValtype.void, WasmOpcode.if_); builder.local("frame"); // Not ip_const, because we can't pass relative IP to do_safepoint - builder.i32_const(ip);// + builder.ptr_const(ip); builder.callImport("safepoint"); builder.endBlock(); } From 23401bcaefdd8191e082eba7027cd96f0ddd139a Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 12:19:10 +0100 Subject: [PATCH 19/29] feedback --- src/mono/browser/runtime/jiterpreter-interp-entry.ts | 2 +- src/mono/browser/runtime/jiterpreter-support.ts | 1 + src/mono/browser/runtime/jiterpreter-trace-generator.ts | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-interp-entry.ts b/src/mono/browser/runtime/jiterpreter-interp-entry.ts index 11a30edf0ab905..5d680e03628efd 100644 --- a/src/mono/browser/runtime/jiterpreter-interp-entry.ts +++ b/src/mono/browser/runtime/jiterpreter-interp-entry.ts @@ -167,7 +167,7 @@ export function mono_jiterp_free_method_data_interp_entry (imethod: number) { // FIXME: move this counter into C and make it thread safe export function mono_interp_record_interp_entry (imethod: number) { // clear the unbox bit - imethod = (imethod >>> 0) & ~0x1; + imethod = (imethod & ~0x1) >>> 0; const info = infoTable[imethod]; // This shouldn't happen but it's not worth crashing over diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index 169ffb636a2a62..fe81a1ede51f70 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -328,6 +328,7 @@ export class WasmBuilder { } ptr_const (pointer: number | ManagedPointer | NativePointer) { + pointer = pointer as any >>> 0; let idx = this.options.useConstants ? this.constantSlots.indexOf(pointer) : -1; if ( this.options.useConstants && diff --git a/src/mono/browser/runtime/jiterpreter-trace-generator.ts b/src/mono/browser/runtime/jiterpreter-trace-generator.ts index 22a52bdd5b8d87..842d89aebcbda7 100644 --- a/src/mono/browser/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/browser/runtime/jiterpreter-trace-generator.ts @@ -1068,7 +1068,7 @@ export function generateWasmBody ( case MintOpcode.MINT_ISINST_COMMON: case MintOpcode.MINT_CASTCLASS: case MintOpcode.MINT_ISINST: { - const klass = get_imethod_data(frame, getArgU16(ip, 3)) >>> 0, + const klass = get_imethod_data(frame, getArgU16(ip, 3)), canDoFastCheck = (opcode === MintOpcode.MINT_CASTCLASS_COMMON) || (opcode === MintOpcode.MINT_ISINST_COMMON), bailoutOnFailure = (opcode === MintOpcode.MINT_CASTCLASS) || @@ -1201,7 +1201,7 @@ export function generateWasmBody ( } case MintOpcode.MINT_UNBOX: { - const klass = get_imethod_data(frame, getArgU16(ip, 3)) >>> 0, + const klass = get_imethod_data(frame, getArgU16(ip, 3)), // The type check needs to examine the boxed value's rank and element class elementClassOffset = getMemberOffset(JiterpMember.ClassElementClass), destOffset = getArgU16(ip, 1), @@ -2336,7 +2336,7 @@ function emit_fieldop ( append_ldloc(builder, objectOffset, WasmOpcode.i32_load); append_ldloc(builder, objectOffset, WasmOpcode.i32_load); builder.i32_const(builder.traceIndex); - builder.ip_const(ip); + builder.ptr_const(ip); builder.callImport("notnull"); } } From cd5d4d8b6c2a8121927f5087d86be6ba3783c85e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 12:27:36 +0100 Subject: [PATCH 20/29] feedback --- src/mono/browser/runtime/jiterpreter-support.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index fe81a1ede51f70..7a6044c289f3fc 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -912,7 +912,8 @@ export class WasmBuilder { appendMemarg (offset: number, alignPower: number) { this.appendULeb(alignPower); - this.appendLeb(offset | 0); + // u64 + this.appendULeb(offset >>> 0); } /* From 0b166ee8aeb7320e680f1518d6d9663388931f29 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 13:03:02 +0100 Subject: [PATCH 21/29] remove support for constantSlots --- .../browser/runtime/jiterpreter-support.ts | 54 +++---------------- 1 file changed, 8 insertions(+), 46 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index 7a6044c289f3fc..8507c4e7318000 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -103,10 +103,8 @@ export class WasmBuilder { traceBuf: Array = []; branchTargets = new Set(); options!: JiterpreterOptions; - constantSlots: Array = []; backBranchOffsets: Array = []; callHandlerReturnAddresses: Array = []; - nextConstantSlot = 0; backBranchTraceLevel = 0; containsSimd!: boolean; @@ -115,14 +113,14 @@ export class WasmBuilder { compressImportNames = false; lockImports = false; - constructor (constantSlotCount: number) { + constructor () { this.stack = [new BlobBuilder()]; - this.clear(constantSlotCount); + this.clear(); this.cfg = new Cfg(this); this.defineType("__cpp_exception", { "ptr": WasmValtype.i32 }, WasmValtype.void, true); } - clear (constantSlotCount: number) { + clear () { this.options = getOptions(); if (this.options.maxModuleSize >= blobBuilderCapacity) throw new Error(`blobBuilderCapacity ${blobBuilderCapacity} is not large enough for jiterpreter-max-module-size of ${this.options.maxModuleSize}`); @@ -154,10 +152,6 @@ export class WasmBuilder { this.traceBuf.length = 0; this.branchTargets.clear(); this.activeBlocks = 0; - this.nextConstantSlot = 0; - this.constantSlots.length = this.options.useConstants ? constantSlotCount : 0; - for (let i = 0; i < this.constantSlots.length; i++) - this.constantSlots[i] = 0; this.backBranchOffsets.length = 0; this.callHandlerReturnAddresses.length = 0; @@ -209,7 +203,6 @@ export class WasmBuilder { const exceptionTag = this.getExceptionTag(); const result: any = { - c: this.getConstants(), m: { h: memory }, }; if (exceptionTag) @@ -329,24 +322,11 @@ export class WasmBuilder { ptr_const (pointer: number | ManagedPointer | NativePointer) { pointer = pointer as any >>> 0; - let idx = this.options.useConstants ? this.constantSlots.indexOf(pointer) : -1; - if ( - this.options.useConstants && - (idx < 0) && (this.nextConstantSlot < this.constantSlots.length) - ) { - idx = this.nextConstantSlot++; - this.constantSlots[idx] = pointer >>> 0; - } - if (idx >= 0) { - this.appendU8(WasmOpcode.get_global); - this.appendLeb(idx); - } else { - // mono_log_info(`Warning: no constant slot for ${pointer} (${this.nextConstantSlot} slots used)`); - this.appendU8(WasmOpcode.i32_const); - // i32_const is always signed - this.appendLebRef((pointer as any | 0), true); - } + // mono_log_info(`Warning: no constant slot for ${pointer} (${this.nextConstantSlot} slots used)`); + this.appendU8(WasmOpcode.i32_const); + // i32_const is always signed + this.appendLeb(pointer as any | 0); } ip_const (value: MintOpcodePtr) { @@ -510,7 +490,7 @@ export class WasmBuilder { this.appendULeb( 1 + // memory (enableWasmEh ? 1 : 0) + // c++ exception tag - importsToEmit.length + this.constantSlots.length + + importsToEmit.length + ((includeFunctionTable !== false) ? 1 : 0) ); @@ -524,14 +504,6 @@ export class WasmBuilder { this.appendU8(ifi.typeIndex); } - for (let i = 0; i < this.constantSlots.length; i++) { - this.appendName("c"); - this.appendName(i.toString(shortNameBase)); - this.appendU8(0x03); // global - this.appendU8(WasmValtype.i32); // all constants are pointers right now - this.appendU8(0x00); // constant - } - // import the native heap this.appendName("m"); this.appendName("h"); @@ -934,13 +906,6 @@ export class WasmBuilder { throw new Error("Jiterpreter block stack not empty"); return this.stack[0].getArrayView(fullCapacity); } - - getConstants () { - const result: { [key: string]: number } = {}; - for (let i = 0; i < this.constantSlots.length; i++) - result[i.toString(shortNameBase)] = this.constantSlots[i]; - return result; - } } export class BlobBuilder { @@ -2023,8 +1988,6 @@ export type JiterpreterOptions = { countBailouts: boolean; // Dump the wasm blob for all compiled traces dumpTraces: boolean; - // Use runtime imports for pointer constants - useConstants: boolean; // Enable performing backward branches without exiting traces noExitBackwardBranches: boolean; // Unwrap gsharedvt wrappers when compiling jitcalls if possible @@ -2065,7 +2028,6 @@ const optionNames: { [jsName: string]: string } = { "estimateHeat": "jiterpreter-estimate-heat", "countBailouts": "jiterpreter-count-bailouts", "dumpTraces": "jiterpreter-dump-traces", - "useConstants": "jiterpreter-use-constants", "eliminateNullChecks": "jiterpreter-eliminate-null-checks", "noExitBackwardBranches": "jiterpreter-backward-branches-enabled", "directJitCalls": "jiterpreter-direct-jit-calls", From 7144407b072d8ea26432fdd93e3d87c0098aff90 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 13:04:46 +0100 Subject: [PATCH 22/29] fix --- src/mono/browser/runtime/jiterpreter-interp-entry.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-interp-entry.ts b/src/mono/browser/runtime/jiterpreter-interp-entry.ts index 5d680e03628efd..e3025366ede1e1 100644 --- a/src/mono/browser/runtime/jiterpreter-interp-entry.ts +++ b/src/mono/browser/runtime/jiterpreter-interp-entry.ts @@ -269,10 +269,9 @@ function flush_wasm_entry_trampoline_jit_queue () { // If the function signature contains types that need stackval_from_data, that'll use // some constant slots, so make some extra space - const constantSlots = (4 * jitQueue.length) + 1; let builder = trampBuilder; if (!builder) { - trampBuilder = builder = new WasmBuilder(constantSlots); + trampBuilder = builder = new WasmBuilder(); builder.defineType( "unbox", @@ -307,7 +306,7 @@ function flush_wasm_entry_trampoline_jit_queue () { WasmValtype.void, true ); } else - builder.clear(constantSlots); + builder.clear(); if (builder.options.wasmBytesLimit <= getCounter(JiterpCounter.BytesGenerated)) { return; From 6ab4e14783e3b8e50a6b2dfb079a5fc7d94115d7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 13:07:26 +0100 Subject: [PATCH 23/29] fix --- src/mono/browser/runtime/jiterpreter-jit-call.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-jit-call.ts b/src/mono/browser/runtime/jiterpreter-jit-call.ts index 0742e73886f73c..3175cc5a758e5a 100644 --- a/src/mono/browser/runtime/jiterpreter-jit-call.ts +++ b/src/mono/browser/runtime/jiterpreter-jit-call.ts @@ -306,7 +306,7 @@ export function mono_interp_flush_jitcall_queue (): void { let builder = trampBuilder; if (!builder) { - trampBuilder = builder = new WasmBuilder(0); + trampBuilder = builder = new WasmBuilder(); // Function type for compiled trampolines builder.defineType( "trampoline", @@ -326,7 +326,7 @@ export function mono_interp_flush_jitcall_queue (): void { builder.defineImportedFunction("i", "begin_catch", "begin_catch", true, getRawCwrap("mono_jiterp_begin_catch")); builder.defineImportedFunction("i", "end_catch", "end_catch", true, getRawCwrap("mono_jiterp_end_catch")); } else - builder.clear(0); + builder.clear(); if (builder.options.wasmBytesLimit <= getCounter(JiterpCounter.BytesGenerated)) { cwraps.mono_jiterp_tlqueue_clear(JitQueue.JitCall); From 927a3a8ad8c69500288cc0dcddc44b6d153bd2da Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 13:09:51 +0100 Subject: [PATCH 24/29] fix --- src/mono/browser/runtime/jiterpreter.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter.ts b/src/mono/browser/runtime/jiterpreter.ts index 5d70c3b26519b8..8138e7f9d53f2c 100644 --- a/src/mono/browser/runtime/jiterpreter.ts +++ b/src/mono/browser/runtime/jiterpreter.ts @@ -731,18 +731,12 @@ function generate_wasm ( traceIndex: number, methodFullName: string | undefined, backwardBranchTable: Uint16Array | null, presetFunctionPointer: number ): number { - // Pre-allocate a decent number of constant slots - this adds fixed size bloat - // to the trace but will make the actual pointer constants in the trace smaller - // If we run out of constant slots it will transparently fall back to i32_const - // For System.Runtime.Tests we only run out of slots ~50 times in 9100 test cases - const constantSlotCount = 8; - let builder = traceBuilder; if (!builder) { - traceBuilder = builder = new WasmBuilder(constantSlotCount); + traceBuilder = builder = new WasmBuilder(); initialize_builder(builder); } else - builder.clear(constantSlotCount); + builder.clear(); mostRecentOptions = builder.options; From e1c8514f711d92618967ce91c4fdc781907a8976 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 13:17:28 +0100 Subject: [PATCH 25/29] fix --- src/mono/browser/runtime/jiterpreter-support.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index 8507c4e7318000..811092f374d8f9 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -321,8 +321,6 @@ export class WasmBuilder { } ptr_const (pointer: number | ManagedPointer | NativePointer) { - pointer = pointer as any >>> 0; - // mono_log_info(`Warning: no constant slot for ${pointer} (${this.nextConstantSlot} slots used)`); this.appendU8(WasmOpcode.i32_const); // i32_const is always signed From 76d46403536bdc8ce26d46a5b2164f26f3026963 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 13:26:09 +0100 Subject: [PATCH 26/29] fix --- src/mono/browser/runtime/jiterpreter-support.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/jiterpreter-support.ts b/src/mono/browser/runtime/jiterpreter-support.ts index 811092f374d8f9..3235406cae7894 100644 --- a/src/mono/browser/runtime/jiterpreter-support.ts +++ b/src/mono/browser/runtime/jiterpreter-support.ts @@ -324,7 +324,7 @@ export class WasmBuilder { // mono_log_info(`Warning: no constant slot for ${pointer} (${this.nextConstantSlot} slots used)`); this.appendU8(WasmOpcode.i32_const); // i32_const is always signed - this.appendLeb(pointer as any | 0); + this.appendLeb((pointer as any) | 0); } ip_const (value: MintOpcodePtr) { From 0d572fc5693200a5b1803b44ab626ea084bec4ff Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 13:48:41 +0100 Subject: [PATCH 27/29] more --- src/native/libs/System.Native.Browser/utils/memory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/libs/System.Native.Browser/utils/memory.ts b/src/native/libs/System.Native.Browser/utils/memory.ts index a29dc6a38de565..bb6484c04be3e3 100644 --- a/src/native/libs/System.Native.Browser/utils/memory.ts +++ b/src/native/libs/System.Native.Browser/utils/memory.ts @@ -61,7 +61,7 @@ export function setHeapU32(offset: MemOffset, value: NumberOrPointer): void { export function setHeapI8(offset: MemOffset, value: number): void { assertIntInRange(value, -0x80, 0x7F); - Module.HEAP8[offset] = value; + Module.HEAP8[offset >>> 0] = value; } export function setHeapI16(offset: MemOffset, value: number): void { @@ -148,7 +148,7 @@ export function getHeapU32_local(localView: Uint32Array, offset: MemOffset): num } export function getHeapI8(offset: MemOffset): number { - return Module.HEAP8[offset]; + return Module.HEAP8[offset >>> 0]; } export function getHeapI16(offset: MemOffset): number { From 4048fbe789d5c5353104ebd86c2e068d7bb85493 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 26 Nov 2025 19:08:29 +0100 Subject: [PATCH 28/29] revert test changes --- src/mono/browser/browser.proj | 5 ++--- src/mono/browser/build/BrowserWasmApp.targets | 2 +- src/mono/browser/test-main.js | 6 ------ 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj index 8f767effc532d0..2088d661ad7943 100644 --- a/src/mono/browser/browser.proj +++ b/src/mono/browser/browser.proj @@ -22,7 +22,7 @@ false true true - 4294901760 + 2147483648 true false false @@ -312,8 +312,7 @@ -O2 - $(CMakeConfigurationLinkFlags) -s EXPORT_ES6=1 -lexports.js -s MAXIMUM_MEMORY=4294901760 - + $(CMakeConfigurationLinkFlags) -s EXPORT_ES6=1 -lexports.js $(CMakeConfigurationLinkFlags) -msimd128 $(CMakeConfigurationLinkFlags) -Wno-pthreads-mem-growth $(CMakeConfigurationLinkFlags) --emit-symbol-map diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index a7002b63621eac..b42a869f811f57 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -314,7 +314,7 @@ <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> <_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" /> - <_EmccCommonFlags Include="-s MAXIMUM_MEMORY=4294901760" /> + <_EmccCommonFlags Include="-s MAXIMUM_MEMORY=$(EmccMaximumHeapSize)" Condition="'$(EmccMaximumHeapSize)' != ''" /> <_EmccIncludePaths Include="$(_WasmIntermediateOutputPath.TrimEnd('\/'))" /> <_EmccIncludePaths Include="$(_WasmRuntimePackIncludeDir)mono-2.0" /> diff --git a/src/mono/browser/test-main.js b/src/mono/browser/test-main.js index 7095bb49413ab8..872e14a2ce4cd9 100644 --- a/src/mono/browser/test-main.js +++ b/src/mono/browser/test-main.js @@ -349,12 +349,6 @@ async function run() { return; } - // waste memory - for (let i = 1; i <= 25; i++) { - const offset = App.runtime.Module._malloc(1024 * 1024 * 100); // 100 MB - console.log(`Allocated ${i * 100} MB at offset ${offset}, total linear memory ${App.runtime.Module.HEAPU8.length} bytes`); - } - if (runArgs.applicationArguments[0] == "--run") { // Run an exe if (runArgs.applicationArguments.length == 1) { From b9b592b2ee2616c938526de05aa0b5fcb734d174 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 26 Nov 2025 19:14:37 +0100 Subject: [PATCH 29/29] Update src/mono/browser/runtime/strings.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/mono/browser/runtime/strings.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/strings.ts b/src/mono/browser/runtime/strings.ts index d2d7b63c9eccc0..9ae9799c166a22 100644 --- a/src/mono/browser/runtime/strings.ts +++ b/src/mono/browser/runtime/strings.ts @@ -65,7 +65,8 @@ export function utf8ToStringRelaxed (buffer: Uint8Array): string { export function utf8ToString (ptr: CharPtr): string { const heapU8 = localHeapViewU8(); - return utf8BufferToString(heapU8, fixupPointer(ptr, 0), heapU8.length - (ptr as any)); + const fixedPtr = fixupPointer(ptr, 0); + return utf8BufferToString(heapU8, fixedPtr, heapU8.length - fixedPtr); } export function utf8BufferToString (heapOrArray: Uint8Array, idx: number, maxBytesToRead: number): string {