Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[browser][mt] Update memory views after growth, refactor string processing, fix SharedArrayBuffer detection #86664

Merged
merged 17 commits into from
May 28, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -59,6 +61,7 @@ export function mono_wasm_add_dbg_command_received(res_ok: boolean, id: number,
}

function mono_wasm_malloc_and_set_debug_buffer(command_parameters: string) {
const heapU8 = localHeapViewU8();
if (command_parameters.length > _debugger_buffer_len) {
if (_debugger_buffer)
Module._free(_debugger_buffer);
Expand All @@ -67,7 +70,7 @@ function mono_wasm_malloc_and_set_debug_buffer(command_parameters: string) {
}
const byteCharacters = atob(command_parameters);
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, utf16ToString, 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 = utf16ToString(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 = utf16ToString(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