From 97d6acf3cb5e853c7a84180d7c7238afdf893382 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Fri, 19 Apr 2024 14:42:50 +0000 Subject: [PATCH 01/10] Calendar - done --- .../src/Interop/Browser/Interop.Calendar.cs | 2 +- .../Globalization/CalendarData.Browser.cs | 12 +++++---- src/mono/browser/runtime/corebindings.c | 2 +- .../runtime/hybrid-globalization/calendar.ts | 25 ++++++++----------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs index 2a7b1d02ad21ad..0824fffcb5ee54 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs @@ -9,6 +9,6 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetCalendarInfo(in string culture, CalendarId calendarId, char* buffer, int bufferLength, out int exceptionalResult, out object result); + internal static extern unsafe nint GetCalendarInfo(in string culture, CalendarId calendarId, char* buffer, int bufferMaxLength, out int bufferLength); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs index 87199ed3f1eedf..9e6638f7dc6e30 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs @@ -15,11 +15,13 @@ internal sealed partial class CalendarData private unsafe bool JSLoadCalendarDataFromBrowser(string localeName, CalendarId calendarId) { char* buffer = stackalloc char[CALENDAR_INFO_BUFFER_LEN]; - int exception; - object exResult; - int resultLength = Interop.JsGlobalization.GetCalendarInfo(localeName, calendarId, buffer, CALENDAR_INFO_BUFFER_LEN, out exception, out exResult); - if (exception != 0) - throw new Exception((string)exResult); + nint exceptionPtr = Interop.JsGlobalization.GetCalendarInfo(localeName, calendarId, buffer, CALENDAR_INFO_BUFFER_LEN, out int resultLength); + if (exceptionPtr != IntPtr.Zero) // JSFunctionBinding.cs + { + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); + } string result = new string(buffer, 0, resultLength); string[] subresults = result.Split("##"); if (subresults.Length < 14) diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index 485ba3189af6e2..0483d07d0eab09 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -64,7 +64,7 @@ extern int mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, extern mono_bool mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); extern mono_bool mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); extern int mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); +extern void* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); extern int mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); extern int mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); extern int mono_wasm_get_first_day_of_week (MonoString **culture, int *is_exception, MonoObject** ex_result); diff --git a/src/mono/browser/runtime/hybrid-globalization/calendar.ts b/src/mono/browser/runtime/hybrid-globalization/calendar.ts index d3944f514ce854..7d7eb94f10a402 100644 --- a/src/mono/browser/runtime/hybrid-globalization/calendar.ts +++ b/src/mono/browser/runtime/hybrid-globalization/calendar.ts @@ -3,20 +3,19 @@ /* eslint-disable no-inner-declarations */ import { mono_wasm_new_external_root } from "../roots"; -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 "./helpers"; +import { monoStringToString, stringToUTF16, stringToUTF16Ptr } from "../strings"; +import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { INNER_SEPARATOR, OUTER_SEPARATOR, normalizeSpaces } from "./helpers"; +import { setI32 } from "../memory"; const MONTH_CODE = "MMMM"; const YEAR_CODE = "yyyy"; const DAY_CODE = "d"; // this function joins all calendar info with OUTER_SEPARATOR into one string and returns it back to managed code -export function mono_wasm_get_calendar_info (culture: MonoStringRef, calendarId: number, dst: number, dstLength: number, isException: Int32Ptr, exAddress: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); +export function mono_wasm_get_calendar_info (culture: MonoStringRef, calendarId: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); const locale = cultureName ? cultureName : undefined; @@ -56,18 +55,16 @@ export function mono_wasm_get_calendar_info (culture: MonoStringRef, calendarId: calendarInfo.AbbreviatedEraNames = eraNames.abbreviatedEraNames; const result = Object.values(calendarInfo).join(OUTER_SEPARATOR); - if (result.length > dstLength) { - throw new Error(`Calendar info exceeds length of ${dstLength}.`); + if (result.length > dstMaxLength) { + throw new Error(`Calendar info exceeds length of ${dstMaxLength}.`); } stringToUTF16(dst, dst + 2 * result.length, result); - wrap_no_error_root(isException, exceptionRoot); - return result.length; + setI32(dstLength, result.length); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } From 4c4ecc9679be7309763a9feb92d49f875f4bb494 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Fri, 19 Apr 2024 15:02:34 +0000 Subject: [PATCH 02/10] Culture info - done. --- .../src/Interop/Browser/Interop.Locale.cs | 2 +- .../Globalization/CultureData.Browser.cs | 15 +++++++---- src/mono/browser/runtime/corebindings.c | 2 +- .../hybrid-globalization/culture-info.ts | 26 +++++++++---------- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs index b831e72e70cdbc..143198a3e3c50c 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs @@ -8,7 +8,7 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetCultureInfo(in string culture, char* buffer, int bufferLength, out int exceptionalResult, out object result); + internal static extern unsafe nint GetCultureInfo(in string culture, char* buffer, int bufferMaxLength, out int resultLength); [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern unsafe int GetFirstDayOfWeek(in string culture, out int exceptionalResult, out object result); [MethodImplAttribute(MethodImplOptions.InternalCall)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs index 8a8edadaf326d0..3ddeba42e685ef 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -65,9 +66,13 @@ private string JSGetNativeDisplayName(string localeName, string cultureName) private static unsafe CultureData JSLoadCultureInfoFromBrowser(string localeName, CultureData culture) { char* buffer = stackalloc char[CULTURE_INFO_BUFFER_LEN]; - int resultLength = Interop.JsGlobalization.GetCultureInfo(localeName, buffer, CULTURE_INFO_BUFFER_LEN, out int exception, out object exResult); - if (exception != 0) - throw new Exception((string)exResult); + nint exceptionPtr = Interop.JsGlobalization.GetCultureInfo(localeName, buffer, CULTURE_INFO_BUFFER_LEN, out int resultLength); + if (exceptionPtr != IntPtr.Zero) + { + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); + } string result = new string(buffer, 0, resultLength); string[] subresults = result.Split("##"); if (subresults.Length < 4) @@ -93,11 +98,11 @@ private static unsafe int GetFirstDayOfWeek(string localeName) private static unsafe int GetFirstWeekOfYear(string localeName) { - int result = Interop.JsGlobalization.GetFirstWeekOfYear(localeName, out int exception, out object ex_result); + int result = Interop.JsGlobalization.GetFirstWeekOfYear(localeName, out int exception, out object ex_result); if (exception != 0) { // Failed, just use 0 - Debug.Fail($"[CultureData.GetFirstDayOfWeek()] failed with {ex_result}"); + Debug.Fail($"[CultureData.GetFirstWeekOfYear()] failed with {ex_result}"); return 0; } return result; diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index 0483d07d0eab09..e4f352a089643b 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -66,7 +66,7 @@ extern mono_bool mono_wasm_ends_with (MonoString **culture, const uint16_t* str1 extern int mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *is_exception, MonoObject** ex_result); extern void* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); extern int mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); +extern int mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); extern int mono_wasm_get_first_day_of_week (MonoString **culture, int *is_exception, MonoObject** ex_result); extern int mono_wasm_get_first_week_of_year (MonoString **culture, int *is_exception, MonoObject** ex_result); diff --git a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts index 03bebd9ec65ee2..5d37e9e9fac2b0 100644 --- a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts +++ b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts @@ -1,16 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { wrap_error_root, wrap_no_error_root } from "./helpers"; +import { setI32 } from "../memory"; import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16 } from "../strings"; -import { Int32Ptr } from "../types/emscripten"; -import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal"; +import { monoStringToString, stringToUTF16, stringToUTF16Ptr } from "../strings"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; +import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; import { OUTER_SEPARATOR, normalizeLocale, normalizeSpaces } from "./helpers"; -export function mono_wasm_get_culture_info (culture: MonoStringRef, dst: number, dstLength: number, isException: Int32Ptr, exAddress: MonoObjectRef): number { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); +export function mono_wasm_get_culture_info (culture: MonoStringRef, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); const cultureInfo = { @@ -26,18 +25,17 @@ export function mono_wasm_get_culture_info (culture: MonoStringRef, dst: number, cultureInfo.LongTimePattern = getLongTimePattern(canonicalLocale, designators); cultureInfo.ShortTimePattern = getShortTimePattern(cultureInfo.LongTimePattern); const result = Object.values(cultureInfo).join(OUTER_SEPARATOR); - if (result.length > dstLength) { - throw new Error(`Culture info exceeds length of ${dstLength}.`); + if (result.length > dstMaxLength) { + throw new Error(`Culture info exceeds length of ${dstMaxLength}.`); } stringToUTF16(dst, dst + 2 * result.length, result); - wrap_no_error_root(isException, exceptionRoot); - return result.length; + setI32(dstLength, result.length); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; + setI32(dstLength, -1); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } From c219d11db12e3cbbebfce7691358ba222eda1a30 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Mon, 22 Apr 2024 10:00:13 +0000 Subject: [PATCH 03/10] Missing change to the previous commit. --- src/mono/browser/runtime/corebindings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index e4f352a089643b..ca0bbb69e9c939 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -66,7 +66,7 @@ extern mono_bool mono_wasm_ends_with (MonoString **culture, const uint16_t* str1 extern int mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *is_exception, MonoObject** ex_result); extern void* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); extern int mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern void* mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); extern int mono_wasm_get_first_day_of_week (MonoString **culture, int *is_exception, MonoObject** ex_result); extern int mono_wasm_get_first_week_of_year (MonoString **culture, int *is_exception, MonoObject** ex_result); From 9a4b902f3d24895deb2209b594e0c7a1195bba17 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:28:01 +0000 Subject: [PATCH 04/10] Change case - done. --- .../src/Interop/Browser/Interop.TextInfo.cs | 4 +-- .../Globalization/TextInfo.WebAssembly.cs | 18 +++++------ src/mono/browser/runtime/corebindings.c | 4 +-- .../hybrid-globalization/change-case.ts | 32 +++++++------------ 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs index ff157eb45f26cf..cae8e0585ec88f 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs @@ -8,8 +8,8 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe void ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper, out int exceptionalResult, out object result); + internal static extern unsafe int ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe void ChangeCase(in string culture, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper, out int exceptionalResult, out object result); + internal static extern unsafe int ChangeCase(in string culture, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs index a2dd2a02c05f18..38ff5dc34b63c0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -13,18 +14,15 @@ internal unsafe void JsChangeCase(char* src, int srcLen, char* dstBuffer, int ds Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(GlobalizationMode.Hybrid); - int exception; - object ex_result; - if (HasEmptyCultureName) + int exceptionPtr = HasEmptyCultureName ? + Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper) : + Interop.JsGlobalization.ChangeCase(_cultureName, src, srcLen, dstBuffer, dstBufferCapacity, toUpper); + if (exceptionPtr != IntPtr.Zero) { - Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper, out exception, out ex_result); + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); } - else - { - Interop.JsGlobalization.ChangeCase(_cultureName, src, srcLen, dstBuffer, dstBufferCapacity, toUpper, out exception, out ex_result); - } - if (exception != 0) - throw new Exception((string)ex_result); } } } diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index ca0bbb69e9c939..b88716838d9971 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -58,8 +58,8 @@ extern void mono_wasm_invoke_jsimport_ST (int function_handle, void *args); #endif /* DISABLE_THREADS */ // HybridGlobalization -extern void mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper, int *is_exception, MonoObject** ex_result); -extern void mono_wasm_change_case (MonoString **culture, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper, int *is_exception, MonoObject** ex_result); +extern void* mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); +extern void* mono_wasm_change_case (MonoString **culture, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); extern int mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); extern mono_bool mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); extern mono_bool mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); diff --git a/src/mono/browser/runtime/hybrid-globalization/change-case.ts b/src/mono/browser/runtime/hybrid-globalization/change-case.ts index 762eacc94c26bc..625a86e6a9269e 100644 --- a/src/mono/browser/runtime/hybrid-globalization/change-case.ts +++ b/src/mono/browser/runtime/hybrid-globalization/change-case.ts @@ -2,15 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. import { mono_wasm_new_external_root } from "../roots"; -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 "./helpers"; +import { monoStringToString, utf16ToStringLoop, stringToUTF16, stringToUTF16Ptr } from "../strings"; +import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { VoidPtr } from "../types/emscripten"; import { localHeapViewU16, setU16_local } from "../memory"; import { isSurrogate } from "./helpers"; -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(ex_address); +export function mono_wasm_change_case_invariant (src: number, srcLength: number, dst: number, dstLength: number, toUpper: number): VoidPtr { try { const input = utf16ToStringLoop(src, src + 2 * srcLength); const result = toUpper ? input.toUpperCase() : input.toLowerCase(); @@ -18,8 +16,7 @@ export function mono_wasm_change_case_invariant (src: number, srcLength: number, // originally we do not support this expansion if (result.length <= dstLength) { stringToUTF16(dst, dst + 2 * dstLength, result); - wrap_no_error_root(is_exception, exceptionRoot); - return; + return VoidPtrNull; } // workaround to maintain the ICU-like behavior @@ -59,17 +56,14 @@ export function mono_wasm_change_case_invariant (src: number, srcLength: number, } } } - wrap_no_error_root(is_exception, exceptionRoot); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - } finally { - exceptionRoot.release(); + return stringToUTF16Ptr((ex)); } } -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(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_change_case (culture: MonoStringRef, src: number, srcLength: number, dst: number, dstLength: number, toUpper: number): VoidPtr { + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); if (!cultureName) @@ -79,8 +73,7 @@ export function mono_wasm_change_case (culture: MonoStringRef, src: number, srcL if (result.length <= input.length) { stringToUTF16(dst, dst + 2 * dstLength, result); - wrap_no_error_root(is_exception, exceptionRoot); - return; + return VoidPtrNull; } // workaround to maintain the ICU-like behavior const heapI16 = localHeapViewU16(); @@ -119,12 +112,11 @@ export function mono_wasm_change_case (culture: MonoStringRef, src: number, srcL } } } - wrap_no_error_root(is_exception, exceptionRoot); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } From de89617ea60a8e9558990dfac433f942d1a7f5f2 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:39:54 +0000 Subject: [PATCH 05/10] issing change to previous commit --- src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs | 4 ++-- .../src/System/Globalization/TextInfo.WebAssembly.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs index cae8e0585ec88f..456837df57b44e 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs @@ -8,8 +8,8 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); + internal static extern unsafe nint ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int ChangeCase(in string culture, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); + internal static extern unsafe nint ChangeCase(in string culture, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs index 38ff5dc34b63c0..c01593f537b93a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs @@ -14,7 +14,7 @@ internal unsafe void JsChangeCase(char* src, int srcLen, char* dstBuffer, int ds Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(GlobalizationMode.Hybrid); - int exceptionPtr = HasEmptyCultureName ? + nint exceptionPtr = HasEmptyCultureName ? Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper) : Interop.JsGlobalization.ChangeCase(_cultureName, src, srcLen, dstBuffer, dstBufferCapacity, toUpper); if (exceptionPtr != IntPtr.Zero) From c551b41d1a23d16c649aae95b67f7169b3fc7b7b Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:56:22 +0000 Subject: [PATCH 06/10] Collation - done. --- .../Interop/Browser/Interop.CompareInfo.cs | 8 +- .../System/Globalization/CompareInfo.Icu.cs | 20 +++- .../Globalization/CompareInfo.WebAssembly.cs | 62 ++++++----- src/mono/browser/runtime/corebindings.c | 8 +- .../hybrid-globalization/collations.ts | 103 +++++++++--------- 5 files changed, 108 insertions(+), 93 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs b/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs index cb7edf5b380a26..6536cee676304b 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs @@ -8,15 +8,15 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int CompareString(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int exceptionalResult, out object result); + internal static extern unsafe nint CompareString(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe bool StartsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int exceptionalResult, out object result); + internal static extern unsafe nint StartsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe bool EndsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int exceptionalResult, out object result); + internal static extern unsafe nint EndsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int IndexOf(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, bool fromBeginning, out int exceptionalResult, out object result); + internal static extern unsafe nint IndexOf(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, bool fromBeginning, out int resultPtr); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs index 75440b2a23c458..72887c1892759c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs @@ -198,9 +198,13 @@ private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan source, Rea #if TARGET_BROWSER if (GlobalizationMode.Hybrid) { - int result = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int result); + if (exceptionPtr != IntPtr.Zero) + { + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); + } return result; } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS @@ -300,9 +304,13 @@ private unsafe int IndexOfOrdinalHelper(ReadOnlySpan source, ReadOnlySpan< #if TARGET_BROWSER if (GlobalizationMode.Hybrid) { - int result = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int result); + if (exceptionPtr != IntPtr.Zero) + { + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); + } return result; } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs index 1d265dc70450a8..623a25f9936a64 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs @@ -50,16 +50,18 @@ private unsafe int JsCompareString(ReadOnlySpan string1, ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) @@ -69,17 +71,18 @@ private unsafe bool JsStartsWith(ReadOnlySpan source, ReadOnlySpan p string cultureName = m_name; AssertIndexingSupported(options, cultureName); - bool result; fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) { - result = Interop.JsGlobalization.StartsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + nint exceptionPtr = Interop.JsGlobalization.StartsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); + if (exceptionPtr != IntPtr.Zero) + { + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); + } + return result; } - - - return result; } private unsafe bool JsEndsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) @@ -89,16 +92,18 @@ private unsafe bool JsEndsWith(ReadOnlySpan source, ReadOnlySpan pre string cultureName = m_name; AssertIndexingSupported(options, cultureName); - bool result; fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) { - result = Interop.JsGlobalization.EndsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + nint exceptionPtr = Interop.JsGlobalization.EndsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); + if (exceptionPtr != IntPtr.Zero) + { + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); + } + return result; } - - return result; } private unsafe int JsIndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) @@ -108,25 +113,24 @@ private unsafe int JsIndexOfCore(ReadOnlySpan source, ReadOnlySpan t string cultureName = m_name; AssertIndexingSupported(options, cultureName); - int idx; if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) { - idx = (options & CompareOptions.IgnoreCase) != 0 ? + return (options & CompareOptions.IgnoreCase) != 0 ? IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr, fromBeginning) : IndexOfOrdinalHelper(source, target, options, matchLengthPtr, fromBeginning); } - else + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pTarget = &MemoryMarshal.GetReference(target)) { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pTarget = &MemoryMarshal.GetReference(target)) + nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, pTarget, target.Length, pSource, source.Length, options, fromBeginning, out int idx); + if (exceptionPtr != IntPtr.Zero) { - idx = Interop.JsGlobalization.IndexOf(m_name, pTarget, target.Length, pSource, source.Length, options, fromBeginning, out int exception, out object ex_result); - if (exception != 0) - throw new Exception((string)ex_result); + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); } + return idx; } - - return idx; } // there are chars that are ignored by ICU hashing algorithm but not ignored by invariant hashing diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index b88716838d9971..bc54219855dcc6 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -60,10 +60,10 @@ extern void mono_wasm_invoke_jsimport_ST (int function_handle, void *args); // HybridGlobalization extern void* mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); extern void* mono_wasm_change_case (MonoString **culture, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); -extern int mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); -extern mono_bool mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); -extern mono_bool mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *is_exception, MonoObject** ex_result); +extern void* mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *resultPtr); +extern void* mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern void* mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern void* mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *resultPtr); extern void* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); extern int mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); extern void* mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); diff --git a/src/mono/browser/runtime/hybrid-globalization/collations.ts b/src/mono/browser/runtime/hybrid-globalization/collations.ts index 523f63307e278c..0cb44b692af054 100644 --- a/src/mono/browser/runtime/hybrid-globalization/collations.ts +++ b/src/mono/browser/runtime/hybrid-globalization/collations.ts @@ -2,110 +2,114 @@ // The .NET Foundation licenses this file to you under the MIT license. import { mono_wasm_new_external_root } from "../roots"; -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 "./helpers"; +import { monoStringToString, stringToUTF16Ptr, utf16ToString } from "../strings"; +import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { GraphemeSegmenter } from "./grapheme-segmenter"; +import { setI32 } from "../memory"; const COMPARISON_ERROR = -2; const INDEXING_ERROR = -1; let graphemeSegmenterCached: GraphemeSegmenter | null; -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(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_compare_string (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); const string1 = utf16ToString(str1, (str1 + 2 * str1Length)); const string2 = utf16ToString(str2, (str2 + 2 * str2Length)); const casePicker = (options & 0x1f); const locale = cultureName ? cultureName : undefined; - wrap_no_error_root(is_exception, exceptionRoot); - return compareStrings(string1, string2, locale, casePicker); + const result = compareStrings(string1, string2, locale, casePicker); + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return COMPARISON_ERROR; + setI32(resultPtr, COMPARISON_ERROR); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } -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(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_starts_with (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); const prefix = decodeToCleanString(str2, str2Length); // no need to look for an empty string - if (prefix.length == 0) - return 1; // true + if (prefix.length == 0) { + setI32(resultPtr, 1); // true + return VoidPtrNull; + } const source = decodeToCleanString(str1, str1Length); - if (source.length < prefix.length) - return 0; //false + if (source.length < prefix.length) { + setI32(resultPtr, 0); // false + return VoidPtrNull; + } const sourceOfPrefixLength = source.slice(0, prefix.length); const casePicker = (options & 0x1f); const locale = cultureName ? cultureName : undefined; - const result = compareStrings(sourceOfPrefixLength, prefix, locale, casePicker); - wrap_no_error_root(is_exception, exceptionRoot); - return result === 0 ? 1 : 0; // equals ? true : false + const cmpResult = compareStrings(sourceOfPrefixLength, prefix, locale, casePicker); + const result = cmpResult === 0 ? 1 : 0; // equals ? true : false + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return INDEXING_ERROR; + setI32(resultPtr, INDEXING_ERROR); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } -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(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_ends_with (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); const suffix = decodeToCleanString(str2, str2Length); - if (suffix.length == 0) - return 1; // true + if (suffix.length == 0) { + setI32(resultPtr, 1); // true + return VoidPtrNull; + } const source = decodeToCleanString(str1, str1Length); const diff = source.length - suffix.length; - if (diff < 0) - return 0; //false + if (diff < 0) { + setI32(resultPtr, 0); // false + return VoidPtrNull; + } const sourceOfSuffixLength = source.slice(diff, source.length); const casePicker = (options & 0x1f); const locale = cultureName ? cultureName : undefined; - const result = compareStrings(sourceOfSuffixLength, suffix, locale, casePicker); - wrap_no_error_root(is_exception, exceptionRoot); - return result === 0 ? 1 : 0; // equals ? true : false + const cmpResult = compareStrings(sourceOfSuffixLength, suffix, locale, casePicker); + const result = cmpResult === 0 ? 1 : 0; // equals ? true : false + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return INDEXING_ERROR; + setI32(resultPtr, INDEXING_ERROR); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } -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(culture), - exceptionRoot = mono_wasm_new_external_root(ex_address); +export function mono_wasm_index_of (culture: MonoStringRef, needlePtr: number, needleLength: number, srcPtr: number, srcLength: number, options: number, fromBeginning: number, resultPtr: Int32Ptr): VoidPtr { + const cultureRoot = mono_wasm_new_external_root(culture); try { const needle = utf16ToString(needlePtr, (needlePtr + 2 * needleLength)); // no need to look for an empty string if (cleanString(needle).length == 0) { - wrap_no_error_root(is_exception, exceptionRoot); - return fromBeginning ? 0 : srcLength; + setI32(resultPtr, fromBeginning ? 0 : srcLength); + return VoidPtrNull; } const source = utf16ToString(srcPtr, (srcPtr + 2 * srcLength)); // no need to look in an empty string if (cleanString(source).length == 0) { - wrap_no_error_root(is_exception, exceptionRoot); - return fromBeginning ? 0 : srcLength; + setI32(resultPtr, fromBeginning ? 0 : srcLength); + return VoidPtrNull; } const cultureName = monoStringToString(cultureRoot); const locale = cultureName ? cultureName : undefined; @@ -148,14 +152,13 @@ export function mono_wasm_index_of (culture: MonoStringRef, needlePtr: number, n break; } } - wrap_no_error_root(is_exception, exceptionRoot); - return result; + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(is_exception, ex, exceptionRoot); - return INDEXING_ERROR; + setI32(resultPtr, INDEXING_ERROR); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } function checkMatchFound (str1: string, str2: string, locale: string | undefined, casePicker: number): boolean { From 9a989317fec74037b961c706e77e9576c9892e4a Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:08:48 +0000 Subject: [PATCH 07/10] Locales - done. --- .../src/Interop/Browser/Interop.Locale.cs | 6 +- .../Globalization/CultureData.Browser.cs | 26 +++++--- src/mono/browser/runtime/corebindings.c | 6 +- .../runtime/hybrid-globalization/helpers.ts | 32 ---------- .../runtime/hybrid-globalization/locales.ts | 64 +++++++++---------- 5 files changed, 53 insertions(+), 81 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs index 143198a3e3c50c..d53372b8e98bfc 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs @@ -10,10 +10,10 @@ internal static unsafe partial class JsGlobalization [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern unsafe nint GetCultureInfo(in string culture, char* buffer, int bufferMaxLength, out int resultLength); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetFirstDayOfWeek(in string culture, out int exceptionalResult, out object result); + internal static extern unsafe nint GetFirstDayOfWeek(in string culture, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetFirstWeekOfYear(in string culture, out int exceptionalResult, out object result); + internal static extern unsafe nint GetFirstWeekOfYear(in string culture, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe int GetLocaleInfo(in string locale, in string culture, char* buffer, int bufferLength, out int exceptionalResult, out object result); + internal static extern unsafe nint GetLocaleInfo(in string locale, in string culture, char* buffer, int bufferLength, out int resultLength); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs index 3ddeba42e685ef..a638ef9b8d90c1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs @@ -43,9 +43,13 @@ private void JSInitLocaleInfo() private unsafe (string, string) JSGetLocaleInfo(string cultureName, string localeName) { char* buffer = stackalloc char[LOCALE_INFO_BUFFER_LEN]; - int resultLength = Interop.JsGlobalization.GetLocaleInfo(cultureName, localeName, buffer, LOCALE_INFO_BUFFER_LEN, out int exception, out object exResult); - if (exception != 0) - throw new Exception((string)exResult); + nint exceptionPtr = Interop.JsGlobalization.GetLocaleInfo(cultureName, localeName, buffer, LOCALE_INFO_BUFFER_LEN, out int resultLength); + if (exceptionPtr != IntPtr.Zero) + { + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + throw new Exception(message); + } string result = new string(buffer, 0, resultLength); string[] subresults = result.Split("##"); if (subresults.Length == 0) @@ -86,11 +90,13 @@ private static unsafe CultureData JSLoadCultureInfoFromBrowser(string localeName private static unsafe int GetFirstDayOfWeek(string localeName) { - int result = Interop.JsGlobalization.GetFirstDayOfWeek(localeName, out int exception, out object ex_result); - if (exception != 0) + nint exceptionPtr = Interop.JsGlobalization.GetFirstDayOfWeek(localeName, out int result); + if (exceptionPtr != IntPtr.Zero) { // Failed, just use 0 - Debug.Fail($"[CultureData.GetFirstDayOfWeek()] failed with {ex_result}"); + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + Debug.Fail($"[CultureData.GetFirstDayOfWeek()] failed with {message}"); return 0; } return result; @@ -98,11 +104,13 @@ private static unsafe int GetFirstDayOfWeek(string localeName) private static unsafe int GetFirstWeekOfYear(string localeName) { - int result = Interop.JsGlobalization.GetFirstWeekOfYear(localeName, out int exception, out object ex_result); - if (exception != 0) + nint exceptionPtr = Interop.JsGlobalization.GetFirstWeekOfYear(localeName, out int result); + if (exceptionPtr != IntPtr.Zero) { // Failed, just use 0 - Debug.Fail($"[CultureData.GetFirstWeekOfYear()] failed with {ex_result}"); + string message = Marshal.PtrToStringUni(exceptionPtr)!; + Marshal.FreeHGlobal(exceptionPtr); + Debug.Fail($"[CultureData.GetFirstWeekOfYear()] failed with {message}"); return 0; } return result; diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index bc54219855dcc6..9c6403ee18981b 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -65,10 +65,10 @@ extern void* mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, extern void* mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); extern void* mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *resultPtr); extern void* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern int mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultLength, int *is_exception, MonoObject** ex_result); +extern void* mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); extern void* mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern int mono_wasm_get_first_day_of_week (MonoString **culture, int *is_exception, MonoObject** ex_result); -extern int mono_wasm_get_first_week_of_year (MonoString **culture, int *is_exception, MonoObject** ex_result); +extern void* mono_wasm_get_first_day_of_week (MonoString **culture, int *resultPtr); +extern void* mono_wasm_get_first_week_of_year (MonoString **culture, int *resultPtr); void bindings_initialize_internals (void) { diff --git a/src/mono/browser/runtime/hybrid-globalization/helpers.ts b/src/mono/browser/runtime/hybrid-globalization/helpers.ts index 74134c4ca3cc1d..0cd2294447226f 100644 --- a/src/mono/browser/runtime/hybrid-globalization/helpers.ts +++ b/src/mono/browser/runtime/hybrid-globalization/helpers.ts @@ -1,12 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { normalize_exception } from "../invoke-js"; -import { receiveWorkerHeapViews, setI32_unchecked } from "../memory"; -import { stringToMonoStringRoot } from "../strings"; -import { Int32Ptr } from "../types/emscripten"; -import { MonoObject, WasmRoot } from "../types/internal"; - const SURROGATE_HIGHER_START = "\uD800"; const SURROGATE_HIGHER_END = "\uDBFF"; const SURROGATE_LOWER_START = "\uDC00"; @@ -48,29 +42,3 @@ export function isSurrogate (str: string, startIdx: number): boolean { SURROGATE_LOWER_START <= str[startIdx + 1] && str[startIdx + 1] <= SURROGATE_LOWER_END; } - -function _wrap_error_flag (is_exception: Int32Ptr | null, ex: any): string { - const res = normalize_exception(ex); - if (is_exception) { - receiveWorkerHeapViews(); - setI32_unchecked(is_exception, 1); - } - return res; -} - -export function wrap_error_root (is_exception: Int32Ptr | null, ex: any, result: WasmRoot): void { - const res = _wrap_error_flag(is_exception, ex); - stringToMonoStringRoot(res, result); -} - -// TODO replace it with replace it with UTF16 char*, no GC root needed -// https://github.com/dotnet/runtime/issues/98365 -export function wrap_no_error_root (is_exception: Int32Ptr | null, result?: WasmRoot): void { - if (is_exception) { - receiveWorkerHeapViews(); - setI32_unchecked(is_exception, 0); - } - if (result) { - result.clear(); - } -} diff --git a/src/mono/browser/runtime/hybrid-globalization/locales.ts b/src/mono/browser/runtime/hybrid-globalization/locales.ts index 252dfe1badf9e2..88c3d890001126 100644 --- a/src/mono/browser/runtime/hybrid-globalization/locales.ts +++ b/src/mono/browser/runtime/hybrid-globalization/locales.ts @@ -1,25 +1,24 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { wrap_error_root, wrap_no_error_root } from "./helpers"; +import { setI32 } from "../memory"; import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16 } from "../strings"; -import { Int32Ptr } from "../types/emscripten"; -import { MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "../types/internal"; +import { monoStringToString, stringToUTF16, stringToUTF16Ptr } from "../strings"; +import { Int32Ptr, VoidPtr } from "../types/emscripten"; +import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; import { OUTER_SEPARATOR, normalizeLocale } from "./helpers"; -export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoStringRef, dst: number, dstLength: number, isException: Int32Ptr, exAddress: MonoObjectRef): number { +export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoStringRef, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { const localeRoot = mono_wasm_new_external_root(locale), - cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); + cultureRoot = mono_wasm_new_external_root(culture); try { const localeNameOriginal = monoStringToString(localeRoot); const localeName = normalizeLocale(localeNameOriginal); if (!localeName && localeNameOriginal) { // handle non-standard or malformed locales by forwarding the locale code stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal); - wrap_no_error_root(isException, exceptionRoot); - return localeNameOriginal.length; + setI32(dstLength, localeNameOriginal.length); + return VoidPtrNull; } const cultureNameOriginal = monoStringToString(cultureRoot); const cultureName = normalizeLocale(cultureNameOriginal); @@ -49,8 +48,8 @@ export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoS if (error instanceof RangeError && error.message === "invalid_argument" && localeNameOriginal) { // handle non-standard or malformed locales by forwarding the locale code, e.g. "xx-u-xx" stringToUTF16(dst, dst + 2 * localeNameOriginal.length, localeNameOriginal); - wrap_no_error_root(isException, exceptionRoot); - return localeNameOriginal.length; + setI32(dstLength, localeNameOriginal.length); + return VoidPtrNull; } throw error; } @@ -67,54 +66,51 @@ export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoS if (!result) throw new Error(`Locale info for locale=${localeName} is null or empty.`); - if (result.length > dstLength) - throw new Error(`Locale info for locale=${localeName} exceeds length of ${dstLength}.`); + if (result.length > dstMaxLength) + throw new Error(`Locale info for locale=${localeName} exceeds length of ${dstMaxLength}.`); stringToUTF16(dst, dst + 2 * result.length, result); - wrap_no_error_root(isException, exceptionRoot); - return result.length; + setI32(dstLength, result.length); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; + setI32(dstLength, -1); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } -export function mono_wasm_get_first_day_of_week (culture: MonoStringRef, isException: Int32Ptr, exAddress: MonoObjectRef): number { +export function mono_wasm_get_first_day_of_week (culture: MonoStringRef, resultPtr: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); const canonicalLocale = normalizeLocale(cultureName); - wrap_no_error_root(isException, exceptionRoot); - return getFirstDayOfWeek(canonicalLocale); + const result = getFirstDayOfWeek(canonicalLocale); + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; + setI32(resultPtr, -1); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } -export function mono_wasm_get_first_week_of_year (culture: MonoStringRef, isException: Int32Ptr, exAddress: MonoObjectRef): number { +export function mono_wasm_get_first_week_of_year (culture: MonoStringRef, resultPtr: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture), - exceptionRoot = mono_wasm_new_external_root(exAddress); + const cultureRoot = mono_wasm_new_external_root(culture); try { const cultureName = monoStringToString(cultureRoot); const canonicalLocale = normalizeLocale(cultureName); - wrap_no_error_root(isException, exceptionRoot); - return getFirstWeekOfYear(canonicalLocale); + const result = getFirstWeekOfYear(canonicalLocale); + setI32(resultPtr, result); + return VoidPtrNull; } catch (ex: any) { - wrap_error_root(isException, ex, exceptionRoot); - return -1; + setI32(resultPtr, -1); + return stringToUTF16Ptr((ex)); } finally { cultureRoot.release(); - exceptionRoot.release(); } } From bda09061e55ba3d3cc2e6f2387b18248e96c7c3d Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:48:19 +0000 Subject: [PATCH 08/10] Feedback --- .../Globalization/CalendarData.Browser.cs | 7 +-- .../System/Globalization/CompareInfo.Icu.cs | 14 +---- .../Globalization/CompareInfo.WebAssembly.cs | 28 ++-------- .../Globalization/CultureData.Browser.cs | 52 ++++++++++++------- .../Globalization/TextInfo.WebAssembly.cs | 7 +-- src/mono/browser/runtime/corebindings.c | 23 ++++---- 6 files changed, 53 insertions(+), 78 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs index 9e6638f7dc6e30..646611c04b0fa5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs @@ -16,12 +16,7 @@ private unsafe bool JSLoadCalendarDataFromBrowser(string localeName, CalendarId { char* buffer = stackalloc char[CALENDAR_INFO_BUFFER_LEN]; nint exceptionPtr = Interop.JsGlobalization.GetCalendarInfo(localeName, calendarId, buffer, CALENDAR_INFO_BUFFER_LEN, out int resultLength); - if (exceptionPtr != IntPtr.Zero) // JSFunctionBinding.cs - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); string result = new string(buffer, 0, resultLength); string[] subresults = result.Split("##"); if (subresults.Length < 14) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs index 72887c1892759c..a7029ba0989252 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs @@ -199,12 +199,7 @@ private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan source, Rea if (GlobalizationMode.Hybrid) { nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int result); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); return result; } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS @@ -305,12 +300,7 @@ private unsafe int IndexOfOrdinalHelper(ReadOnlySpan source, ReadOnlySpan< if (GlobalizationMode.Hybrid) { nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int result); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); return result; } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs index 623a25f9936a64..c5483721db3897 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs @@ -54,12 +54,7 @@ private unsafe int JsCompareString(ReadOnlySpan string1, ReadOnlySpan source, ReadOnlySpan p fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) { nint exceptionPtr = Interop.JsGlobalization.StartsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); return result; } } @@ -96,12 +86,7 @@ private unsafe bool JsEndsWith(ReadOnlySpan source, ReadOnlySpan pre fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) { nint exceptionPtr = Interop.JsGlobalization.EndsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); return result; } } @@ -123,12 +108,7 @@ private unsafe int JsIndexOfCore(ReadOnlySpan source, ReadOnlySpan t fixed (char* pTarget = &MemoryMarshal.GetReference(target)) { nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, pTarget, target.Length, pSource, source.Length, options, fromBeginning, out int idx); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); return idx; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs index a638ef9b8d90c1..feb3173e15adc5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs @@ -44,12 +44,7 @@ private unsafe (string, string) JSGetLocaleInfo(string cultureName, string local { char* buffer = stackalloc char[LOCALE_INFO_BUFFER_LEN]; nint exceptionPtr = Interop.JsGlobalization.GetLocaleInfo(cultureName, localeName, buffer, LOCALE_INFO_BUFFER_LEN, out int resultLength); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); string result = new string(buffer, 0, resultLength); string[] subresults = result.Split("##"); if (subresults.Length == 0) @@ -71,12 +66,7 @@ private static unsafe CultureData JSLoadCultureInfoFromBrowser(string localeName { char* buffer = stackalloc char[CULTURE_INFO_BUFFER_LEN]; nint exceptionPtr = Interop.JsGlobalization.GetCultureInfo(localeName, buffer, CULTURE_INFO_BUFFER_LEN, out int resultLength); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); string result = new string(buffer, 0, resultLength); string[] subresults = result.Split("##"); if (subresults.Length < 4) @@ -93,11 +83,13 @@ private static unsafe int GetFirstDayOfWeek(string localeName) nint exceptionPtr = Interop.JsGlobalization.GetFirstDayOfWeek(localeName, out int result); if (exceptionPtr != IntPtr.Zero) { + int success = Helper.MarshalAndThrowIfException( + exceptionPtr, + failOnlyDebug: true, + failureMessage: $"[CultureData.GetFirstDayOfWeek()] failed with"); // Failed, just use 0 - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - Debug.Fail($"[CultureData.GetFirstDayOfWeek()] failed with {message}"); - return 0; + if (success == -1) + return 0; } return result; } @@ -107,13 +99,35 @@ private static unsafe int GetFirstWeekOfYear(string localeName) nint exceptionPtr = Interop.JsGlobalization.GetFirstWeekOfYear(localeName, out int result); if (exceptionPtr != IntPtr.Zero) { + int success = Helper.MarshalAndThrowIfException( + exceptionPtr, + failOnlyDebug: true, + failureMessage: $"[CultureData.GetFirstWeekOfYear()] failed with"); // Failed, just use 0 + if (success == -1) + return 0; + } + return result; + } + } + + internal static class Helper + { + internal static int MarshalAndThrowIfException(nint exceptionPtr, bool failOnlyDebug = false, string failureMessage = "") + { + if (exceptionPtr != IntPtr.Zero) + { string message = Marshal.PtrToStringUni(exceptionPtr)!; Marshal.FreeHGlobal(exceptionPtr); - Debug.Fail($"[CultureData.GetFirstWeekOfYear()] failed with {message}"); - return 0; + if (failOnlyDebug) + { + Debug.Fail($"{failureMessage} {message}"); + return -1; + } + throw new Exception(message); } - return result; + return 0; } + } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs index c01593f537b93a..92a609d6c1602b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs @@ -17,12 +17,7 @@ internal unsafe void JsChangeCase(char* src, int srcLen, char* dstBuffer, int ds nint exceptionPtr = HasEmptyCultureName ? Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper) : Interop.JsGlobalization.ChangeCase(_cultureName, src, srcLen, dstBuffer, dstBufferCapacity, toUpper); - if (exceptionPtr != IntPtr.Zero) - { - string message = Marshal.PtrToStringUni(exceptionPtr)!; - Marshal.FreeHGlobal(exceptionPtr); - throw new Exception(message); - } + Helper.MarshalAndThrowIfException(exceptionPtr); } } } diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index 9c6403ee18981b..db10866498642f 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -58,17 +59,17 @@ extern void mono_wasm_invoke_jsimport_ST (int function_handle, void *args); #endif /* DISABLE_THREADS */ // HybridGlobalization -extern void* mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); -extern void* mono_wasm_change_case (MonoString **culture, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); -extern void* mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *resultPtr); -extern void* mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); -extern void* mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); -extern void* mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *resultPtr); -extern void* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern void* mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern void* mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern void* mono_wasm_get_first_day_of_week (MonoString **culture, int *resultPtr); -extern void* mono_wasm_get_first_week_of_year (MonoString **culture, int *resultPtr); +extern char16_t* mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); +extern char16_t* mono_wasm_change_case (MonoString **culture, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); +extern char16_t* mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *resultPtr); +extern char16_t* mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern char16_t* mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern char16_t* mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *resultPtr); +extern char16_t* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_first_day_of_week (MonoString **culture, int *resultPtr); +extern char16_t* mono_wasm_get_first_week_of_year (MonoString **culture, int *resultPtr); void bindings_initialize_internals (void) { From ad79d0132d8aa6ebdcb65c326ce36caf18e9d5ee Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Tue, 23 Apr 2024 10:09:30 +0000 Subject: [PATCH 09/10] remove MonoString that is not thread-safe --- .../src/Interop/Browser/Interop.Calendar.cs | 2 +- .../Interop/Browser/Interop.CompareInfo.cs | 8 +- .../src/Interop/Browser/Interop.Locale.cs | 8 +- .../src/Interop/Browser/Interop.TextInfo.cs | 2 +- .../Globalization/CalendarData.Browser.cs | 50 +++++---- .../System/Globalization/CompareInfo.Icu.cs | 20 ++-- .../Globalization/CompareInfo.WebAssembly.cs | 28 ++--- .../Globalization/CultureData.Browser.cs | 100 +++++++++++------- .../Globalization/TextInfo.WebAssembly.cs | 12 ++- src/mono/browser/runtime/corebindings.c | 20 ++-- .../runtime/hybrid-globalization/calendar.ts | 12 +-- .../hybrid-globalization/change-case.ts | 12 +-- .../hybrid-globalization/collations.ts | 33 ++---- .../hybrid-globalization/culture-info.ts | 12 +-- .../runtime/hybrid-globalization/locales.ts | 31 ++---- 15 files changed, 175 insertions(+), 175 deletions(-) diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs index 0824fffcb5ee54..73fbfa924d141d 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Calendar.cs @@ -9,6 +9,6 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint GetCalendarInfo(in string culture, CalendarId calendarId, char* buffer, int bufferMaxLength, out int bufferLength); + internal static extern unsafe nint GetCalendarInfo(char* culture, int cultureLength, CalendarId calendarId, char* buffer, int bufferMaxLength, out int bufferLength); } } diff --git a/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs b/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs index 6536cee676304b..638934edb416d6 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.CompareInfo.cs @@ -8,15 +8,15 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint CompareString(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int resultPtr); + internal static extern unsafe nint CompareString(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint StartsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); + internal static extern unsafe nint StartsWith(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint EndsWith(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); + internal static extern unsafe nint EndsWith(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, out bool resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint IndexOf(in string culture, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, bool fromBeginning, out int resultPtr); + internal static extern unsafe nint IndexOf(char* culture, int cultureLength, char* str1, int str1Len, char* str2, int str2Len, global::System.Globalization.CompareOptions options, bool fromBeginning, out int resultPtr); } } diff --git a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs index d53372b8e98bfc..b2dc0db99c00c0 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.Locale.cs @@ -8,12 +8,12 @@ internal static partial class Interop internal static unsafe partial class JsGlobalization { [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint GetCultureInfo(in string culture, char* buffer, int bufferMaxLength, out int resultLength); + internal static extern unsafe nint GetCultureInfo(char* culture, int cultureLength, char* buffer, int bufferMaxLength, out int resultLength); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint GetFirstDayOfWeek(in string culture, out int resultPtr); + internal static extern unsafe nint GetFirstDayOfWeek(char* culture, int cultureLength, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint GetFirstWeekOfYear(in string culture, out int resultPtr); + internal static extern unsafe nint GetFirstWeekOfYear(char* culture, int cultureLength, out int resultPtr); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint GetLocaleInfo(in string locale, in string culture, char* buffer, int bufferLength, out int resultLength); + internal static extern unsafe nint GetLocaleInfo(char* locale, int localeLength, char* culture, int cultureLength, char* buffer, int bufferLength, out int resultLength); } } diff --git a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs index 456837df57b44e..a10d2897f75be0 100644 --- a/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs +++ b/src/libraries/Common/src/Interop/Browser/Interop.TextInfo.cs @@ -10,6 +10,6 @@ internal static unsafe partial class JsGlobalization [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern unsafe nint ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal static extern unsafe nint ChangeCase(in string culture, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); + internal static extern unsafe nint ChangeCase(char* culture, int cultureLen, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs index 646611c04b0fa5..582492c6c40f84 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Browser.cs @@ -14,29 +14,33 @@ internal sealed partial class CalendarData private const int CALENDAR_INFO_BUFFER_LEN = 1000; private unsafe bool JSLoadCalendarDataFromBrowser(string localeName, CalendarId calendarId) { - char* buffer = stackalloc char[CALENDAR_INFO_BUFFER_LEN]; - nint exceptionPtr = Interop.JsGlobalization.GetCalendarInfo(localeName, calendarId, buffer, CALENDAR_INFO_BUFFER_LEN, out int resultLength); - Helper.MarshalAndThrowIfException(exceptionPtr); - string result = new string(buffer, 0, resultLength); - string[] subresults = result.Split("##"); - if (subresults.Length < 14) - throw new Exception("CalendarInfo recieved from the Browser is in icorrect format."); - // JS always has one result per locale, so even arrays are initialized with one element - this.sNativeName = string.IsNullOrEmpty(subresults[0]) ? ((CalendarId)calendarId).ToString() : subresults[0]; // this is EnglishName, not NativeName but it's the best we can do - this.saYearMonths = new string[] { subresults[1] }; - this.sMonthDay = subresults[2]; - this.saLongDates = new string[] { subresults[3] }; - this.saShortDates = new string[] { subresults[4] }; - this.saEraNames = new string[] { subresults[5] }; - this.saAbbrevEraNames = new string[] { subresults[6] }; - this.saDayNames = subresults[7].Split("||"); - this.saAbbrevDayNames = subresults[8].Split("||"); - this.saSuperShortDayNames = subresults[9].Split("||"); - this.saMonthNames = ResizeMonthsArray(subresults[10].Split("||")); - this.saAbbrevMonthNames = ResizeMonthsArray(subresults[11].Split("||")); - this.saMonthGenitiveNames = ResizeMonthsArray(subresults[12].Split("||")); - this.saAbbrevMonthGenitiveNames = ResizeMonthsArray(subresults[13].Split("||")); - return true; + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) + { + char* buffer = stackalloc char[CALENDAR_INFO_BUFFER_LEN]; + nint exceptionPtr = Interop.JsGlobalization.GetCalendarInfo(pLocaleName, localeNameSpan.Length, calendarId, buffer, CALENDAR_INFO_BUFFER_LEN, out int resultLength); + Helper.MarshalAndThrowIfException(exceptionPtr); + string result = new string(buffer, 0, resultLength); + string[] subresults = result.Split("##"); + if (subresults.Length < 14) + throw new Exception("CalendarInfo recieved from the Browser is in icorrect format."); + // JS always has one result per locale, so even arrays are initialized with one element + this.sNativeName = string.IsNullOrEmpty(subresults[0]) ? ((CalendarId)calendarId).ToString() : subresults[0]; // this is EnglishName, not NativeName but it's the best we can do + this.saYearMonths = new string[] { subresults[1] }; + this.sMonthDay = subresults[2]; + this.saLongDates = new string[] { subresults[3] }; + this.saShortDates = new string[] { subresults[4] }; + this.saEraNames = new string[] { subresults[5] }; + this.saAbbrevEraNames = new string[] { subresults[6] }; + this.saDayNames = subresults[7].Split("||"); + this.saAbbrevDayNames = subresults[8].Split("||"); + this.saSuperShortDayNames = subresults[9].Split("||"); + this.saMonthNames = ResizeMonthsArray(subresults[10].Split("||")); + this.saAbbrevMonthNames = ResizeMonthsArray(subresults[11].Split("||")); + this.saMonthGenitiveNames = ResizeMonthsArray(subresults[12].Split("||")); + this.saAbbrevMonthGenitiveNames = ResizeMonthsArray(subresults[13].Split("||")); + return true; + } static string[] ResizeMonthsArray(string[] months) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs index a7029ba0989252..bc532fcb26c059 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.Icu.cs @@ -198,9 +198,13 @@ private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan source, Rea #if TARGET_BROWSER if (GlobalizationMode.Hybrid) { - nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int result); - Helper.MarshalAndThrowIfException(exceptionPtr); - return result; + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) + { + nint exceptionPtr = Interop.JsGlobalization.IndexOf(pCultureName, cultureNameSpan.Length, b, target.Length, a, source.Length, options, fromBeginning, out int result); + Helper.MarshalAndThrowIfException(exceptionPtr); + return result; + } } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS if (GlobalizationMode.Hybrid) @@ -299,9 +303,13 @@ private unsafe int IndexOfOrdinalHelper(ReadOnlySpan source, ReadOnlySpan< #if TARGET_BROWSER if (GlobalizationMode.Hybrid) { - nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, b, target.Length, a, source.Length, options, fromBeginning, out int result); - Helper.MarshalAndThrowIfException(exceptionPtr); - return result; + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) + { + nint exceptionPtr = Interop.JsGlobalization.IndexOf(pCultureName, cultureNameSpan.Length, b, target.Length, a, source.Length, options, fromBeginning, out int result); + Helper.MarshalAndThrowIfException(exceptionPtr); + return result; + } } #elif TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS if (GlobalizationMode.Hybrid) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs index c5483721db3897..e8935a6d2439cc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CompareInfo.WebAssembly.cs @@ -47,13 +47,14 @@ private static void AssertIndexingSupported(CompareOptions options, string cultu private unsafe int JsCompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) { AssertHybridOnWasm(options); - string cultureName = m_name; - AssertComparisonSupported(options, cultureName); + AssertComparisonSupported(options, m_name); + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - nint exceptionPtr = Interop.JsGlobalization.CompareString(cultureName, pString1, string1.Length, pString2, string2.Length, options, out int cmpResult); + nint exceptionPtr = Interop.JsGlobalization.CompareString(pCultureName, cultureNameSpan.Length, pString1, string1.Length, pString2, string2.Length, options, out int cmpResult); Helper.MarshalAndThrowIfException(exceptionPtr); return cmpResult; } @@ -63,13 +64,14 @@ private unsafe bool JsStartsWith(ReadOnlySpan source, ReadOnlySpan p { AssertHybridOnWasm(options); Debug.Assert(!prefix.IsEmpty); - string cultureName = m_name; - AssertIndexingSupported(options, cultureName); + AssertIndexingSupported(options, m_name); + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - nint exceptionPtr = Interop.JsGlobalization.StartsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); + nint exceptionPtr = Interop.JsGlobalization.StartsWith(pCultureName, cultureNameSpan.Length, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); Helper.MarshalAndThrowIfException(exceptionPtr); return result; } @@ -79,13 +81,14 @@ private unsafe bool JsEndsWith(ReadOnlySpan source, ReadOnlySpan pre { AssertHybridOnWasm(options); Debug.Assert(!prefix.IsEmpty); - string cultureName = m_name; - AssertIndexingSupported(options, cultureName); + AssertIndexingSupported(options, m_name); + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - nint exceptionPtr = Interop.JsGlobalization.EndsWith(cultureName, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); + nint exceptionPtr = Interop.JsGlobalization.EndsWith(pCultureName, cultureNameSpan.Length, pSource, source.Length, pPrefix, prefix.Length, options, out bool result); Helper.MarshalAndThrowIfException(exceptionPtr); return result; } @@ -95,8 +98,7 @@ private unsafe int JsIndexOfCore(ReadOnlySpan source, ReadOnlySpan t { AssertHybridOnWasm(options); Debug.Assert(!target.IsEmpty); - string cultureName = m_name; - AssertIndexingSupported(options, cultureName); + AssertIndexingSupported(options, m_name); if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) { @@ -104,10 +106,12 @@ private unsafe int JsIndexOfCore(ReadOnlySpan source, ReadOnlySpan t IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr, fromBeginning) : IndexOfOrdinalHelper(source, target, options, matchLengthPtr, fromBeginning); } + ReadOnlySpan cultureNameSpan = m_name.AsSpan(); fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pTarget = &MemoryMarshal.GetReference(target)) + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) { - nint exceptionPtr = Interop.JsGlobalization.IndexOf(m_name, pTarget, target.Length, pSource, source.Length, options, fromBeginning, out int idx); + nint exceptionPtr = Interop.JsGlobalization.IndexOf(pCultureName, cultureNameSpan.Length, pTarget, target.Length, pSource, source.Length, options, fromBeginning, out int idx); Helper.MarshalAndThrowIfException(exceptionPtr); return idx; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs index feb3173e15adc5..417bd563bf3574 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Browser.cs @@ -42,16 +42,22 @@ private void JSInitLocaleInfo() private unsafe (string, string) JSGetLocaleInfo(string cultureName, string localeName) { - char* buffer = stackalloc char[LOCALE_INFO_BUFFER_LEN]; - nint exceptionPtr = Interop.JsGlobalization.GetLocaleInfo(cultureName, localeName, buffer, LOCALE_INFO_BUFFER_LEN, out int resultLength); - Helper.MarshalAndThrowIfException(exceptionPtr); - string result = new string(buffer, 0, resultLength); - string[] subresults = result.Split("##"); - if (subresults.Length == 0) - throw new Exception("LocaleInfo recieved from the Browser is in incorrect format."); - if (subresults.Length == 1) - return (subresults[0], ""); // Neutral culture - return (subresults[0], subresults[1]); + ReadOnlySpan cultureNameSpan = cultureName.AsSpan(); + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureNameSpan)) + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) + { + char* buffer = stackalloc char[LOCALE_INFO_BUFFER_LEN]; + nint exceptionPtr = Interop.JsGlobalization.GetLocaleInfo(pCultureName, cultureNameSpan.Length, pLocaleName, localeNameSpan.Length, buffer, LOCALE_INFO_BUFFER_LEN, out int resultLength); + Helper.MarshalAndThrowIfException(exceptionPtr); + string result = new string(buffer, 0, resultLength); + string[] subresults = result.Split("##"); + if (subresults.Length == 0) + throw new Exception("LocaleInfo recieved from the Browser is in incorrect format."); + if (subresults.Length == 1) + return (subresults[0], ""); // Neutral culture + return (subresults[0], subresults[1]); + } } private string JSGetNativeDisplayName(string localeName, string cultureName) @@ -64,50 +70,62 @@ private string JSGetNativeDisplayName(string localeName, string cultureName) private static unsafe CultureData JSLoadCultureInfoFromBrowser(string localeName, CultureData culture) { - char* buffer = stackalloc char[CULTURE_INFO_BUFFER_LEN]; - nint exceptionPtr = Interop.JsGlobalization.GetCultureInfo(localeName, buffer, CULTURE_INFO_BUFFER_LEN, out int resultLength); - Helper.MarshalAndThrowIfException(exceptionPtr); - string result = new string(buffer, 0, resultLength); - string[] subresults = result.Split("##"); - if (subresults.Length < 4) - throw new Exception("CultureInfo recieved from the Browser is in incorrect format."); - culture._sAM1159 = subresults[0]; - culture._sPM2359 = subresults[1]; - culture._saLongTimes = new string[] { subresults[2] }; - culture._saShortTimes = new string[] { subresults[3] }; + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) + { + char* buffer = stackalloc char[CULTURE_INFO_BUFFER_LEN]; + nint exceptionPtr = Interop.JsGlobalization.GetCultureInfo(pLocaleName, localeNameSpan.Length, buffer, CULTURE_INFO_BUFFER_LEN, out int resultLength); + Helper.MarshalAndThrowIfException(exceptionPtr); + string result = new string(buffer, 0, resultLength); + string[] subresults = result.Split("##"); + if (subresults.Length < 4) + throw new Exception("CultureInfo recieved from the Browser is in incorrect format."); + culture._sAM1159 = subresults[0]; + culture._sPM2359 = subresults[1]; + culture._saLongTimes = new string[] { subresults[2] }; + culture._saShortTimes = new string[] { subresults[3] }; + } return culture; } private static unsafe int GetFirstDayOfWeek(string localeName) { - nint exceptionPtr = Interop.JsGlobalization.GetFirstDayOfWeek(localeName, out int result); - if (exceptionPtr != IntPtr.Zero) + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) { - int success = Helper.MarshalAndThrowIfException( - exceptionPtr, - failOnlyDebug: true, - failureMessage: $"[CultureData.GetFirstDayOfWeek()] failed with"); - // Failed, just use 0 - if (success == -1) - return 0; + nint exceptionPtr = Interop.JsGlobalization.GetFirstDayOfWeek(pLocaleName, localeNameSpan.Length, out int result); + if (exceptionPtr != IntPtr.Zero) + { + int success = Helper.MarshalAndThrowIfException( + exceptionPtr, + failOnlyDebug: true, + failureMessage: $"[CultureData.GetFirstDayOfWeek()] failed with"); + // Failed, just use 0 + if (success == -1) + return 0; + } + return result; } - return result; } private static unsafe int GetFirstWeekOfYear(string localeName) { - nint exceptionPtr = Interop.JsGlobalization.GetFirstWeekOfYear(localeName, out int result); - if (exceptionPtr != IntPtr.Zero) + ReadOnlySpan localeNameSpan = localeName.AsSpan(); + fixed (char* pLocaleName = &MemoryMarshal.GetReference(localeNameSpan)) { - int success = Helper.MarshalAndThrowIfException( - exceptionPtr, - failOnlyDebug: true, - failureMessage: $"[CultureData.GetFirstWeekOfYear()] failed with"); - // Failed, just use 0 - if (success == -1) - return 0; + nint exceptionPtr = Interop.JsGlobalization.GetFirstWeekOfYear(pLocaleName, localeNameSpan.Length, out int result); + if (exceptionPtr != IntPtr.Zero) + { + int success = Helper.MarshalAndThrowIfException( + exceptionPtr, + failOnlyDebug: true, + failureMessage: $"[CultureData.GetFirstWeekOfYear()] failed with"); + // Failed, just use 0 + if (success == -1) + return 0; + } + return result; } - return result; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs index 92a609d6c1602b..05e8cc3e1d0495 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.WebAssembly.cs @@ -14,10 +14,14 @@ internal unsafe void JsChangeCase(char* src, int srcLen, char* dstBuffer, int ds Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(GlobalizationMode.Hybrid); - nint exceptionPtr = HasEmptyCultureName ? - Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper) : - Interop.JsGlobalization.ChangeCase(_cultureName, src, srcLen, dstBuffer, dstBufferCapacity, toUpper); - Helper.MarshalAndThrowIfException(exceptionPtr); + ReadOnlySpan cultureName = _cultureName.AsSpan(); + fixed (char* pCultureName = &MemoryMarshal.GetReference(cultureName)) + { + nint exceptionPtr = HasEmptyCultureName ? + Interop.JsGlobalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, toUpper) : + Interop.JsGlobalization.ChangeCase(pCultureName, cultureName.Length, src, srcLen, dstBuffer, dstBufferCapacity, toUpper); + Helper.MarshalAndThrowIfException(exceptionPtr); + } } } } diff --git a/src/mono/browser/runtime/corebindings.c b/src/mono/browser/runtime/corebindings.c index 906a75e9e4fdf8..39b25e5bff333d 100644 --- a/src/mono/browser/runtime/corebindings.c +++ b/src/mono/browser/runtime/corebindings.c @@ -60,16 +60,16 @@ extern void mono_wasm_invoke_jsimport_ST (int function_handle, void *args); // HybridGlobalization extern char16_t* mono_wasm_change_case_invariant (const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); -extern char16_t* mono_wasm_change_case (MonoString **culture, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); -extern char16_t* mono_wasm_compare_string (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *resultPtr); -extern char16_t* mono_wasm_starts_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); -extern char16_t* mono_wasm_ends_with (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); -extern char16_t* mono_wasm_index_of (MonoString **culture, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *resultPtr); -extern char16_t* mono_wasm_get_calendar_info (MonoString **culture, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern char16_t* mono_wasm_get_locale_info (MonoString **locale, MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern char16_t* mono_wasm_get_culture_info (MonoString **culture, const uint16_t* result, int32_t resultMaxLength, int *resultLength); -extern char16_t* mono_wasm_get_first_day_of_week (MonoString **culture, int *resultPtr); -extern char16_t* mono_wasm_get_first_week_of_year (MonoString **culture, int *resultPtr); +extern char16_t* mono_wasm_change_case (const uint16_t* culture, int32_t cultureLength, const uint16_t* src, int32_t srcLength, uint16_t* dst, int32_t dstLength, mono_bool bToUpper); +extern char16_t* mono_wasm_compare_string (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, int *resultPtr); +extern char16_t* mono_wasm_starts_with (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern char16_t* mono_wasm_ends_with (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool *resultPtr); +extern char16_t* mono_wasm_index_of (const uint16_t* culture, int32_t cultureLength, const uint16_t* str1, int32_t str1Length, const uint16_t* str2, int32_t str2Length, int32_t options, mono_bool fromBeginning, int *resultPtr); +extern char16_t* mono_wasm_get_calendar_info (const uint16_t* culture, int32_t cultureLength, int32_t calendarId, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_culture_info (const uint16_t* culture, int32_t cultureLength, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_locale_info (const uint16_t* locale, int32_t localeLength, const uint16_t* culture, int32_t cultureLength, const uint16_t* result, int32_t resultMaxLength, int *resultLength); +extern char16_t* mono_wasm_get_first_day_of_week (const uint16_t* culture, int32_t cultureLength, int *resultPtr); +extern char16_t* mono_wasm_get_first_week_of_year (const uint16_t* culture, int32_t cultureLength, int *resultPtr); void bindings_initialize_internals (void) { diff --git a/src/mono/browser/runtime/hybrid-globalization/calendar.ts b/src/mono/browser/runtime/hybrid-globalization/calendar.ts index 7d7eb94f10a402..f569fc02c7c5a3 100644 --- a/src/mono/browser/runtime/hybrid-globalization/calendar.ts +++ b/src/mono/browser/runtime/hybrid-globalization/calendar.ts @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. /* eslint-disable no-inner-declarations */ -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16, stringToUTF16Ptr } from "../strings"; -import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; +import { VoidPtrNull } from "../types/internal"; import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { INNER_SEPARATOR, OUTER_SEPARATOR, normalizeSpaces } from "./helpers"; import { setI32 } from "../memory"; @@ -14,10 +13,9 @@ const YEAR_CODE = "yyyy"; const DAY_CODE = "d"; // this function joins all calendar info with OUTER_SEPARATOR into one string and returns it back to managed code -export function mono_wasm_get_calendar_info (culture: MonoStringRef, calendarId: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_get_calendar_info (culture: number, cultureLength: number, calendarId: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const locale = cultureName ? cultureName : undefined; const calendarInfo = { EnglishName: "", @@ -63,8 +61,6 @@ export function mono_wasm_get_calendar_info (culture: MonoStringRef, calendarId: return VoidPtrNull; } catch (ex: any) { return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/change-case.ts b/src/mono/browser/runtime/hybrid-globalization/change-case.ts index 625a86e6a9269e..b0943580b0def4 100644 --- a/src/mono/browser/runtime/hybrid-globalization/change-case.ts +++ b/src/mono/browser/runtime/hybrid-globalization/change-case.ts @@ -1,9 +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 { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, utf16ToStringLoop, stringToUTF16, stringToUTF16Ptr } from "../strings"; -import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { utf16ToStringLoop, stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; +import { VoidPtrNull } from "../types/internal"; import { VoidPtr } from "../types/emscripten"; import { localHeapViewU16, setU16_local } from "../memory"; import { isSurrogate } from "./helpers"; @@ -62,10 +61,9 @@ 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, dstLength: number, toUpper: number): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_change_case (culture: number, cultureLength: number, src: number, srcLength: number, dst: number, dstLength: number, toUpper: number): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); if (!cultureName) throw new Error("Cannot change case, the culture name is null."); const input = utf16ToStringLoop(src, src + 2 * srcLength); @@ -115,8 +113,6 @@ export function mono_wasm_change_case (culture: MonoStringRef, src: number, srcL return VoidPtrNull; } catch (ex: any) { return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/collations.ts b/src/mono/browser/runtime/hybrid-globalization/collations.ts index 0cb44b692af054..bdc32ea43f1124 100644 --- a/src/mono/browser/runtime/hybrid-globalization/collations.ts +++ b/src/mono/browser/runtime/hybrid-globalization/collations.ts @@ -1,9 +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 { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16Ptr, utf16ToString } from "../strings"; -import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { stringToUTF16Ptr, utf16ToString } from "../strings"; +import { VoidPtrNull } from "../types/internal"; import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { GraphemeSegmenter } from "./grapheme-segmenter"; import { setI32 } from "../memory"; @@ -12,10 +11,9 @@ const COMPARISON_ERROR = -2; const INDEXING_ERROR = -1; let graphemeSegmenterCached: GraphemeSegmenter | null; -export function mono_wasm_compare_string (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_compare_string (culture: number, cultureLength: number, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const string1 = utf16ToString(str1, (str1 + 2 * str1Length)); const string2 = utf16ToString(str2, (str2 + 2 * str2Length)); const casePicker = (options & 0x1f); @@ -26,15 +24,12 @@ export function mono_wasm_compare_string (culture: MonoStringRef, str1: number, } catch (ex: any) { setI32(resultPtr, COMPARISON_ERROR); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } -export function mono_wasm_starts_with (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_starts_with (culture: number, cultureLength: number, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const prefix = decodeToCleanString(str2, str2Length); // no need to look for an empty string if (prefix.length == 0) { @@ -58,15 +53,12 @@ export function mono_wasm_starts_with (culture: MonoStringRef, str1: number, str } catch (ex: any) { setI32(resultPtr, INDEXING_ERROR); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } -export function mono_wasm_ends_with (culture: MonoStringRef, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_ends_with (culture: number, cultureLength: number, str1: number, str1Length: number, str2: number, str2Length: number, options: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const suffix = decodeToCleanString(str2, str2Length); if (suffix.length == 0) { setI32(resultPtr, 1); // true @@ -90,13 +82,10 @@ export function mono_wasm_ends_with (culture: MonoStringRef, str1: number, str1L } catch (ex: any) { setI32(resultPtr, INDEXING_ERROR); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } -export function mono_wasm_index_of (culture: MonoStringRef, needlePtr: number, needleLength: number, srcPtr: number, srcLength: number, options: number, fromBeginning: number, resultPtr: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_index_of (culture: number, cultureLength: number, needlePtr: number, needleLength: number, srcPtr: number, srcLength: number, options: number, fromBeginning: number, resultPtr: Int32Ptr): VoidPtr { try { const needle = utf16ToString(needlePtr, (needlePtr + 2 * needleLength)); // no need to look for an empty string @@ -111,7 +100,7 @@ export function mono_wasm_index_of (culture: MonoStringRef, needlePtr: number, n setI32(resultPtr, fromBeginning ? 0 : srcLength); return VoidPtrNull; } - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const locale = cultureName ? cultureName : undefined; const casePicker = (options & 0x1f); let result = -1; @@ -157,8 +146,6 @@ export function mono_wasm_index_of (culture: MonoStringRef, needlePtr: number, n } catch (ex: any) { setI32(resultPtr, INDEXING_ERROR); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } function checkMatchFound (str1: string, str2: string, locale: string | undefined, casePicker: number): boolean { diff --git a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts index 5d37e9e9fac2b0..5eca7ff26520ff 100644 --- a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts +++ b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts @@ -2,16 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. import { setI32 } from "../memory"; -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16, stringToUTF16Ptr } from "../strings"; +import { stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; import { Int32Ptr, VoidPtr } from "../types/emscripten"; -import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { VoidPtrNull } from "../types/internal"; import { OUTER_SEPARATOR, normalizeLocale, normalizeSpaces } from "./helpers"; -export function mono_wasm_get_culture_info (culture: MonoStringRef, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_get_culture_info (culture: number, cultureLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const cultureInfo = { AmDesignator: "", PmDesignator: "", @@ -34,8 +32,6 @@ export function mono_wasm_get_culture_info (culture: MonoStringRef, dst: number, } catch (ex: any) { setI32(dstLength, -1); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/locales.ts b/src/mono/browser/runtime/hybrid-globalization/locales.ts index 88c3d890001126..ba3265b1b23d0c 100644 --- a/src/mono/browser/runtime/hybrid-globalization/locales.ts +++ b/src/mono/browser/runtime/hybrid-globalization/locales.ts @@ -2,17 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. import { setI32 } from "../memory"; -import { mono_wasm_new_external_root } from "../roots"; -import { monoStringToString, stringToUTF16, stringToUTF16Ptr } from "../strings"; +import { stringToUTF16, stringToUTF16Ptr, utf16ToString } from "../strings"; import { Int32Ptr, VoidPtr } from "../types/emscripten"; -import { MonoString, MonoStringRef, VoidPtrNull } from "../types/internal"; +import { VoidPtrNull } from "../types/internal"; import { OUTER_SEPARATOR, normalizeLocale } from "./helpers"; -export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoStringRef, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { - const localeRoot = mono_wasm_new_external_root(locale), - cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_get_locale_info (culture: number, cultureLength: number, locale: number, localeLength: number, dst: number, dstMaxLength: number, dstLength: Int32Ptr): VoidPtr { try { - const localeNameOriginal = monoStringToString(localeRoot); + const localeNameOriginal = utf16ToString(locale, (locale + 2 * localeLength)); const localeName = normalizeLocale(localeNameOriginal); if (!localeName && localeNameOriginal) { // handle non-standard or malformed locales by forwarding the locale code @@ -20,7 +17,7 @@ export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoS setI32(dstLength, localeNameOriginal.length); return VoidPtrNull; } - const cultureNameOriginal = monoStringToString(cultureRoot); + const cultureNameOriginal = utf16ToString(culture, (culture + 2 * cultureLength)); const cultureName = normalizeLocale(cultureNameOriginal); if (!localeName || !cultureName) @@ -75,16 +72,12 @@ export function mono_wasm_get_locale_info (culture: MonoStringRef, locale: MonoS } catch (ex: any) { setI32(dstLength, -1); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } -export function mono_wasm_get_first_day_of_week (culture: MonoStringRef, resultPtr: Int32Ptr): VoidPtr { - - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_get_first_day_of_week (culture: number, cultureLength: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const canonicalLocale = normalizeLocale(cultureName); const result = getFirstDayOfWeek(canonicalLocale); setI32(resultPtr, result); @@ -92,16 +85,12 @@ export function mono_wasm_get_first_day_of_week (culture: MonoStringRef, resultP } catch (ex: any) { setI32(resultPtr, -1); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } -export function mono_wasm_get_first_week_of_year (culture: MonoStringRef, resultPtr: Int32Ptr): VoidPtr { - - const cultureRoot = mono_wasm_new_external_root(culture); +export function mono_wasm_get_first_week_of_year (culture: number, cultureLength: number, resultPtr: Int32Ptr): VoidPtr { try { - const cultureName = monoStringToString(cultureRoot); + const cultureName = utf16ToString(culture, (culture + 2 * cultureLength)); const canonicalLocale = normalizeLocale(cultureName); const result = getFirstWeekOfYear(canonicalLocale); setI32(resultPtr, result); @@ -109,8 +98,6 @@ export function mono_wasm_get_first_week_of_year (culture: MonoStringRef, result } catch (ex: any) { setI32(resultPtr, -1); return stringToUTF16Ptr((ex)); - } finally { - cultureRoot.release(); } } From b7a3165ea5333c2f92d393fd2069057716d2c316 Mon Sep 17 00:00:00 2001 From: Ilona Tomkowicz <32700855+ilonatommy@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:11:23 +0000 Subject: [PATCH 10/10] Preserve stack from JS correctly. --- src/mono/browser/runtime/hybrid-globalization/calendar.ts | 2 +- .../browser/runtime/hybrid-globalization/change-case.ts | 4 ++-- .../browser/runtime/hybrid-globalization/collations.ts | 8 ++++---- .../browser/runtime/hybrid-globalization/culture-info.ts | 2 +- src/mono/browser/runtime/hybrid-globalization/locales.ts | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mono/browser/runtime/hybrid-globalization/calendar.ts b/src/mono/browser/runtime/hybrid-globalization/calendar.ts index f569fc02c7c5a3..2d87d1c085cc04 100644 --- a/src/mono/browser/runtime/hybrid-globalization/calendar.ts +++ b/src/mono/browser/runtime/hybrid-globalization/calendar.ts @@ -60,7 +60,7 @@ export function mono_wasm_get_calendar_info (culture: number, cultureLength: num setI32(dstLength, result.length); return VoidPtrNull; } catch (ex: any) { - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/change-case.ts b/src/mono/browser/runtime/hybrid-globalization/change-case.ts index b0943580b0def4..437aabb42bfcd2 100644 --- a/src/mono/browser/runtime/hybrid-globalization/change-case.ts +++ b/src/mono/browser/runtime/hybrid-globalization/change-case.ts @@ -57,7 +57,7 @@ export function mono_wasm_change_case_invariant (src: number, srcLength: number, } return VoidPtrNull; } catch (ex: any) { - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } @@ -112,7 +112,7 @@ export function mono_wasm_change_case (culture: number, cultureLength: number, s } return VoidPtrNull; } catch (ex: any) { - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/collations.ts b/src/mono/browser/runtime/hybrid-globalization/collations.ts index bdc32ea43f1124..b329b39b15d0e1 100644 --- a/src/mono/browser/runtime/hybrid-globalization/collations.ts +++ b/src/mono/browser/runtime/hybrid-globalization/collations.ts @@ -23,7 +23,7 @@ export function mono_wasm_compare_string (culture: number, cultureLength: number return VoidPtrNull; } catch (ex: any) { setI32(resultPtr, COMPARISON_ERROR); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } @@ -52,7 +52,7 @@ export function mono_wasm_starts_with (culture: number, cultureLength: number, s return VoidPtrNull; } catch (ex: any) { setI32(resultPtr, INDEXING_ERROR); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } @@ -81,7 +81,7 @@ export function mono_wasm_ends_with (culture: number, cultureLength: number, str return VoidPtrNull; } catch (ex: any) { setI32(resultPtr, INDEXING_ERROR); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } @@ -145,7 +145,7 @@ export function mono_wasm_index_of (culture: number, cultureLength: number, need return VoidPtrNull; } catch (ex: any) { setI32(resultPtr, INDEXING_ERROR); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } function checkMatchFound (str1: string, str2: string, locale: string | undefined, casePicker: number): boolean { diff --git a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts index 5eca7ff26520ff..70b36296407bbb 100644 --- a/src/mono/browser/runtime/hybrid-globalization/culture-info.ts +++ b/src/mono/browser/runtime/hybrid-globalization/culture-info.ts @@ -31,7 +31,7 @@ export function mono_wasm_get_culture_info (culture: number, cultureLength: numb return VoidPtrNull; } catch (ex: any) { setI32(dstLength, -1); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } diff --git a/src/mono/browser/runtime/hybrid-globalization/locales.ts b/src/mono/browser/runtime/hybrid-globalization/locales.ts index ba3265b1b23d0c..da6a478d1e3931 100644 --- a/src/mono/browser/runtime/hybrid-globalization/locales.ts +++ b/src/mono/browser/runtime/hybrid-globalization/locales.ts @@ -71,7 +71,7 @@ export function mono_wasm_get_locale_info (culture: number, cultureLength: numbe return VoidPtrNull; } catch (ex: any) { setI32(dstLength, -1); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } @@ -84,7 +84,7 @@ export function mono_wasm_get_first_day_of_week (culture: number, cultureLength: return VoidPtrNull; } catch (ex: any) { setI32(resultPtr, -1); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } } @@ -97,7 +97,7 @@ export function mono_wasm_get_first_week_of_year (culture: number, cultureLength return VoidPtrNull; } catch (ex: any) { setI32(resultPtr, -1); - return stringToUTF16Ptr((ex)); + return stringToUTF16Ptr(ex.toString()); } }