Skip to content

Commit

Permalink
[browser][mt] Update memory views after growth, refactor string proce…
Browse files Browse the repository at this point in the history
…ssing, fix SharedArrayBuffer detection (#86664)

Co-authored-by: pavelsavara <pavel.savara@gmail.com>
  • Loading branch information
IsaMorphic and pavelsavara committed May 28, 2023
1 parent d58754b commit 5b8437d
Show file tree
Hide file tree
Showing 41 changed files with 585 additions and 431 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -611,20 +611,6 @@ public static void OnceAJSStringIsInternedItIsAlwaysUsedIfPossible()
Assert.True(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
}

[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()
{
Expand Down
3 changes: 2 additions & 1 deletion src/mono/wasm/runtime/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { endMeasure, MeasuredBlock, startMeasure } from "./profiler";
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 {
Expand Down Expand Up @@ -157,7 +158,7 @@ export function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): b

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;
Expand Down
13 changes: 8 additions & 5 deletions src/mono/wasm/runtime/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { toBase64StringImpl } from "./base64";
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 = {};
Expand Down Expand Up @@ -39,12 +41,12 @@ export function mono_wasm_fire_debugger_agent_message_with_data_to_pause(base64S
}

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,
Expand All @@ -66,8 +68,9 @@ function mono_wasm_malloc_and_set_debug_buffer(command_parameters: string) {
_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);
}
}

Expand Down Expand Up @@ -150,7 +153,7 @@ export function mono_wasm_debugger_attached(): void {

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
Expand Down Expand Up @@ -341,7 +344,7 @@ export function mono_wasm_release_object(objectId: string): void {
}

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);
Expand Down
7 changes: 4 additions & 3 deletions src/mono/wasm/runtime/diagnostics/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// 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";
Expand All @@ -14,7 +15,7 @@ import { mono_log_warn } from "../logging";

// called from C on the main thread
export function mono_wasm_event_pipe_early_startup_callback(): void {
if (monoWasmThreads) {
if (MonoWasmThreads) {
return;
}
}
Expand All @@ -37,7 +38,7 @@ let diagnosticsInitialized = false;
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 {
Expand Down
5 changes: 3 additions & 2 deletions src/mono/wasm/runtime/diagnostics/server_pthread/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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";
Expand Down Expand Up @@ -47,6 +47,7 @@ import {
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) => {
Expand Down Expand Up @@ -283,7 +284,7 @@ function parseProtocolCommand(data: ArrayBuffer | BinaryProtocolCommand): ParseC

/// 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:")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

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,
Expand All @@ -21,7 +21,7 @@ class SocketGuts {
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);
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/mono/wasm/runtime/dotnet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,23 @@ declare interface Int32Ptr extends NativePointer {
__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;
Expand All @@ -39,6 +48,7 @@ declare interface EmscriptenModule {
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;
Expand Down Expand Up @@ -231,6 +241,15 @@ type APIType = {
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 = {
/**
Expand Down
11 changes: 10 additions & 1 deletion src/mono/wasm/runtime/export-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { MonoConfig, APIType } from "./types";

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";
Expand Down Expand Up @@ -44,6 +44,15 @@ export function export_api(): any {
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;
}
2 changes: 0 additions & 2 deletions src/mono/wasm/runtime/exports-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { mono_wasm_send_dbg_command_with_parms, mono_wasm_send_dbg_command, mono
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";
Expand All @@ -23,7 +22,6 @@ export function export_internal(): any {
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,
Expand Down
37 changes: 12 additions & 25 deletions src/mono/wasm/runtime/hybrid-globalization/change-case.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
// 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) {
Expand All @@ -31,20 +27,19 @@ export function mono_wasm_change_case_invariant(src: number, srcLength: number,
}
}

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) {
Expand All @@ -54,12 +49,4 @@ export function mono_wasm_change_case(culture: MonoStringRef, src: number, srcLe
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;
}
}
Loading

0 comments on commit 5b8437d

Please sign in to comment.