}
[Fact]
- public static void ManuallyInternString()
- {
- HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
- Utils.InvokeJS(@"
- var sym = INTERNAL.mono_intern_string(""interned string 3"");
- App.call_test_method (""InvokeString"", [ sym ], ""s"");
- App.call_test_method (""InvokeString2"", [ sym ], ""s"");
- ");
- Assert.Equal("interned string 3", HelperMarshal._stringResource);
- Assert.Equal(HelperMarshal._stringResource, HelperMarshal._stringResource2);
- Assert.True(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
- }
-
- [Fact]
public static void LargeStringsAreNotAutomaticallyLocatedInInternTable()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
import { AssetEntryInternal } from "./types/internal";
import { AssetEntry } from "./types";
import { InstantiateWasmSuccessCallback, VoidPtr } from "./types/emscripten";
+import { utf8BufferToString } from "./strings";
// this need to be run only after onRuntimeInitialized event, when the memory is ready
export function instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array): void {
let manifest;
try {
- const manifestContent = Module.UTF8ArrayToString(data, 8, manifestSize);
+ const manifestContent = utf8BufferToString(data, 8, manifestSize);
manifest = JSON.parse(manifestContent);
if (!(manifest instanceof Array))
return false;
import cwraps from "./cwraps";
import { VoidPtr, CharPtr } from "./types/emscripten";
import { mono_log_warn } from "./logging";
+import { localHeapViewU8 } from "./memory";
+import { utf8ToString } from "./strings";
const commands_received: any = new Map<number, CommandResponse>();
commands_received.remove = function (key: number): CommandResponse { const value = this.get(key); this.delete(key); return value; };
let _call_function_res_cache: any = {};
}
export function mono_wasm_fire_debugger_agent_message_with_data(data: number, len: number): void {
- const base64String = toBase64StringImpl(new Uint8Array(Module.HEAPU8.buffer, data, len));
+ const base64String = toBase64StringImpl(new Uint8Array(localHeapViewU8().buffer, data, 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(Module.HEAPU8.buffer, buffer, buffer_len);
+ const dbg_command = new Uint8Array(localHeapViewU8().buffer, buffer, buffer_len);
const base64String = toBase64StringImpl(dbg_command);
const buffer_obj = {
res_ok,
_debugger_buffer = Module._malloc(_debugger_buffer_len);
}
const byteCharacters = atob(command_parameters);
+ const heapU8 = localHeapViewU8();
for (let i = 0; i < byteCharacters.length; i++) {
- Module.HEAPU8[<any>_debugger_buffer + i] = byteCharacters.charCodeAt(i);
+ heapU8[<any>_debugger_buffer + i] = byteCharacters.charCodeAt(i);
}
}
export function mono_wasm_set_entrypoint_breakpoint(assembly_name: CharPtr, entrypoint_method_token: number): void {
//keep these assignments, these values are used by BrowserDebugProxy
- _assembly_name_str = Module.UTF8ToString(assembly_name).concat(".dll");
+ _assembly_name_str = utf8ToString(assembly_name).concat(".dll");
_entrypoint_method_token = entrypoint_method_token;
//keep this console.assert, otherwise optimization will remove the assignments
// eslint-disable-next-line no-console
}
export function mono_wasm_debugger_log(level: number, message_ptr: CharPtr): void {
- const message = Module.UTF8ToString(message_ptr);
+ const message = utf8ToString(message_ptr);
if (INTERNAL["logging"] && typeof INTERNAL.logging["debugger"] === "function") {
INTERNAL.logging.debugger(level, message);
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import monoWasmThreads from "consts:monoWasmThreads";
+import MonoWasmThreads from "consts:monoWasmThreads";
+
import type {
DiagnosticOptions,
} from "./shared/types";
// called from C on the main thread
export function mono_wasm_event_pipe_early_startup_callback(): void {
- if (monoWasmThreads) {
+ if (MonoWasmThreads) {
return;
}
}
export async function mono_wasm_init_diagnostics(): Promise<void> {
if (diagnosticsInitialized)
return;
- if (!monoWasmThreads) {
+ if (!MonoWasmThreads) {
mono_log_warn("ignoring diagnostics options because this runtime does not support diagnostics");
return;
} else {
import monoDiagnosticsMock from "consts:monoDiagnosticsMock";
import { PromiseAndController, assertNever } from "../../types/internal";
import { pthread_self } from "../../pthreads/worker";
-import { Module, createPromiseController } from "../../globals";
+import { createPromiseController } from "../../globals";
import cwraps from "../../cwraps";
import { EventPipeSessionIDImpl } from "../shared/types";
import { CharPtr } from "../../types/emscripten";
createBinaryCommandOKReply,
} from "./ipc-protocol/serializer";
import { mono_log_error, mono_log_info, mono_log_debug, mono_log_warn } from "../../logging";
+import { utf8ToString } from "../../strings";
function addOneShotProtocolCommandEventListener(src: EventTarget): Promise<ProtocolCommandEvent> {
return new Promise((resolve) => {
/// Called by the runtime to initialize the diagnostic server workers
export function mono_wasm_diagnostic_server_on_server_thread_created(websocketUrlPtr: CharPtr): void {
- const websocketUrl = Module.UTF8ToString(websocketUrlPtr);
+ const websocketUrl = utf8ToString(websocketUrlPtr);
mono_log_debug(`mono_wasm_diagnostic_server_on_server_thread_created, url ${websocketUrl}`);
let mock: PromiseAndController<Mock> | undefined = undefined;
if (monoDiagnosticsMock && websocketUrl.startsWith("mock:")) {
import { assertNever } from "../../types/internal";
import { VoidPtr } from "../../types/emscripten";
-import { Module } from "../../globals";
import type { CommonSocket } from "./common-socket";
import { mono_log_debug, mono_log_warn } from "../../logging";
+import { localHeapViewU8 } from "../../memory";
enum ListenerState {
Sending,
Closed,
const buf = new ArrayBuffer(size);
const view = new Uint8Array(buf);
// Can we avoid this copy?
- view.set(new Uint8Array(Module.HEAPU8.buffer, data as unknown as number, size));
+ view.set(new Uint8Array(localHeapViewU8().buffer, data as unknown as number, size));
this.socket.send(buf);
}
}
__brand: "Int32Ptr";
}
declare interface EmscriptenModule {
+ /** @deprecated Please use growableHeapI8() instead.*/
HEAP8: Int8Array;
+ /** @deprecated Please use growableHeapI16() instead.*/
HEAP16: Int16Array;
+ /** @deprecated Please use growableHeapI32() instead. */
HEAP32: Int32Array;
+ /** @deprecated Please use growableHeapI64() instead. */
HEAP64: BigInt64Array;
+ /** @deprecated Please use growableHeapU8() instead. */
HEAPU8: Uint8Array;
+ /** @deprecated Please use growableHeapU16() instead. */
HEAPU16: Uint16Array;
+ /** @deprecated Please use growableHeapU32() instead */
HEAPU32: Uint32Array;
+ /** @deprecated Please use growableHeapF32() instead */
HEAPF32: Float32Array;
+ /** @deprecated Please use growableHeapF64() instead. */
HEAPF64: Float64Array;
_malloc(size: number): VoidPtr;
_free(ptr: VoidPtr): void;
getValue(ptr: number, type: string, noSafe?: number | boolean): number;
UTF8ToString(ptr: CharPtr, maxBytesToRead?: number): string;
UTF8ArrayToString(u8Array: Uint8Array, idx?: number, maxBytesToRead?: number): string;
+ stringToUTF8Array(str: string, heap: Uint8Array, outIdx: number, maxBytesToWrite: number): void;
FS_createPath(parent: string, path: string, canRead?: boolean, canWrite?: boolean): string;
FS_createDataFile(parent: string, name: string, data: TypedArray, canRead: boolean, canWrite: boolean, canOwn?: boolean): string;
addFunction(fn: Function, signature: string): number;
getHeapI64Big: (offset: NativePointer) => bigint;
getHeapF32: (offset: NativePointer) => number;
getHeapF64: (offset: NativePointer) => number;
+ localHeapViewI8: () => Int8Array;
+ localHeapViewI16: () => Int16Array;
+ localHeapViewI32: () => Int32Array;
+ localHeapViewI64Big: () => BigInt64Array;
+ localHeapViewU8: () => Uint8Array;
+ localHeapViewU16: () => Uint16Array;
+ localHeapViewU32: () => Uint32Array;
+ localHeapViewF32: () => Float32Array;
+ localHeapViewF64: () => Float64Array;
};
type RuntimeAPI = {
/**
import { mono_wasm_get_assembly_exports } from "./invoke-cs";
import { mono_wasm_set_module_imports } from "./invoke-js";
-import { getB32, getF32, getF64, getI16, getI32, getI52, getI64Big, getI8, getU16, getU32, getU52, getU8, setB32, setF32, setF64, setI16, setI32, setI52, setI64Big, setI8, setU16, setU32, setU52, setU8 } from "./memory";
+import { getB32, getF32, getF64, getI16, getI32, getI52, getI64Big, getI8, getU16, getU32, getU52, getU8, localHeapViewF32, localHeapViewF64, localHeapViewI16, localHeapViewI32, localHeapViewI64Big, localHeapViewI8, localHeapViewU16, localHeapViewU32, localHeapViewU8, setB32, setF32, setF64, setI16, setI32, setI52, setI64Big, setI8, setU16, setU32, setU52, setU8 } from "./memory";
import { mono_run_main, mono_run_main_and_exit } from "./run";
import { mono_wasm_setenv } from "./startup";
import { runtimeHelpers } from "./globals";
getHeapI64Big: getI64Big,
getHeapF32: getF32,
getHeapF64: getF64,
+ localHeapViewU8: localHeapViewU8,
+ localHeapViewU16: localHeapViewU16,
+ localHeapViewU32: localHeapViewU32,
+ localHeapViewI8: localHeapViewI8,
+ localHeapViewI16: localHeapViewI16,
+ localHeapViewI32: localHeapViewI32,
+ localHeapViewI64Big: localHeapViewI64Big,
+ localHeapViewF32: localHeapViewF32,
+ localHeapViewF64: localHeapViewF64,
};
return api;
}
import { http_wasm_supports_streaming_response, http_wasm_create_abort_controler, http_wasm_abort_request, http_wasm_abort_response, http_wasm_fetch, http_wasm_fetch_bytes, http_wasm_get_response_header_names, http_wasm_get_response_header_values, http_wasm_get_response_bytes, http_wasm_get_response_length, http_wasm_get_streamed_response_bytes } from "./http";
import { exportedRuntimeAPI, Module, runtimeHelpers } from "./globals";
import { get_property, set_property, has_property, get_typeof_property, get_global_this, dynamic_import } from "./invoke-js";
-import { mono_intern_string } from "./strings";
import { mono_wasm_stringify_as_error_with_stack } from "./logging";
import { ws_wasm_create, ws_wasm_open, ws_wasm_send, ws_wasm_receive, ws_wasm_close, ws_wasm_abort } from "./web-socket";
import { mono_wasm_get_loaded_files } from "./assets";
mono_wasm_profiler_init_aot: cwraps.mono_wasm_profiler_init_aot,
mono_wasm_profiler_init_browser: cwraps.mono_wasm_profiler_init_browser,
mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
- mono_intern_string, // MarshalTests.cs
// with mono_wasm_debugger_log and mono_wasm_trace_logger
logging: undefined,
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import { Module } from "../globals";
-import { setU16 } from "../memory";
import { mono_wasm_new_external_root } from "../roots";
-import { conv_string_root } from "../strings";
+import { monoStringToString, utf16ToStringLoop, stringToUTF16 } from "../strings";
import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal";
import { Int32Ptr } from "../types/emscripten";
import { wrap_error_root, wrap_no_error_root } from "../invoke-js";
-export function mono_wasm_change_case_invariant(src: number, srcLength: number, dst: number, dstLength: number, toUpper: number, is_exception: Int32Ptr, ex_address: MonoObjectRef) : void{
+export function mono_wasm_change_case_invariant(src: number, srcLength: number, dst: number, dstLength: number, toUpper: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): void {
const exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
- try{
- const input = get_utf16_string(src, srcLength);
+ try {
+ const input = utf16ToStringLoop(src, src + 2 * srcLength);
let result = toUpper ? input.toUpperCase() : input.toLowerCase();
// Unicode defines some codepoints which expand into multiple codepoints,
// originally we do not support this expansion
if (result.length > dstLength)
result = input;
-
- for (let i = 0; i < result.length; i++)
- setU16(dst + i*2, result.charCodeAt(i));
+ stringToUTF16(dst, dst + 2 * dstLength, result);
wrap_no_error_root(is_exception, exceptionRoot);
}
catch (ex: any) {
}
}
-export function mono_wasm_change_case(culture: MonoStringRef, src: number, srcLength: number, dst: number, destLength: number, toUpper: number, is_exception: Int32Ptr, ex_address: MonoObjectRef) : void{
+export function mono_wasm_change_case(culture: MonoStringRef, src: number, srcLength: number, dst: number, dstLength: number, toUpper: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): void {
const cultureRoot = mono_wasm_new_external_root<MonoString>(culture),
exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
- try{
- const cultureName = conv_string_root(cultureRoot);
+ try {
+ const cultureName = monoStringToString(cultureRoot);
if (!cultureName)
throw new Error("Cannot change case, the culture name is null.");
- const input = get_utf16_string(src, srcLength);
+ const input = utf16ToStringLoop(src, src + 2 * srcLength);
let result = toUpper ? input.toLocaleUpperCase(cultureName) : input.toLocaleLowerCase(cultureName);
- if (result.length > destLength)
+ if (result.length > dstLength)
result = input;
- for (let i = 0; i < destLength; i++)
- setU16(dst + i*2, result.charCodeAt(i));
+ stringToUTF16(dst, dst + 2 * dstLength, result);
wrap_no_error_root(is_exception, exceptionRoot);
}
catch (ex: any) {
cultureRoot.release();
exceptionRoot.release();
}
-}
-
-function get_utf16_string(ptr: number, length: number): string{
- const view = new Uint16Array(Module.HEAPU16.buffer, ptr, length);
- let string = "";
- for (let i = 0; i < length; i++)
- string += String.fromCharCode(view[i]);
- return string;
-}
+}
\ No newline at end of file
// The .NET Foundation licenses this file to you under the MIT license.
import { mono_wasm_new_external_root } from "../roots";
-import { conv_string_root, string_decoder } from "../strings";
+import { monoStringToString, utf16ToString } from "../strings";
import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal";
import { Int32Ptr } from "../types/emscripten";
import { wrap_error_root, wrap_no_error_root } from "../invoke-js";
const COMPARISON_ERROR = -2;
const INDEXING_ERROR = -1;
-export function mono_wasm_compare_string(culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef) : number{
+export function mono_wasm_compare_string(culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number {
const cultureRoot = mono_wasm_new_external_root<MonoString>(culture),
exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
- try{
- const cultureName = conv_string_root(cultureRoot);
- const string1 = string_decoder.decode(<any>str1, <any>(str1 + 2*str1Length));
- const string2 = string_decoder.decode(<any>str2, <any>(str2 + 2*str2Length));
+ try {
+ const cultureName = monoStringToString(cultureRoot);
+ const string1 = utf16ToString(<any>str1, <any>(str1 + 2 * str1Length));
+ const string2 = utf16ToString(<any>str2, <any>(str2 + 2 * str2Length));
const casePicker = (options & 0x1f);
const locale = cultureName ? cultureName : undefined;
wrap_no_error_root(is_exception, exceptionRoot);
}
}
-export function mono_wasm_starts_with(culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number{
+export function mono_wasm_starts_with(culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number {
const cultureRoot = mono_wasm_new_external_root<MonoString>(culture),
exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
- try{
- const cultureName = conv_string_root(cultureRoot);
+ try {
+ const cultureName = monoStringToString(cultureRoot);
const prefix = decode_to_clean_string(str2, str2Length);
// no need to look for an empty string
if (prefix.length == 0)
}
}
-export function mono_wasm_ends_with(culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number{
+export function mono_wasm_ends_with(culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number {
const cultureRoot = mono_wasm_new_external_root<MonoString>(culture),
exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
- try{
- const cultureName = conv_string_root(cultureRoot);
+ try {
+ const cultureName = monoStringToString(cultureRoot);
const suffix = decode_to_clean_string(str2, str2Length);
if (suffix.length == 0)
return 1; // true
}
}
-export function mono_wasm_index_of(culture: MonoStringRef, needlePtr: number, needleLength: number, srcPtr: number, srcLength: number, options: number, fromBeginning: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number{
+export function mono_wasm_index_of(culture: MonoStringRef, needlePtr: number, needleLength: number, srcPtr: number, srcLength: number, options: number, fromBeginning: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number {
const cultureRoot = mono_wasm_new_external_root<MonoString>(culture),
exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
try {
- const needle = string_decoder.decode(<any>needlePtr, <any>(needlePtr + 2*needleLength));
+ const needle = utf16ToString(<any>needlePtr, <any>(needlePtr + 2 * needleLength));
// no need to look for an empty string
- if (clean_string(needle).length == 0)
- {
+ if (clean_string(needle).length == 0) {
wrap_no_error_root(is_exception, exceptionRoot);
return fromBeginning ? 0 : srcLength;
}
- const source = string_decoder.decode(<any>srcPtr, <any>(srcPtr + 2*srcLength));
+ const source = utf16ToString(<any>srcPtr, <any>(srcPtr + 2 * srcLength));
// no need to look in an empty string
- if (clean_string(source).length == 0)
- {
+ if (clean_string(source).length == 0) {
wrap_no_error_root(is_exception, exceptionRoot);
return fromBeginning ? 0 : srcLength;
}
- const cultureName = conv_string_root(cultureRoot);
+ const cultureName = monoStringToString(cultureRoot);
const locale = cultureName ? cultureName : undefined;
const casePicker = (options & 0x1f);
let segmentWidth = 0;
let index = 0;
let nextIndex = 0;
- while (!stop)
- {
+ while (!stop) {
// we need to restart the iterator in this outer loop because we have shifted it in the inner loop
const iteratorSrc = segmenter.segment(source.slice(i, source.length))[Symbol.iterator]();
let srcNext = iteratorSrc.next();
let matchFound = check_match_found(srcNext.value.segment, needleSegments[0], locale, casePicker);
index = nextIndex;
srcNext = iteratorSrc.next();
- if (srcNext.done)
- {
+ if (srcNext.done) {
result = matchFound ? index : result;
break;
}
segmentWidth = srcNext.value.index;
nextIndex = index + segmentWidth;
- if (matchFound)
- {
- for(let j=1; j<needleSegments.length; j++)
- {
- if (srcNext.done)
- {
+ if (matchFound) {
+ for (let j = 1; j < needleSegments.length; j++) {
+ if (srcNext.done) {
stop = true;
break;
}
break;
}
- if (matchFound)
- {
+ if (matchFound) {
result = index;
if (fromBeginning)
break;
exceptionRoot.release();
}
- function check_match_found(str1: string, str2: string, locale: string | undefined, casePicker: number) : boolean
- {
+ function check_match_found(str1: string, str2: string, locale: string | undefined, casePicker: number): boolean {
return compare_strings(str1, str2, locale, casePicker) === 0;
}
}
-function compare_strings(string1: string, string2: string, locale: string | undefined, casePicker: number) : number{
- switch (casePicker)
- {
+function compare_strings(string1: string, string2: string, locale: string | undefined, casePicker: number): number {
+ switch (casePicker) {
case 0:
// 0: None - default algorithm for the platform OR
// StringSort - for ICU it gives the same result as None, see: https://github.com/dotnet/dotnet-api-docs/issues
}
}
-function decode_to_clean_string(strPtr: number, strLen: number)
-{
- const str = string_decoder.decode(<any>strPtr, <any>(strPtr + 2*strLen));
+function decode_to_clean_string(strPtr: number, strLen: number) {
+ const str = utf16ToString(<any>strPtr, <any>(strPtr + 2 * strLen));
return clean_string(str);
}
-function clean_string(str: string)
-{
+function clean_string(str: string) {
const nStr = str.normalize();
return nStr.replace(/[\u200B-\u200D\uFEFF\0]/g, "");
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import { setU16 } from "../memory";
import { mono_wasm_new_external_root } from "../roots";
-import { conv_string_root } from "../strings";
+import { monoStringToString, stringToUTF16 } from "../strings";
import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal";
import { Int32Ptr } from "../types/emscripten";
import { wrap_error_root, wrap_no_error_root } from "../invoke-js";
const NORMALIZATION_FORM_MAP = [undefined, "NFC", "NFD", undefined, undefined, "NFKC", "NFKD"];
const ERROR = -1;
-export function mono_wasm_is_normalized(normalizationForm: number, inputStr: MonoStringRef, is_exception: Int32Ptr, ex_address: MonoObjectRef) : number{
+export function mono_wasm_is_normalized(normalizationForm: number, inputStr: MonoStringRef, is_exception: Int32Ptr, ex_address: MonoObjectRef): number {
const inputRoot = mono_wasm_new_external_root<MonoString>(inputStr),
exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
- try{
- const jsString = conv_string_root(inputRoot);
+ try {
+ const jsString = monoStringToString(inputRoot);
if (!jsString)
throw new Error("Invalid string was received.");
}
}
-export function mono_wasm_normalize_string(normalizationForm: number, inputStr: MonoStringRef, dstPtr: number, dstLength: number, is_exception: Int32Ptr, ex_address: MonoObjectRef) : number{
+export function mono_wasm_normalize_string(normalizationForm: number, inputStr: MonoStringRef, dstPtr: number, dstLength: number, is_exception: Int32Ptr, ex_address: MonoObjectRef): number {
const inputRoot = mono_wasm_new_external_root<MonoString>(inputStr),
exceptionRoot = mono_wasm_new_external_root<MonoObject>(ex_address);
try {
- const jsString = conv_string_root(inputRoot);
+ const jsString = monoStringToString(inputRoot);
if (!jsString)
throw new Error("Invalid string was received.");
// increase the dest buffer
if (result.length > dstLength)
return result.length;
- for (let i = 0; i < result.length; i++)
- setU16(dstPtr + i*2, result.charCodeAt(i));
+ stringToUTF16(dstPtr, dstPtr + 2 * dstLength, result);
return result.length;
} catch (ex) {
wrap_error_root(is_exception, ex, exceptionRoot);
bound_cs_function_symbol, get_signature_version, alloc_stack_frame, get_signature_type,
} from "./marshal";
import { mono_wasm_new_external_root, mono_wasm_new_root } from "./roots";
-import { conv_string_root, string_decoder } from "./strings";
+import { monoStringToString, monoStringToStringUnsafe } from "./strings";
import { MonoObjectRef, MonoStringRef, MonoString, MonoObject, MonoMethod, JSMarshalerArguments, JSFunctionSignature, BoundMarshalerToCs, BoundMarshalerToJs, VoidPtrNull, MonoObjectRefNull, MonoObjectNull } from "./types/internal";
import { Int32Ptr } from "./types/emscripten";
import cwraps from "./cwraps";
mono_assert(version === 1, () => `Signature version ${version} mismatch.`);
const args_count = get_signature_argument_count(signature);
- const js_fqn = conv_string_root(fqn_root)!;
+ const js_fqn = monoStringToString(fqn_root)!;
mono_assert(js_fqn, "fully_qualified_name must be string");
mono_log_debug(`Binding [JSExport] ${js_fqn}`);
export function invoke_method_and_handle_exception(method: MonoMethod, args: JSMarshalerArguments): void {
assert_synchronization_context();
const fail = cwraps.mono_wasm_invoke_method_bound(method, args);
- if (fail) throw new Error("ERR24: Unexpected error: " + string_decoder.copy(fail));
+ if (fail) throw new Error("ERR24: Unexpected error: " + monoStringToStringUnsafe(fail));
if (is_args_exception(args)) {
const exc = get_arg(args, 0);
throw marshal_exception_to_js(exc);
try {
cwraps.mono_wasm_invoke_method_ref(method, MonoObjectRefNull, VoidPtrNull, outException.address, outResult.address);
if (outException.value !== MonoObjectNull) {
- const msg = conv_string_root(outResult)!;
+ const msg = monoStringToString(outResult)!;
throw new Error(msg);
}
}
import { marshal_exception_to_cs, bind_arg_marshal_to_cs } from "./marshal-to-cs";
import { get_signature_argument_count, bound_js_function_symbol, get_sig, get_signature_version, get_signature_type, imported_js_function_symbol } from "./marshal";
-import { setI32_unchecked } from "./memory";
-import { conv_string_root, js_string_to_mono_string_root } from "./strings";
+import { setI32, setI32_unchecked, receiveWorkerHeapViews } from "./memory";
+import { monoStringToString, stringToMonoStringRoot } from "./strings";
import { MonoObject, MonoObjectRef, MonoString, MonoStringRef, JSFunctionSignature, JSMarshalerArguments, WasmRoot, BoundMarshalerToJs, JSFnHandle, BoundMarshalerToCs, JSHandle, MarshalerType } from "./types/internal";
import { Int32Ptr } from "./types/emscripten";
import { INTERNAL, Module } from "./globals";
const version = get_signature_version(signature);
mono_assert(version === 1, () => `Signature version ${version} mismatch.`);
- const js_function_name = conv_string_root(function_name_root)!;
+ const js_function_name = monoStringToString(function_name_root)!;
const mark = startMeasure();
- const js_module_name = conv_string_root(module_name_root)!;
+ const js_module_name = monoStringToString(module_name_root)!;
mono_log_debug(`Binding [JSImport] ${js_function_name} from ${js_module_name} module`);
const fn = mono_wasm_lookup_function(js_function_name, js_module_name);
(<any>bound_fn)[imported_js_function_symbol] = true;
const fn_handle = fn_wrapper_by_fn_handle.length;
fn_wrapper_by_fn_handle.push(bound_fn);
- setI32_unchecked(function_js_handle, <any>fn_handle);
+ setI32(function_js_handle, <any>fn_handle);
wrap_no_error_root(is_exception, resultRoot);
endMeasure(mark, MeasuredBlock.bindJsFunction, js_function_name);
} catch (ex: any) {
- setI32_unchecked(function_js_handle, 0);
+ setI32(function_js_handle, 0);
Module.err(ex.toString());
wrap_error_root(is_exception, ex, resultRoot);
} finally {
res = mono_wasm_symbolicate_string(res);
}
if (is_exception) {
+ receiveWorkerHeapViews();
setI32_unchecked(is_exception, 1);
}
return res;
export function wrap_error_root(is_exception: Int32Ptr | null, ex: any, result: WasmRoot<MonoObject>): void {
const res = _wrap_error_flag(is_exception, ex);
- js_string_to_mono_string_root(res, <any>result);
+ stringToMonoStringRoot(res, <any>result);
}
// to set out parameters of icalls
export function wrap_no_error_root(is_exception: Int32Ptr | null, result?: WasmRoot<MonoObject>): void {
if (is_exception) {
+ receiveWorkerHeapViews();
setI32_unchecked(is_exception, 0);
}
if (result) {
JiterpreterOptions, getMemberOffset, JiterpMember
} from "./jiterpreter-support";
import { mono_log_error, mono_log_info } from "./logging";
+import { utf8ToString } from "./strings";
// Controls miscellaneous diagnostic output.
const trace = 0;
const info = new TrampolineInfo(
imethod, method, argumentCount, pParamTypes,
- unbox, hasThisReference, hasReturnValue, Module.UTF8ToString(<any>name),
+ unbox, hasThisReference, hasReturnValue, utf8ToString(<any>name),
defaultImplementation
);
if (!fnTable)
import { NativePointer, Int32Ptr, VoidPtr } from "./types/emscripten";
import { Module, runtimeHelpers } from "./globals";
import {
- getU8, getI32_unaligned, getU32_unaligned, setU32_unchecked
+ getU8, getI32_unaligned, getU32_unaligned, setU32_unchecked, receiveWorkerHeapViews
} from "./memory";
import { WasmOpcode } from "./jiterpreter-opcodes";
import {
} from "./jiterpreter-feature-detect";
import cwraps from "./cwraps";
import { mono_log_error, mono_log_info } from "./logging";
+import { utf8ToString } from "./strings";
// Controls miscellaneous diagnostic output.
const trace = 0;
if (useFullNames) {
const pMethodName = method ? cwraps.mono_wasm_method_get_full_name(method) : <any>0;
try {
- suffix = Module.UTF8ToString(pMethodName);
+ suffix = utf8ToString(pMethodName);
} finally {
if (pMethodName)
Module._free(<any>pMethodName);
try {
thunk(ret_sp, sp, ftndesc, thrown);
} catch (exc) {
+ receiveWorkerHeapViews();
setU32_unchecked(thrown, 1);
}
}
try {
jitCallCb(_cb_data);
} catch (exc) {
+ receiveWorkerHeapViews();
setU32_unchecked(_thrown, 1);
}
};
// Keep this file in sync with mintops.def. The order and values need to match exactly.
-import { Module } from "./globals";
import cwraps from "./cwraps";
+import { utf8ToString } from "./strings";
export const enum MintOpArgType {
MintOpNoArgs = 0,
let result = opcodeNameCache[opcode];
if (typeof (result) !== "string") {
const pName = cwraps.mono_jiterp_get_opcode_info(opcode, OpcodeInfoType.Name);
- opcodeNameCache[opcode] = result = Module.UTF8ToString(<any>pName);
+ opcodeNameCache[opcode] = result = utf8ToString(<any>pName);
}
return result;
}
import { MintOpcode } from "./mintops";
import cwraps from "./cwraps";
import { mono_log_error, mono_log_info } from "./logging";
+import { localHeapViewU8 } from "./memory";
+import { utf8ToString } from "./strings";
export const maxFailures = 2,
maxMemsetSize = 64,
constructor() {
this.capacity = 16 * 1024;
this.buffer = <any>Module._malloc(this.capacity);
- Module.HEAPU8.fill(0, this.buffer, this.buffer + this.capacity);
+ localHeapViewU8().fill(0, this.buffer, this.buffer + this.capacity);
this.size = 0;
this.clear();
if (typeof (TextEncoder) === "function")
throw new Error("Buffer full");
const result = this.size;
- Module.HEAPU8[this.buffer + (this.size++)] = value;
+ localHeapViewU8()[this.buffer + (this.size++)] = value;
return result;
}
if (typeof (count) !== "number")
count = this.size;
- Module.HEAPU8.copyWithin(destination.buffer + destination.size, this.buffer, this.buffer + count);
+ localHeapViewU8().copyWithin(destination.buffer + destination.size, this.buffer, this.buffer + count);
destination.size += count;
}
appendBytes(bytes: Uint8Array, count?: number) {
const result = this.size;
- if (bytes.buffer === Module.HEAPU8.buffer) {
+ const heapU8 = localHeapViewU8();
+ if (bytes.buffer === heapU8.buffer) {
if (typeof (count) !== "number")
count = bytes.length;
- Module.HEAPU8.copyWithin(this.buffer + result, bytes.byteOffset, bytes.byteOffset + count);
+ heapU8.copyWithin(this.buffer + result, bytes.byteOffset, bytes.byteOffset + count);
this.size += count;
} else {
if (typeof (count) === "number")
}
getArrayView(fullCapacity?: boolean) {
- return new Uint8Array(Module.HEAPU8.buffer, this.buffer, fullCapacity ? this.capacity : this.size);
+ return new Uint8Array(localHeapViewU8().buffer, this.buffer, fullCapacity ? this.capacity : this.size);
}
}
if (size > 64)
throw new Error("Scratch buffer size is 64");
- Module.HEAPU8.copyWithin(<any>scratchBuffer, <any>src, <any>src + size);
+ localHeapViewU8().copyWithin(<any>scratchBuffer, <any>src, <any>src + size);
return scratchBuffer;
}
function updateOptions() {
const pJson = cwraps.mono_jiterp_get_options_as_json();
- const json = Module.UTF8ToString(<any>pJson);
+ const json = utf8ToString(<any>pJson);
Module._free(<any>pJson);
const blob = JSON.parse(json);
// The .NET Foundation licenses this file to you under the MIT license.
import { MonoMethod } from "./types/internal";
-import { Module } from "./globals";
import { NativePointer } from "./types/emscripten";
import {
getU16, getI16,
- getU32_unaligned, getI32_unaligned, getF32_unaligned, getF64_unaligned,
+ getU32_unaligned, getI32_unaligned, getF32_unaligned, getF64_unaligned, localHeapViewU8,
} from "./memory";
import {
WasmOpcode, WasmSimdOpcode,
if (builder.options.enableSimd && getIsWasmSimdSupported()) {
builder.local("pLocals");
builder.v128_const(
- Module.HEAPU8.slice(<any>ip + 4, <any>ip + 4 + sizeOfV128)
+ localHeapViewU8().slice(<any>ip + 4, <any>ip + 4 + sizeOfV128)
);
append_simd_store(builder, ip);
} else {
import { MonoMethod } from "./types/internal";
import { NativePointer } from "./types/emscripten";
import { Module, runtimeHelpers } from "./globals";
-import {
- getU16, getU32_unaligned
-} from "./memory";
+import { getU16, getU32_unaligned, localHeapViewU8 } from "./memory";
import { WasmOpcode, getOpcodeName } from "./jiterpreter-opcodes";
import { MintOpcode } from "./mintops";
import cwraps from "./cwraps";
generateWasmBody
} from "./jiterpreter-trace-generator";
import { mono_log_error, mono_log_info, mono_log_warn } from "./logging";
+import { utf8ToString } from "./strings";
// Controls miscellaneous diagnostic output.
export const trace = 0;
let methodFullName: string | undefined;
if (mostRecentOptions.estimateHeat || (instrumentedMethodNames.length > 0) || useFullNames) {
const pMethodName = cwraps.mono_wasm_method_get_full_name(method);
- methodFullName = Module.UTF8ToString(pMethodName);
+ methodFullName = utf8ToString(pMethodName);
Module._free(<any>pMethodName);
}
- const methodName = Module.UTF8ToString(cwraps.mono_wasm_method_get_name(method));
+ const methodName = utf8ToString(cwraps.mono_wasm_method_get_name(method));
info.name = methodFullName || methodName;
const imethod = getU32_unaligned(getMemberOffset(JiterpMember.Imethod) + <any>frame);
const backBranchCount = getU32_unaligned(getMemberOffset(JiterpMember.BackwardBranchOffsetsCount) + imethod);
const pBackBranches = getU32_unaligned(getMemberOffset(JiterpMember.BackwardBranchOffsets) + imethod);
let backwardBranchTable = backBranchCount
- ? new Uint16Array(Module.HEAPU8.buffer, pBackBranches, backBranchCount)
+ ? new Uint16Array(localHeapViewU8().buffer, pBackBranches, backBranchCount)
: null;
// If we're compiling a trace that doesn't start at the beginning of a method,
for (let i = 0, c = Math.min(summaryStatCount, targetPointers.length); i < c; i++) {
const targetMethod = Number(targetPointers[i]) | 0;
const pMethodName = cwraps.mono_wasm_method_get_full_name(<any>targetMethod);
- const targetMethodName = Module.UTF8ToString(pMethodName);
+ const targetMethodName = utf8ToString(pMethodName);
const hitCount = callTargetCounts[<any>targetMethod];
Module._free(<any>pMethodName);
mono_log_info(`${targetMethodName} ${hitCount}`);
// The .NET Foundation licenses this file to you under the MIT license.
/* eslint-disable no-console */
-import { INTERNAL, Module, runtimeHelpers } from "./globals";
+import { INTERNAL, runtimeHelpers } from "./globals";
+import { utf8ToString } from "./strings";
import { CharPtr, VoidPtr } from "./types/emscripten";
const prefix = "MONO_WASM: ";
}
export function mono_wasm_trace_logger(log_domain_ptr: CharPtr, log_level_ptr: CharPtr, message_ptr: CharPtr, fatal: number, user_data: VoidPtr): void {
- const origMessage = Module.UTF8ToString(message_ptr);
+ const origMessage = utf8ToString(message_ptr);
const isFatal = !!fatal;
- const domain = Module.UTF8ToString(log_domain_ptr);
+ const domain = utf8ToString(log_domain_ptr);
const dataPtr = user_data;
- const log_level = Module.UTF8ToString(log_level_ptr);
+ const log_level = utf8ToString(log_level_ptr);
const message = `[MONO] ${origMessage}`;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import monoWasmThreads from "consts:monoWasmThreads";
+import MonoWasmThreads from "consts:monoWasmThreads";
import { isThenable } from "./cancelable-promise";
import cwraps from "./cwraps";
import { assert_not_disposed, cs_owned_js_handle_symbol, js_owned_gc_handle_symbol, mono_wasm_get_js_handle, setup_managed_proxy, teardown_managed_proxy } from "./gc-handles";
set_arg_element_type, ManagedObject, JavaScriptMarshalerArgSize
} from "./marshal";
import { get_marshaler_to_js_by_type } from "./marshal-to-js";
-import { _zero_region } from "./memory";
-import { js_string_to_mono_string_root } from "./strings";
+import { _zero_region, localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory";
+import { stringToMonoStringRoot } from "./strings";
import { GCHandle, GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToCs, MarshalerType } from "./types/internal";
import { TypedArray } from "./types/emscripten";
import { addUnsettledPromise, settleUnsettledPromise } from "./pthreads/shared/eventloop";
function _marshal_string_to_cs_impl(arg: JSMarshalerArgument, value: string) {
const root = get_string_root(arg);
try {
- js_string_to_mono_string_root(value, root);
+ stringToMonoStringRoot(value, root);
}
finally {
root.release();
const holder = new TaskCallbackHolder(value);
setup_managed_proxy(holder, gc_handle);
- if (monoWasmThreads)
+ if (MonoWasmThreads)
addUnsettledPromise();
value.then(data => {
- if (monoWasmThreads)
+ if (MonoWasmThreads)
settleUnsettledPromise();
runtimeHelpers.javaScriptExports.complete_task(gc_handle, null, data, res_converter || _marshal_cs_object_to_cs);
teardown_managed_proxy(holder, gc_handle); // this holds holder alive for finalizer, until the promise is freed, (holding promise instead would not work)
}).catch(reason => {
- if (monoWasmThreads)
+ if (MonoWasmThreads)
settleUnsettledPromise();
runtimeHelpers.javaScriptExports.complete_task(gc_handle, reason, null, undefined);
teardown_managed_proxy(holder, gc_handle); // this holds holder alive for finalizer, until the promise is freed
}
else if (element_type == MarshalerType.Byte) {
mono_assert(Array.isArray(value) || value instanceof Uint8Array, "Value is not an Array or Uint8Array");
- const targetView = Module.HEAPU8.subarray(<any>buffer_ptr, buffer_ptr + length);
+ const targetView = localHeapViewU8().subarray(<any>buffer_ptr, buffer_ptr + length);
targetView.set(value);
}
else if (element_type == MarshalerType.Int32) {
mono_assert(Array.isArray(value) || value instanceof Int32Array, "Value is not an Array or Int32Array");
- const targetView = Module.HEAP32.subarray(<any>buffer_ptr >> 2, (buffer_ptr >> 2) + length);
+ const targetView = localHeapViewI32().subarray(<any>buffer_ptr >> 2, (buffer_ptr >> 2) + length);
targetView.set(value);
}
else if (element_type == MarshalerType.Double) {
mono_assert(Array.isArray(value) || value instanceof Float64Array, "Value is not an Array or Float64Array");
- const targetView = Module.HEAPF64.subarray(<any>buffer_ptr >> 3, (buffer_ptr >> 3) + length);
+ const targetView = localHeapViewF64().subarray(<any>buffer_ptr >> 3, (buffer_ptr >> 3) + length);
targetView.set(value);
}
else {
get_signature_res_type, get_arg_u16, array_element_size, get_string_root,
ArraySegment, Span, MemoryViewType, get_signature_arg3_type, get_arg_i64_big, get_arg_intptr, get_arg_element_type, JavaScriptMarshalerArgSize
} from "./marshal";
-import { conv_string_root } from "./strings";
+import { monoStringToString } from "./strings";
import { JSHandleNull, GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToJs, MarshalerType } from "./types/internal";
import { TypedArray } from "./types/emscripten";
import { get_marshaler_to_cs_by_type } from "./marshal-to-cs";
+import { localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory";
export function initialize_marshalers_to_js(): void {
if (cs_to_js_marshalers.size == 0) {
}
const root = get_string_root(arg);
try {
- const value = conv_string_root(root);
+ const value = monoStringToString(root);
return value;
} finally {
root.release();
}
}
else if (element_type == MarshalerType.Byte) {
- const sourceView = Module.HEAPU8.subarray(<any>buffer_ptr, buffer_ptr + length);
+ const sourceView = localHeapViewU8().subarray(<any>buffer_ptr, buffer_ptr + length);
result = sourceView.slice();//copy
}
else if (element_type == MarshalerType.Int32) {
- const sourceView = Module.HEAP32.subarray(buffer_ptr >> 2, (buffer_ptr >> 2) + length);
+ const sourceView = localHeapViewI32().subarray(buffer_ptr >> 2, (buffer_ptr >> 2) + length);
result = sourceView.slice();//copy
}
else if (element_type == MarshalerType.Double) {
- const sourceView = Module.HEAPF64.subarray(buffer_ptr >> 3, (buffer_ptr >> 3) + length);
+ const sourceView = localHeapViewF64().subarray(buffer_ptr >> 3, (buffer_ptr >> 3) + length);
result = sourceView.slice();//copy
}
else {
import { js_owned_gc_handle_symbol, teardown_managed_proxy } from "./gc-handles";
import { Module, runtimeHelpers } from "./globals";
-import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8 } from "./memory";
+import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8, localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory";
import { mono_wasm_new_external_root } from "./roots";
import { GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot, MarshalerType } from "./types/internal";
import { CharPtr, TypedArray, VoidPtr } from "./types/emscripten";
_unsafe_create_view(): TypedArray {
// this view must be short lived so that it doesn't fail after wasm memory growth
// for that reason we also don't give the view out to end user and provide set/slice/copyTo API instead
- const view = this._viewType == MemoryViewType.Byte ? new Uint8Array(Module.HEAPU8.buffer, <any>this._pointer, this._length)
- : this._viewType == MemoryViewType.Int32 ? new Int32Array(Module.HEAP32.buffer, <any>this._pointer, this._length)
- : this._viewType == MemoryViewType.Double ? new Float64Array(Module.HEAPF64.buffer, <any>this._pointer, this._length)
+ const view = this._viewType == MemoryViewType.Byte ? new Uint8Array(localHeapViewU8().buffer, <any>this._pointer, this._length)
+ : this._viewType == MemoryViewType.Int32 ? new Int32Array(localHeapViewI32().buffer, <any>this._pointer, this._length)
+ : this._viewType == MemoryViewType.Double ? new Float64Array(localHeapViewF64().buffer, <any>this._pointer, this._length)
: null;
if (!view) throw new Error("NotImplementedException");
return view;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import monoWasmThreads from "consts:monoWasmThreads";
+import MonoWasmThreads from "consts:monoWasmThreads";
+
import { MemOffset, NumberOrPointer } from "./types/internal";
import { VoidPtr, CharPtr } from "./types/emscripten";
import cwraps, { I52Error } from "./cwraps";
import { Module, runtimeHelpers } from "./globals";
+import { utf8ToString } from "./strings";
const alloca_stack: Array<VoidPtr> = [];
const alloca_buffer_size = 32 * 1024;
}
export function _zero_region(byteOffset: VoidPtr, sizeBytes: number): void {
- Module.HEAP8.fill(0, <any>byteOffset, <any>byteOffset + sizeBytes);
+ localHeapViewU8().fill(0, <any>byteOffset, <any>byteOffset + sizeBytes);
}
export function setB32(offset: MemOffset, value: number | boolean): void {
+ receiveWorkerHeapViews();
const boolValue = !!value;
if (typeof (value) === "number")
assert_int_in_range(value, 0, 1);
export function setU8(offset: MemOffset, value: number): void {
assert_int_in_range(value, 0, 0xFF);
+ receiveWorkerHeapViews();
Module.HEAPU8[<any>offset] = value;
}
export function setU16(offset: MemOffset, value: number): void {
assert_int_in_range(value, 0, 0xFFFF);
+ receiveWorkerHeapViews();
Module.HEAPU16[<any>offset >>> 1] = value;
}
+// does not check for growable heap
+export function setU16_local(localView: Uint16Array, offset: MemOffset, value: number): void {
+ assert_int_in_range(value, 0, 0xFFFF);
+ localView[<any>offset >>> 1] = value;
+}
+
+// does not check for overflow nor growable heap
export function setU16_unchecked(offset: MemOffset, value: number): void {
Module.HEAPU16[<any>offset >>> 1] = value;
}
+// does not check for overflow nor growable heap
export function setU32_unchecked(offset: MemOffset, value: NumberOrPointer): void {
Module.HEAPU32[<any>offset >>> 2] = <number><any>value;
}
export function setU32(offset: MemOffset, value: NumberOrPointer): void {
assert_int_in_range(<any>value, 0, 0xFFFF_FFFF);
+ receiveWorkerHeapViews();
Module.HEAPU32[<any>offset >>> 2] = <number><any>value;
}
export function setI8(offset: MemOffset, value: number): void {
assert_int_in_range(value, -0x80, 0x7F);
+ receiveWorkerHeapViews();
Module.HEAP8[<any>offset] = value;
}
export function setI16(offset: MemOffset, value: number): void {
assert_int_in_range(value, -0x8000, 0x7FFF);
+ receiveWorkerHeapViews();
Module.HEAP16[<any>offset >>> 1] = value;
}
export function setI32_unchecked(offset: MemOffset, value: number): void {
+ receiveWorkerHeapViews();
Module.HEAP32[<any>offset >>> 2] = value;
}
export function setI32(offset: MemOffset, value: number): void {
assert_int_in_range(<any>value, -0x8000_0000, 0x7FFF_FFFF);
+ receiveWorkerHeapViews();
Module.HEAP32[<any>offset >>> 2] = value;
}
*/
export function setI52(offset: MemOffset, value: number): void {
mono_assert(Number.isSafeInteger(value), () => `Value is not a safe integer: ${value} (${typeof (value)})`);
+ receiveWorkerHeapViews();
const error = cwraps.mono_wasm_f64_to_i52(<any>offset, value);
autoThrowI52(error);
}
export function setU52(offset: MemOffset, value: number): void {
mono_assert(Number.isSafeInteger(value), () => `Value is not a safe integer: ${value} (${typeof (value)})`);
mono_assert(value >= 0, "Can't convert negative Number into UInt64");
+ receiveWorkerHeapViews();
const error = cwraps.mono_wasm_f64_to_u52(<any>offset, value);
autoThrowI52(error);
}
export function setF32(offset: MemOffset, value: number): void {
mono_assert(typeof value === "number", () => `Value is not a Number: ${value} (${typeof (value)})`);
+ receiveWorkerHeapViews();
Module.HEAPF32[<any>offset >>> 2] = value;
}
export function setF64(offset: MemOffset, value: number): void {
mono_assert(typeof value === "number", () => `Value is not a Number: ${value} (${typeof (value)})`);
+ receiveWorkerHeapViews();
Module.HEAPF64[<any>offset >>> 3] = value;
}
export function getB32(offset: MemOffset): boolean {
+ receiveWorkerHeapViews();
return !!(Module.HEAP32[<any>offset >>> 2]);
}
export function getU8(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAPU8[<any>offset];
}
export function getU16(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAPU16[<any>offset >>> 1];
}
+// does not check for growable heap
+export function getU16_local(localView: Uint16Array, offset: MemOffset): number {
+ return localView[<any>offset >>> 1];
+}
+
export function getU32(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAPU32[<any>offset >>> 2];
}
+// does not check for growable heap
+export function getU32_local(localView: Uint32Array, offset: MemOffset): number {
+ return localView[<any>offset >>> 2];
+}
+
export function getI32_unaligned(offset: MemOffset): number {
return cwraps.mono_wasm_get_i32_unaligned(<any>offset);
}
}
export function getI8(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAP8[<any>offset];
}
export function getI16(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAP16[<any>offset >>> 1];
}
+// does not check for growable heap
+export function getI16_local(localView: Int16Array, offset: MemOffset): number {
+ return localView[<any>offset >>> 1];
+}
+
export function getI32(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAP32[<any>offset >>> 2];
}
+// does not check for growable heap
+export function getI32_local(localView: Int32Array, offset: MemOffset): number {
+ return localView[<any>offset >>> 2];
+}
+
/**
* Throws for Number.MIN_SAFE_INTEGER > value > Number.MAX_SAFE_INTEGER
*/
}
export function getI64Big(offset: MemOffset): bigint {
+ receiveWorkerHeapViews();
return Module.HEAP64[<any>offset >>> 3];
}
export function getF32(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAPF32[<any>offset >>> 2];
}
export function getF64(offset: MemOffset): number {
+ receiveWorkerHeapViews();
return Module.HEAPF64[<any>offset >>> 3];
}
// and it is copied to that location. returns the address of the allocation.
export function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr {
const memoryOffset = Module._malloc(bytes.length);
- const heapBytes = new Uint8Array(Module.HEAPU8.buffer, <any>memoryOffset, bytes.length);
+ const heapBytes = new Uint8Array(localHeapViewU8().buffer, <any>memoryOffset, bytes.length);
heapBytes.set(bytes);
return memoryOffset;
}
charPtr = cwraps.mono_wasm_getenv(name);
if (<any>charPtr === 0)
return null;
- else return Module.UTF8ToString(charPtr);
+ else return utf8ToString(charPtr);
} finally {
if (charPtr) Module._free(<any>charPtr);
}
const BuiltinAtomics = globalThis.Atomics;
-export const Atomics = monoWasmThreads ? {
+export const Atomics = MonoWasmThreads ? {
storeI32(offset: MemOffset, value: number): void {
-
- BuiltinAtomics.store(Module.HEAP32, <any>offset >>> 2, value);
+ BuiltinAtomics.store(localHeapViewI32(), <any>offset >>> 2, value);
},
notifyI32(offset: MemOffset, count: number): void {
- BuiltinAtomics.notify(Module.HEAP32, <any>offset >>> 2, count);
+ BuiltinAtomics.notify(localHeapViewI32(), <any>offset >>> 2, count);
}
} : {
storeI32: setI32,
notifyI32: () => { /*empty*/ }
};
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewI8(): Int8Array {
+ receiveWorkerHeapViews();
+ return Module.HEAP8;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewI16(): Int16Array {
+ receiveWorkerHeapViews();
+ return Module.HEAP16;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewI32(): Int32Array {
+ receiveWorkerHeapViews();
+ return Module.HEAP32;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewI64Big(): BigInt64Array {
+ receiveWorkerHeapViews();
+ return Module.HEAP64;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewU8(): Uint8Array {
+ receiveWorkerHeapViews();
+ return Module.HEAPU8;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewU16(): Uint16Array {
+ receiveWorkerHeapViews();
+ return Module.HEAPU16;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewU32(): Uint32Array {
+ receiveWorkerHeapViews();
+ return Module.HEAPU32;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewF32(): Float32Array {
+ receiveWorkerHeapViews();
+ return Module.HEAPF32;
+}
+
+// returns memory view which is valid within current synchronous call stack
+export function localHeapViewF64(): Float64Array {
+ receiveWorkerHeapViews();
+ return Module.HEAPF64;
+}
+
+// when we run with multithreading enabled, we need to make sure that the memory views are updated on each worker
+// on non-MT build, this will be a no-op trimmed by rollup
+export function receiveWorkerHeapViews() {
+ if (!MonoWasmThreads) return;
+ if (Module.wasmMemory!.buffer != Module.HEAPU8.buffer) {
+ runtimeHelpers.updateMemoryViews();
+ }
+}
+
+const sharedArrayBufferDefined = typeof SharedArrayBuffer !== "undefined";
+export function isSharedArrayBuffer(buffer: any): buffer is SharedArrayBuffer {
+ if (!MonoWasmThreads) return false;
+ // this condition should be eliminated by rollup on non-threading builds
+ return sharedArrayBufferDefined && buffer[Symbol.toStringTag] === "SharedArrayBuffer";
+}
\ No newline at end of file
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import { Module } from "../globals";
import { wrap_error_root, wrap_no_error_root } from "../invoke-js";
import { mono_wasm_new_external_root } from "../roots";
import { MonoArray, MonoObjectRef, MonoObject } from "../types/internal";
import { Int32Ptr, TypedArray } from "../types/emscripten";
import { js_to_mono_obj_root } from "./js-to-cs";
+import { localHeapViewU8 } from "../memory";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function mono_wasm_typed_array_from_ref(pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number, type: number, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
// offset index into the view
const offset = begin * bytes_per_element;
// Set view bytes to value from HEAPU8
- typedarrayBytes.set(Module.HEAPU8.subarray(<any>pinned_array + offset, <any>pinned_array + offset + num_of_bytes));
+ typedarrayBytes.set(localHeapViewU8().subarray(<any>pinned_array + offset, <any>pinned_array + offset + num_of_bytes));
return num_of_bytes;
}
else {
import { ManagedObject } from "../marshal";
import { getU32, getI32, getF32, getF64, setI32_unchecked } from "../memory";
import { mono_wasm_new_root, mono_wasm_new_external_root } from "../roots";
-import { conv_string_root, string_decoder } from "../strings";
+import { monoStringToString, monoStringToStringUnsafe } from "../strings";
import { legacyManagedExports } from "./corebindings";
import { legacyHelpers } from "./globals";
import { js_to_mono_obj_root } from "./js-to-cs";
throw new Error("int64 not available");
case MarshalType.STRING:
case MarshalType.STRING_INTERNED:
- return conv_string_root(root);
+ return monoStringToString(root);
case MarshalType.VT:
throw new Error("no idea on how to unbox value types");
case MarshalType.DELEGATE:
nameRoot = mono_wasm_new_external_root<MonoString>(core_name),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
- const js_name = conv_string_root(nameRoot);
+ const js_name = monoStringToString(nameRoot);
if (!js_name) {
wrap_error_root(is_exception, "Invalid name @" + nameRoot.value, resultRoot);
return;
*/
export function conv_string(mono_obj: MonoString): string | null {
assert_legacy_interop();
- return string_decoder.copy(mono_obj);
+ return monoStringToStringUnsafe(mono_obj);
}
\ No newline at end of file
import { mono_wasm_new_root_buffer, mono_wasm_new_root, mono_wasm_new_external_root, mono_wasm_release_roots } from "../roots";
import { mono_run_main, mono_run_main_and_exit } from "../run";
import { mono_wasm_setenv } from "../startup";
-import { js_string_to_mono_string, js_string_to_mono_string_root, conv_string_root } from "../strings";
+import { stringToMonoStringRoot, monoStringToString } from "../strings";
import { mono_array_to_js_array, unbox_mono_obj, unbox_mono_obj_root, mono_array_root_to_js_array, conv_string } from "./cs-to-js";
import { js_typed_array_to_array, js_to_mono_obj, js_typed_array_to_array_root, js_to_mono_obj_root } from "./js-to-cs";
import { mono_bind_static_method, mono_call_assembly_entry_point } from "./method-calls";
import { mono_wasm_load_data_archive } from "../assets";
import { mono_method_resolve } from "./method-binding";
import { runtimeHelpers } from "../globals";
+import { js_string_to_mono_string } from "./strings";
export function export_mono_api(): MONOType {
return {
mono_obj_array_new_ref: <any>null,
mono_obj_array_set_ref: <any>null,
- js_string_to_mono_string_root,
+ js_string_to_mono_string_root: stringToMonoStringRoot,
js_typed_array_to_array_root,
js_to_mono_obj_root,
- conv_string_root,
+ conv_string_root: monoStringToString,
unbox_mono_obj_root,
mono_array_root_to_js_array,
};
import { js_owned_gc_handle_symbol, assert_not_disposed, cs_owned_js_handle_symbol, mono_wasm_get_js_handle, setup_managed_proxy, mono_wasm_release_cs_owned_object, teardown_managed_proxy, mono_wasm_get_jsobj_from_js_handle } from "../gc-handles";
import { Module } from "../globals";
import { wrap_error_root, wrap_no_error_root } from "../invoke-js";
-import { setI32_unchecked, setU32_unchecked, setF64, setB32 } from "../memory";
+import { setI32_unchecked, setU32_unchecked, setF64, setB32, localHeapViewU8 } from "../memory";
import { mono_wasm_new_root, mono_wasm_release_roots, mono_wasm_new_external_root } from "../roots";
-import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root } from "../strings";
+import { stringToMonoStringRoot, stringToInternedMonoStringRoot } from "../strings";
import { MonoObject, is_nullish, MonoClass, MonoArray, MonoObjectNull, JSHandle, MonoObjectRef, JSHandleNull, JSHandleDisposed, WasmRoot } from "../types/internal";
import { TypedArray, Int32Ptr } from "../types/emscripten";
import { has_backing_array_buffer } from "./buffers";
return;
}
case typeof js_obj === "string":
- js_string_to_mono_string_root(js_obj, <any>result);
+ stringToMonoStringRoot(js_obj, <any>result);
return;
case typeof js_obj === "symbol":
- js_string_to_mono_string_interned_root(js_obj, <any>result);
+ stringToInternedMonoStringRoot(js_obj, <any>result);
return;
case typeof js_obj === "boolean":
setB32(legacyHelpers._box_buffer, js_obj);
// https://github.com/Planeshifter/emscripten-examples/blob/master/01_PassingArrays/sum_post.js
function js_typedarray_to_heap(typedArray: TypedArray) {
+ assert_legacy_interop();
const numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
const ptr = Module._malloc(numBytes);
- const heapBytes = new Uint8Array(Module.HEAPU8.buffer, <any>ptr, numBytes);
+ const heapU8 = localHeapViewU8();
+ const heapBytes = new Uint8Array(heapU8.buffer, <any>ptr, numBytes);
heapBytes.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, numBytes));
+ // WARNING: returned memory view will get stale when linear memory grows on another thread. This is legacy interop so we don't try to fix it. The view will be fine when used in synchronous calls.
return heapBytes;
}
import { parseFQN } from "../invoke-cs";
import { setI32, setU32, setF32, setF64, setU52, setI52, setB32, setI32_unchecked, setU32_unchecked, _zero_region, _create_temp_frame, getB32, getI32, getU32, getF32, getF64 } from "../memory";
import { mono_wasm_new_external_root, mono_wasm_new_root } from "../roots";
-import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root, conv_string_root } from "../strings";
+import { stringToMonoStringRoot, stringToInternedMonoStringRoot, monoStringToString } from "../strings";
import { MonoMethod, MonoObject, VoidPtrNull, MarshalType, MonoString, MonoObjectNull, WasmRootBuffer, WasmRoot } from "../types/internal";
import { VoidPtr } from "../types/emscripten";
import { legacyManagedExports } from "./corebindings";
export function _create_primitive_converters(): void {
const result = primitiveConverters;
result.set("m", { steps: [{}], size: 0 });
- result.set("s", { steps: [{ convert_root: js_string_to_mono_string_root.bind(Module) }], size: 0, needs_root: true });
- result.set("S", { steps: [{ convert_root: js_string_to_mono_string_interned_root.bind(Module) }], size: 0, needs_root: true });
+ result.set("s", { steps: [{ convert_root: stringToMonoStringRoot.bind(Module) }], size: 0, needs_root: true });
+ result.set("S", { steps: [{ convert_root: stringToInternedMonoStringRoot.bind(Module) }], size: 0, needs_root: true });
// note we also bind first argument to false for both _js_to_mono_obj and _js_to_mono_uri,
// because we will root the reference, so we don't need in-flight reference
// also as those are callback arguments and we don't have platform code which would release the in-flight reference on C# end
if (exception.value === MonoObjectNull)
return null;
- const msg = conv_string_root(result);
+ const msg = monoStringToString(result);
const err = new Error(msg!); //the convention is that invoke_method ToString () any outgoing exception
// console.warn (`error ${msg} at location ${err.stack});
return err;
import { _release_temp_frame } from "../memory";
import { mono_wasm_new_external_root, mono_wasm_new_root } from "../roots";
import { find_entry_point } from "../run";
-import { conv_string_root, js_string_to_mono_string_root } from "../strings";
+import { monoStringToString, stringToMonoStringRoot } from "../strings";
import { JSHandle, MonoStringRef, MonoObjectRef, MonoArray, MonoString, MonoObject, is_nullish, WasmRoot } from "../types/internal";
import { Int32Ptr, VoidPtr } from "../types/emscripten";
import { mono_array_root_to_js_array, unbox_mono_obj_root } from "./cs-to-js";
nameRoot = mono_wasm_new_external_root<MonoString>(method_name),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
- const js_name = conv_string_root(nameRoot);
+ const js_name = monoStringToString(nameRoot);
if (!js_name || (typeof (js_name) !== "string")) {
wrap_error_root(is_exception, "ERR12: Invalid method name object @" + nameRoot.value, resultRoot);
return;
const nameRoot = mono_wasm_new_external_root<MonoString>(property_name),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
- const js_name = conv_string_root(nameRoot);
+ const js_name = monoStringToString(nameRoot);
if (!js_name) {
wrap_error_root(is_exception, "Invalid property name object '" + nameRoot.value + "'", resultRoot);
return;
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
- const property = conv_string_root(nameRoot);
+ const property = monoStringToString(nameRoot);
if (!property) {
wrap_error_root(is_exception, "Invalid property name object '" + property_name + "'", resultRoot);
return;
const nameRoot = mono_wasm_new_external_root<MonoString>(global_name),
resultRoot = mono_wasm_new_external_root(result_address);
try {
- const js_name = conv_string_root(nameRoot);
+ const js_name = monoStringToString(nameRoot);
let globalObj;
} catch (ex: any) {
const exceptionJsString = ex.message + "\n" + ex.stack;
const exceptionRoot = mono_wasm_new_root<MonoString>();
- js_string_to_mono_string_root(exceptionJsString, exceptionRoot);
+ stringToMonoStringRoot(exceptionJsString, exceptionRoot);
exceptionRoot.copy_to_address(<any>exceptionMessage);
exceptionRoot.release();
return 0;
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+import { assert_legacy_interop } from "../pthreads/shared";
+import { mono_wasm_new_root } from "../roots";
+import { stringToMonoStringRoot } from "../strings";
+import { MonoString } from "../types/internal";
+
+/**
+ * @deprecated Not GC or thread safe
+ */
+export function js_string_to_mono_string(string: string): MonoString {
+ assert_legacy_interop();
+ const temp = mono_wasm_new_root<MonoString>();
+ try {
+ stringToMonoStringRoot(string, temp);
+ return temp.value;
+ } finally {
+ temp.release();
+ }
+}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import { ENVIRONMENT_IS_WEB, Module, runtimeHelpers } from "./globals";
+import { ENVIRONMENT_IS_WEB, runtimeHelpers } from "./globals";
import { MonoMethod, AOTProfilerOptions, BrowserProfilerOptions } from "./types/internal";
import cwraps from "./cwraps";
+import { utf8ToString } from "./strings";
// Initialize the AOT profiler with OPTIONS.
// Requires the AOT profiler to be linked into the app.
let methodName = methodNames.get(method as any);
if (!methodName) {
const chars = cwraps.mono_wasm_method_get_name(method);
- methodName = Module.UTF8ToString(chars);
+ methodName = utf8ToString(chars);
methodNames.set(method as any, methodName);
}
globalThis.performance.measure(methodName, options);
import { Module } from "./globals";
import { VoidPtr, ManagedPointer, NativePointer } from "./types/emscripten";
import { MonoObjectRef, MonoObjectRefNull, MonoObject, is_nullish, WasmRoot, WasmRootBuffer } from "./types/internal";
-import { _zero_region } from "./memory";
+import { _zero_region, localHeapViewU32 } from "./memory";
const maxScratchRoots = 8192;
let _scratch_root_buffer: WasmRootBuffer | null = null;
get(index: number): ManagedPointer {
this._check_in_range(index);
const offset = this.get_address_32(index);
- return <any>Module.HEAPU32[offset];
+ return <any>localHeapViewU32()[offset];
}
set(index: number, value: ManagedPointer): ManagedPointer {
}
_unsafe_get(index: number): number {
- return Module.HEAPU32[this.__offset32 + index];
+ return localHeapViewU32()[this.__offset32 + index];
}
_unsafe_set(index: number, value: ManagedPointer | NativePointer): void {
// .set performs an expensive write barrier, and that is not necessary in most cases
// for clear since clearing a root cannot cause new objects to survive a GC
const address32 = this.__buffer.get_address_32(this.__index);
- Module.HEAPU32[address32] = 0;
+ localHeapViewU32()[address32] = 0;
}
release(): void {
}
get(): T {
- const result = Module.HEAPU32[this.__external_address_32];
+ const result = localHeapViewU32()[this.__external_address_32];
return <any>result;
}
clear(): void {
// .set performs an expensive write barrier, and that is not necessary in most cases
// for clear since clearing a root cannot cause new objects to survive a GC
- Module.HEAPU32[<any>this.__external_address >>> 2] = 0;
+ localHeapViewU32()[<any>this.__external_address >>> 2] = 0;
}
release(): void {
}
const copy = MonoWasmThreads
// storing SHaredArrayBuffer in the cache is not working
- ? (new Int8Array(memory)).slice(0)
+ ? (new Uint8Array(memory)).slice(0)
: memory;
const responseToCache = new Response(copy, {
import { initialize_marshalers_to_js } from "./marshal-to-js";
import { init_polyfills_async } from "./polyfills";
import * as pthreads_worker from "./pthreads/worker";
-import { string_decoder } from "./strings";
+import { strings_init, utf8ToString } from "./strings";
import { init_managed_exports } from "./managed-exports";
import { cwraps_internal } from "./exports-internal";
import { CharPtr, InstantiateWasmCallBack, InstantiateWasmSuccessCallback } from "./types/emscripten";
import { BINDING, MONO } from "./net6-legacy/globals";
import { mono_log_debug, mono_log_warn } from "./logging";
import { install_synchronization_context } from "./pthreads/shared";
+import { localHeapViewU8 } from "./memory";
// default size if MonoConfig.pthreadPoolSize is undefined
bindings_init();
if (!runtimeHelpers.mono_wasm_runtime_is_ready) mono_wasm_runtime_ready();
- setTimeout(() => {
- // when there are free CPU cycles
- string_decoder.init_fields();
- });
-
if (runtimeHelpers.config.startupOptions && INTERNAL.resourceLoader) {
if (INTERNAL.resourceLoader.bootConfig.debugBuild && INTERNAL.resourceLoader.bootConfig.cacheBootResources) {
INTERNAL.resourceLoader.logToConsole();
if (runtimeHelpers.loadedMemorySnapshot) {
// get the bytes after we re-sized the memory, so that we don't have too much memory in use at the same time
const memoryBytes = await getMemorySnapshot();
- mono_assert(memoryBytes!.byteLength === Module.HEAP8.byteLength, "Loaded memory is not the expected size");
- Module.HEAP8.set(new Int8Array(memoryBytes!), 0);
+ const heapU8 = localHeapViewU8();
+ mono_assert(memoryBytes!.byteLength === heapU8.byteLength, "Loaded memory is not the expected size");
+ heapU8.set(new Uint8Array(memoryBytes!), 0);
mono_log_debug("Loaded WASM linear memory from browser cache");
// all things below are loaded from the snapshot
if (runtimeHelpers.config.startupMemoryCache) {
// this would install the mono_jiterp_do_jit_call_indirect
cwraps.mono_jiterp_update_jit_call_dispatcher(-1);
- await storeMemorySnapshot(Module.HEAP8.buffer);
+ await storeMemorySnapshot(localHeapViewU8().buffer);
runtimeHelpers.storeMemorySnapshotPending = false;
}
runtimeHelpers.mono_wasm_bindings_is_ready = true;
try {
const mark = startMeasure();
+ strings_init();
init_managed_exports();
if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop && !ENVIRONMENT_IS_PTHREAD) {
init_legacy_exports();
// Only trigger this codepath for assemblies loaded after app is ready
if (runtimeHelpers.mono_wasm_runtime_is_ready !== true)
return;
-
- const assembly_name_str = assembly_name !== CharPtrNull ? Module.UTF8ToString(assembly_name).concat(".dll") : "";
- const assembly_data = new Uint8Array(Module.HEAPU8.buffer, assembly_ptr, assembly_len);
+ 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_b64 = toBase64StringImpl(assembly_data);
let pdb_b64;
if (pdb_ptr) {
- const pdb_data = new Uint8Array(Module.HEAPU8.buffer, pdb_ptr, pdb_len);
+ const pdb_data = new Uint8Array(heapU8.buffer, pdb_ptr, pdb_len);
pdb_b64 = toBase64StringImpl(pdb_data);
}
// The .NET Foundation licenses this file to you under the MIT license.
import { mono_wasm_new_root_buffer } from "./roots";
-import { MonoString, MonoStringNull, is_nullish, WasmRoot, WasmRootBuffer } from "./types/internal";
+import { MonoString, MonoStringNull, WasmRoot, WasmRootBuffer } from "./types/internal";
import { Module } from "./globals";
import cwraps from "./cwraps";
import { mono_wasm_new_root } from "./roots";
-import { getI32, getU32 } from "./memory";
+import { isSharedArrayBuffer, localHeapViewU8, getU32_local, setU16_local, localHeapViewU32, getU16_local, localHeapViewU16 } from "./memory";
import { NativePointer, CharPtr } from "./types/emscripten";
-import { assert_legacy_interop } from "./pthreads/shared";
-export class StringDecoder {
-
- private mono_wasm_string_root: any;
- private mono_text_decoder: TextDecoder | undefined | null;
- private mono_wasm_string_decoder_buffer: NativePointer | undefined;
-
- init_fields(): void {
- if (!this.mono_wasm_string_decoder_buffer) {
- this.mono_text_decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-16le") : null;
- this.mono_wasm_string_root = mono_wasm_new_root();
- this.mono_wasm_string_decoder_buffer = Module._malloc(12);
+export const interned_js_string_table = new Map<string, MonoString>();
+export const mono_wasm_empty_string = "";
+let mono_wasm_string_root: any;
+let mono_wasm_string_decoder_buffer: NativePointer | undefined;
+export const interned_string_table = new Map<MonoString, string>();
+let _empty_string_ptr: MonoString = <any>0;
+const _interned_string_full_root_buffers = [];
+let _interned_string_current_root_buffer: WasmRootBuffer | null = null;
+let _interned_string_current_root_buffer_count = 0;
+let _text_decoder_utf16: TextDecoder | undefined | null;
+let _text_decoder_utf8_relaxed: TextDecoder | undefined = undefined;
+let _text_decoder_utf8_validating: TextDecoder | undefined = undefined;
+let _text_encoder_utf8: TextEncoder | undefined = undefined;
+
+export function strings_init(): void {
+ if (!mono_wasm_string_decoder_buffer) {
+ if (typeof TextDecoder !== "undefined") {
+ _text_decoder_utf16 = new TextDecoder("utf-16le");
+ _text_decoder_utf8_relaxed = new TextDecoder("utf-8", { fatal: false });
+ _text_decoder_utf8_validating = new TextDecoder("utf-8");
+ _text_encoder_utf8 = new TextEncoder();
}
+ mono_wasm_string_root = mono_wasm_new_root();
+ mono_wasm_string_decoder_buffer = Module._malloc(12);
}
+}
- /**
- * @deprecated Not GC or thread safe
- */
- copy(mono_string: MonoString): string | null {
- this.init_fields();
- if (mono_string === MonoStringNull)
- return null;
-
- this.mono_wasm_string_root.value = mono_string;
- const result = this.copy_root(this.mono_wasm_string_root);
- this.mono_wasm_string_root.value = MonoStringNull;
- return result;
+export function stringToUTF8(str: string): Uint8Array {
+ if (_text_encoder_utf8 === undefined) {
+ const buffer = new Uint8Array(str.length * 2);
+ Module.stringToUTF8Array(str, buffer, 0, str.length * 2);
+ return buffer;
}
+ return _text_encoder_utf8.encode(str);
+}
- copy_root(root: WasmRoot<MonoString>): string | null {
- this.init_fields();
- if (root.value === MonoStringNull)
- return null;
-
- const ppChars = <any>this.mono_wasm_string_decoder_buffer + 0,
- pLengthBytes = <any>this.mono_wasm_string_decoder_buffer + 4,
- pIsInterned = <any>this.mono_wasm_string_decoder_buffer + 8;
-
- cwraps.mono_wasm_string_get_data_ref(root.address, <any>ppChars, <any>pLengthBytes, <any>pIsInterned);
-
- let result = undefined;
- const lengthBytes = getI32(pLengthBytes),
- pChars = getU32(ppChars),
- isInterned = getI32(pIsInterned);
-
- if (isInterned)
- result = interned_string_table.get(root.value)!;
-
- if (result === undefined) {
- if (lengthBytes && pChars) {
- result = this.decode(<any>pChars, <any>pChars + lengthBytes);
- if (isInterned)
- interned_string_table.set(root.value, result);
- } else
- result = mono_wasm_empty_string;
- }
+export function utf8ToStringRelaxed(buffer: Uint8Array): string {
+ if (_text_decoder_utf8_relaxed === undefined) {
+ return Module.UTF8ArrayToString(buffer, 0, buffer.byteLength);
+ }
+ return _text_decoder_utf8_relaxed.decode(buffer);
+}
- if (result === undefined)
- throw new Error(`internal error when decoding string at location ${root.value}`);
+export function utf8ToString(ptr: CharPtr): string {
+ const heapU8 = localHeapViewU8();
+ return utf8BufferToString(heapU8, ptr as any, heapU8.length - (ptr as any));
+}
- return result;
+export function utf8BufferToString(heapOrArray: Uint8Array, idx: number, maxBytesToRead: number): string {
+ const endIdx = idx + maxBytesToRead;
+ let endPtr = idx;
+ while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
+ if (endPtr - idx <= 16) {
+ return Module.UTF8ArrayToString(heapOrArray, idx, maxBytesToRead);
}
+ if (_text_decoder_utf8_validating === undefined) {
+ return Module.UTF8ArrayToString(heapOrArray, idx, maxBytesToRead);
+ }
+ const view = viewOrCopy(heapOrArray, idx as any, endPtr as any);
+ return _text_decoder_utf8_validating.decode(view);
+}
- decode(start: CharPtr, end: CharPtr): string {
- let str = "";
- if (this.mono_text_decoder) {
- // When threading is enabled, TextDecoder does not accept a view of a
- // SharedArrayBuffer, we must make a copy of the array first.
- // See https://github.com/whatwg/encoding/issues/172
- const subArray = typeof SharedArrayBuffer !== "undefined" && Module.HEAPU8.buffer instanceof SharedArrayBuffer
- ? Module.HEAPU8.slice(<any>start, <any>end)
- : Module.HEAPU8.subarray(<any>start, <any>end);
-
- str = this.mono_text_decoder.decode(subArray);
- } else {
- for (let i = 0; i < <any>end - <any>start; i += 2) {
- const char = Module.getValue(<any>start + i, "i16");
- str += String.fromCharCode(char);
- }
- }
-
- return str;
+export function utf16ToString(startPtr: number, endPtr: number): string {
+ if (_text_decoder_utf16) {
+ const subArray = viewOrCopy(localHeapViewU8(), startPtr as any, endPtr as any);
+ return _text_decoder_utf16.decode(subArray);
+ } else {
+ return utf16ToStringLoop(startPtr, endPtr);
}
}
-const interned_string_table = new Map<MonoString, string>();
-export const interned_js_string_table = new Map<string, MonoString>();
-let _empty_string_ptr: MonoString = <any>0;
-const _interned_string_full_root_buffers = [];
-let _interned_string_current_root_buffer: WasmRootBuffer | null = null;
-let _interned_string_current_root_buffer_count = 0;
-export const string_decoder = new StringDecoder();
-export const mono_wasm_empty_string = "";
+export function utf16ToStringLoop(startPtr: number, endPtr: number): string {
+ let str = "";
+ const heapU16 = localHeapViewU16();
+ for (let i = startPtr; i < endPtr; i += 2) {
+ const char = getU16_local(heapU16, i);
+ str += String.fromCharCode(char);
+ }
+ return str;
+}
-export function conv_string_root(root: WasmRoot<MonoString>): string | null {
- return string_decoder.copy_root(root);
+export function stringToUTF16(dstPtr: number, endPtr: number, text: string) {
+ const heapI16 = localHeapViewU16();
+ const len = text.length;
+ for (let i = 0; i < len; i++) {
+ setU16_local(heapI16, dstPtr, text.charCodeAt(i));
+ dstPtr += 2;
+ if (dstPtr >= endPtr) break;
+ }
}
-// Ensures the string is already interned on both the managed and JavaScript sides,
-// then returns the interned string value (to provide fast reference comparisons like C#)
-export function mono_intern_string(string: string): string {
- if (string.length === 0)
- return mono_wasm_empty_string;
-
- // HACK: This would normally be unsafe, but the return value of js_string_to_mono_string_interned is always an
- // interned string, so the address will never change and it is safe for us to use the raw pointer. Don't do this though
- const ptr = js_string_to_mono_string_interned(string);
- const result = interned_string_table.get(ptr);
- if (is_nullish(result))
- throw new Error("internal error: interned_string_table did not contain string after js_string_to_mono_string_interned");
+/* @deprecated not GC safe, use monoStringToString */
+export function monoStringToStringUnsafe(mono_string: MonoString): string | null {
+ if (mono_string === MonoStringNull)
+ return null;
+
+ mono_wasm_string_root.value = mono_string;
+ const result = monoStringToString(mono_wasm_string_root);
+ mono_wasm_string_root.value = MonoStringNull;
return result;
}
-function _store_string_in_intern_table(string: string, root: WasmRoot<MonoString>, internIt: boolean): void {
- if (!root.value)
- throw new Error("null pointer passed to _store_string_in_intern_table");
+export function monoStringToString(root: WasmRoot<MonoString>): string | null {
+ if (root.value === MonoStringNull)
+ return null;
- const internBufferSize = 8192;
+ const ppChars = <any>mono_wasm_string_decoder_buffer + 0,
+ pLengthBytes = <any>mono_wasm_string_decoder_buffer + 4,
+ pIsInterned = <any>mono_wasm_string_decoder_buffer + 8;
- if (_interned_string_current_root_buffer_count >= internBufferSize) {
- _interned_string_full_root_buffers.push(_interned_string_current_root_buffer);
- _interned_string_current_root_buffer = null;
- }
- if (!_interned_string_current_root_buffer) {
- _interned_string_current_root_buffer = mono_wasm_new_root_buffer(internBufferSize, "interned strings");
- _interned_string_current_root_buffer_count = 0;
- }
+ cwraps.mono_wasm_string_get_data_ref(root.address, <any>ppChars, <any>pLengthBytes, <any>pIsInterned);
- const rootBuffer = _interned_string_current_root_buffer;
- const index = _interned_string_current_root_buffer_count++;
+ let result = undefined;
+ const heapU32 = localHeapViewU32();
+ const lengthBytes = getU32_local(heapU32, pLengthBytes),
+ pChars = getU32_local(heapU32, ppChars),
+ isInterned = getU32_local(heapU32, pIsInterned);
- // Store the managed string into the managed intern table. This can theoretically
- // provide a different managed object than the one we passed in, so update our
- // pointer (stored in the root) with the result.
- if (internIt) {
- cwraps.mono_wasm_intern_string_ref(root.address);
- if (!root.value)
- throw new Error("mono_wasm_intern_string_ref produced a null pointer");
+ if (isInterned)
+ result = interned_string_table.get(root.value)!;
+
+ if (result === undefined) {
+ if (lengthBytes && pChars) {
+ result = utf16ToString(<any>pChars, <any>pChars + lengthBytes);
+ if (isInterned)
+ interned_string_table.set(root.value, result);
+ } else
+ result = mono_wasm_empty_string;
}
- interned_js_string_table.set(string, root.value);
- interned_string_table.set(root.value, string);
+ if (result === undefined)
+ throw new Error(`internal error when decoding string at location ${root.value}`);
- if ((string.length === 0) && !_empty_string_ptr)
- _empty_string_ptr = root.value;
+ return result;
+}
- // Copy the final pointer into our interned string root buffer to ensure the string
- // remains rooted. TODO: Is this actually necessary?
- rootBuffer.copy_value_from_address(index, root.address);
+export function stringToMonoStringRoot(string: string, result: WasmRoot<MonoString>): void {
+ result.clear();
+
+ if (string === null)
+ return;
+ else if (typeof (string) === "symbol")
+ stringToInternedMonoStringRoot(string, result);
+ else if (typeof (string) !== "string")
+ throw new Error("Expected string argument, got " + typeof (string));
+ else if (string.length === 0)
+ // Always use an interned pointer for empty strings
+ stringToInternedMonoStringRoot(string, result);
+ else {
+ // Looking up large strings in the intern table will require the JS runtime to
+ // potentially hash them and then do full byte-by-byte comparisons, which is
+ // very expensive. Because we can not guarantee it won't happen, try to minimize
+ // the cost of this and prevent performance issues for large strings
+ if (string.length <= 256) {
+ const interned = interned_js_string_table.get(string);
+ if (interned) {
+ result.set(interned);
+ return;
+ }
+ }
+
+ js_string_to_mono_string_new_root(string, result);
+ }
}
-export function js_string_to_mono_string_interned_root(string: string | symbol, result: WasmRoot<MonoString>): void {
+export function stringToInternedMonoStringRoot(string: string | symbol, result: WasmRoot<MonoString>): void {
let text: string | undefined;
if (typeof (string) === "symbol") {
text = string.description;
_store_string_in_intern_table(text, result, true);
}
-export function js_string_to_mono_string_root(string: string, result: WasmRoot<MonoString>): void {
- result.clear();
+function _store_string_in_intern_table(string: string, root: WasmRoot<MonoString>, internIt: boolean): void {
+ if (!root.value)
+ throw new Error("null pointer passed to _store_string_in_intern_table");
- if (string === null)
- return;
- else if (typeof (string) === "symbol")
- js_string_to_mono_string_interned_root(string, result);
- else if (typeof (string) !== "string")
- throw new Error("Expected string argument, got " + typeof (string));
- else if (string.length === 0)
- // Always use an interned pointer for empty strings
- js_string_to_mono_string_interned_root(string, result);
- else {
- // Looking up large strings in the intern table will require the JS runtime to
- // potentially hash them and then do full byte-by-byte comparisons, which is
- // very expensive. Because we can not guarantee it won't happen, try to minimize
- // the cost of this and prevent performance issues for large strings
- if (string.length <= 256) {
- const interned = interned_js_string_table.get(string);
- if (interned) {
- result.set(interned);
- return;
- }
- }
+ const internBufferSize = 8192;
- js_string_to_mono_string_new_root(string, result);
+ if (_interned_string_current_root_buffer_count >= internBufferSize) {
+ _interned_string_full_root_buffers.push(_interned_string_current_root_buffer);
+ _interned_string_current_root_buffer = null;
+ }
+ if (!_interned_string_current_root_buffer) {
+ _interned_string_current_root_buffer = mono_wasm_new_root_buffer(internBufferSize, "interned strings");
+ _interned_string_current_root_buffer_count = 0;
}
-}
-export function js_string_to_mono_string_new_root(string: string, result: WasmRoot<MonoString>): void {
- const buffer = Module._malloc((string.length + 1) * 2);
- const buffer16 = (<any>buffer >>> 1) | 0;
- for (let i = 0; i < string.length; i++)
- Module.HEAP16[buffer16 + i] = string.charCodeAt(i);
- Module.HEAP16[buffer16 + string.length] = 0;
- cwraps.mono_wasm_string_from_utf16_ref(<any>buffer, string.length, result.address);
- Module._free(buffer);
-}
+ const rootBuffer = _interned_string_current_root_buffer;
+ const index = _interned_string_current_root_buffer_count++;
-/**
- * @deprecated Not GC or thread safe
- */
-export function js_string_to_mono_string_interned(string: string | symbol): MonoString {
- const temp = mono_wasm_new_root<MonoString>();
- try {
- js_string_to_mono_string_interned_root(string, temp);
- return temp.value;
- } finally {
- temp.release();
+ // Store the managed string into the managed intern table. This can theoretically
+ // provide a different managed object than the one we passed in, so update our
+ // pointer (stored in the root) with the result.
+ if (internIt) {
+ cwraps.mono_wasm_intern_string_ref(root.address);
+ if (!root.value)
+ throw new Error("mono_wasm_intern_string_ref produced a null pointer");
}
-}
-/**
- * @deprecated Not GC or thread safe
- */
-export function js_string_to_mono_string(string: string): MonoString {
- assert_legacy_interop();
- const temp = mono_wasm_new_root<MonoString>();
- try {
- js_string_to_mono_string_root(string, temp);
- return temp.value;
- } finally {
- temp.release();
- }
+ interned_js_string_table.set(string, root.value);
+ interned_string_table.set(root.value, string);
+
+ if ((string.length === 0) && !_empty_string_ptr)
+ _empty_string_ptr = root.value;
+
+ // Copy the final pointer into our interned string root buffer to ensure the string
+ // remains rooted. TODO: Is this actually necessary?
+ rootBuffer.copy_value_from_address(index, root.address);
}
-/**
- * @deprecated Not GC or thread safe
- */
-export function js_string_to_mono_string_new(string: string): MonoString {
- assert_legacy_interop();
- const temp = mono_wasm_new_root<MonoString>();
- try {
- js_string_to_mono_string_new_root(string, temp);
- return temp.value;
- } finally {
- temp.release();
- }
+function js_string_to_mono_string_new_root(string: string, result: WasmRoot<MonoString>): void {
+ const bufferLen = (string.length + 1) * 2;
+ const buffer = Module._malloc(bufferLen);
+ stringToUTF16(buffer as any, buffer as any + bufferLen, string);
+ cwraps.mono_wasm_string_from_utf16_ref(<any>buffer, string.length, result.address);
+ Module._free(buffer);
}
+
+// When threading is enabled, TextDecoder does not accept a view of a
+// SharedArrayBuffer, we must make a copy of the array first.
+// See https://github.com/whatwg/encoding/issues/172
+// BEWARE: In some cases, `instanceof SharedArrayBuffer` returns false even though buffer is an SAB.
+// Patch adapted from https://github.com/emscripten-core/emscripten/pull/16994
+// See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
+export function viewOrCopy(view: Uint8Array, start: CharPtr, end: CharPtr): Uint8Array {
+ // this condition should be eliminated by rollup on non-threading builds
+ const needsCopy = isSharedArrayBuffer(view.buffer);
+ return needsCopy
+ ? view.slice(<any>start, <any>end)
+ : view.subarray(<any>start, <any>end);
+}
\ No newline at end of file
}
export declare interface EmscriptenModule {
+ /** @deprecated Please use growableHeapI8() instead.*/
HEAP8: Int8Array,
+ /** @deprecated Please use growableHeapI16() instead.*/
HEAP16: Int16Array;
+ /** @deprecated Please use growableHeapI32() instead. */
HEAP32: Int32Array;
+ /** @deprecated Please use growableHeapI64() instead. */
HEAP64: BigInt64Array;
+ /** @deprecated Please use growableHeapU8() instead. */
HEAPU8: Uint8Array;
+ /** @deprecated Please use growableHeapU16() instead. */
HEAPU16: Uint16Array;
+ /** @deprecated Please use growableHeapU32() instead */
HEAPU32: Uint32Array;
+ /** @deprecated Please use growableHeapF32() instead */
HEAPF32: Float32Array;
+ /** @deprecated Please use growableHeapF64() instead. */
HEAPF64: Float64Array;
// this should match emcc -s EXPORTED_FUNCTIONS
getValue(ptr: number, type: string, noSafe?: number | boolean): number;
UTF8ToString(ptr: CharPtr, maxBytesToRead?: number): string;
UTF8ArrayToString(u8Array: Uint8Array, idx?: number, maxBytesToRead?: number): string;
+ stringToUTF8Array(str: string, heap: Uint8Array, outIdx: number, maxBytesToWrite: number): void;
FS_createPath(parent: string, path: string, canRead?: boolean, canWrite?: boolean): string;
FS_createDataFile(parent: string, name: string, data: TypedArray, canRead: boolean, canWrite: boolean, canOwn?: boolean): string;
addFunction(fn: Function, signature: string): number;
getAssemblyExports(assemblyName: string): Promise<any>,
setModuleImports(moduleName: string, moduleImports: any): void,
getConfig: () => MonoConfig,
+
+ // memory management
setHeapB32: (offset: NativePointer, value: number | boolean) => void,
setHeapU8: (offset: NativePointer, value: number) => void,
setHeapU16: (offset: NativePointer, value: number) => void,
getHeapI64Big: (offset: NativePointer) => bigint,
getHeapF32: (offset: NativePointer) => number,
getHeapF64: (offset: NativePointer) => number,
+ localHeapViewI8: () => Int8Array,
+ localHeapViewI16: () => Int16Array,
+ localHeapViewI32: () => Int32Array,
+ localHeapViewI64Big: () => BigInt64Array,
+ localHeapViewU8: () => Uint8Array,
+ localHeapViewU16: () => Uint16Array,
+ localHeapViewU32: () => Uint32Array,
+ localHeapViewF32: () => Float32Array,
+ localHeapViewF64: () => Float64Array,
}
export type RuntimeAPI = {
import { prevent_timer_throttling } from "./scheduling";
import { Queue } from "./queue";
-import { Module, createPromiseController } from "./globals";
-import { setI32 } from "./memory";
+import { createPromiseController } from "./globals";
+import { setI32, localHeapViewU8 } from "./memory";
import { VoidPtr } from "./types/emscripten";
import { PromiseController } from "./types/internal";
import { mono_log_warn } from "./logging";
+import { viewOrCopy, utf8ToStringRelaxed, stringToUTF8 } from "./strings";
const wasm_ws_pending_send_buffer = Symbol.for("wasm ws_pending_send_buffer");
const wasm_ws_pending_send_buffer_offset = Symbol.for("wasm ws_pending_send_buffer_offset");
const wasm_ws_is_aborted = Symbol.for("wasm ws_is_aborted");
const wasm_ws_receive_status_ptr = Symbol.for("wasm ws_receive_status_ptr");
let mono_wasm_web_socket_close_warning = false;
-let _text_decoder_utf8: TextDecoder | undefined = undefined;
-let _text_encoder_utf8: TextEncoder | undefined = undefined;
const ws_send_buffer_blocking_threshold = 65536;
const emptyBuffer = new Uint8Array();
export function ws_wasm_send(ws: WebSocketExtension, buffer_ptr: VoidPtr, buffer_length: number, message_type: number, end_of_message: boolean): Promise<void> | null {
mono_assert(!!ws, "ERR17: expected ws instance");
- const buffer_view = new Uint8Array(Module.HEAPU8.buffer, <any>buffer_ptr, buffer_length);
+ const buffer_view = new Uint8Array(localHeapViewU8().buffer, <any>buffer_ptr, buffer_length);
const whole_buffer = _mono_wasm_web_socket_send_buffering(ws, buffer_view, message_type, end_of_message);
if (!end_of_message || !whole_buffer) {
const promise_queue = ws[wasm_ws_pending_receive_promise_queue];
if (typeof event.data === "string") {
- if (_text_encoder_utf8 === undefined) {
- _text_encoder_utf8 = new TextEncoder();
- }
event_queue.enqueue({
type: 0, // WebSocketMessageType.Text
// according to the spec https://encoding.spec.whatwg.org/
// - Unpaired surrogates will get replaced with 0xFFFD
// - utf8 encode specifically is defined to never throw
- data: _text_encoder_utf8.encode(event.data),
+ data: stringToUTF8(event.data),
offset: 0
});
}
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(Module.HEAPU8.buffer, <any>buffer_ptr, buffer_length);
+ const bufferView = new Uint8Array(localHeapViewU8().buffer, <any>buffer_ptr, buffer_length);
bufferView.set(sourceView, 0);
event.offset += count;
}
}
if (message_type === 0) {
// text, convert from UTF-8 bytes to string, because of bad browser API
- if (_text_decoder_utf8 === undefined) {
- // we do not validate outgoing data https://github.com/dotnet/runtime/issues/59214
- _text_decoder_utf8 = new TextDecoder("utf-8", { fatal: false });
- }
- // See https://github.com/whatwg/encoding/issues/172
- const bytes = typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer
- ? (<any>buffer).slice(0, offset)
- : buffer.subarray(0, offset);
- return _text_decoder_utf8.decode(bytes);
+ const bytes = viewOrCopy(buffer, 0 as any, offset as any);
+ // we do not validate outgoing data https://github.com/dotnet/runtime/issues/59214
+ return utf8ToStringRelaxed(bytes);
} else {
// binary, view to used part of the buffer
return buffer.subarray(0, offset);
<EmccExportedRuntimeMethod Include="getValue" />
<EmccExportedRuntimeMethod Include="UTF8ToString" />
<EmccExportedRuntimeMethod Include="UTF8ArrayToString" />
+ <EmccExportedRuntimeMethod Include="stringToUTF8Array" />
<EmccExportedRuntimeMethod Include="FS_createPath" />
<EmccExportedRuntimeMethod Include="FS_createDataFile" />
<EmccExportedRuntimeMethod Include="removeRunDependency" />
<ItemGroup Condition="'$(MonoWasmThreads)' == 'true'">
<WasmOptConfigurationFlags Include="--enable-threads;--enable-bulk-memory;--enable-sign-ext" />
+
+ <!-- workaround for https://github.com/emscripten-core/emscripten/issues/18034 -->
+ <_EmccLinkFlags Include="-s TEXTDECODER=0"/>
</ItemGroup>
<ItemGroup Condition="'$(OS)' != 'Windows_NT'">