diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/JavaScriptTests.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/JavaScriptTests.cs index 005e54ac03f0d5..16e4ffd7cedc55 100644 --- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/JavaScriptTests.cs +++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/JavaScriptTests.cs @@ -95,10 +95,10 @@ public static void FunctionSum() public static void FunctionMath() { JSObject math = (JSObject)Runtime.GetGlobalObject("Math"); - Assert.NotNull(math); + Assert.True(math != null, "math != null"); Function mathMax = (Function)math.GetObjectProperty("max"); - Assert.NotNull(mathMax); + Assert.True(mathMax != null, "mathMax != null"); var maxValue = (int)mathMax.Apply(null, new object[] { 5, 6, 2, 3, 7 }); Assert.Equal(7, maxValue); @@ -107,7 +107,7 @@ public static void FunctionMath() Assert.Equal(7, maxValue); Function mathMin = (Function)((JSObject)Runtime.GetGlobalObject("Math")).GetObjectProperty("min"); - Assert.NotNull(mathMin); + Assert.True(mathMin != null, "mathMin != null"); var minValue = (int)mathMin.Apply(null, new object[] { 5, 6, 2, 3, 7 }); Assert.Equal(2, minValue); @@ -115,5 +115,39 @@ public static void FunctionMath() minValue = (int)mathMin.Call(null, 5, 6, 2, 3, 7); Assert.Equal(2, minValue); } + + private static string GetBigTestString() { + var expectedSb = new System.Text.StringBuilder(); + expectedSb.Append("start<<<"); + for (int i = 0; i < 4096000; i++) + expectedSb.Append(i % 10); + expectedSb.Append(">>>end"); + return expectedSb.ToString(); + } + + [ActiveIssue("https://github.com/dotnet/runtime/issues/42693")] + [Fact] + public static void InvokeJSMarshalsStrings() { + var invokeResult = Runtime.InvokeJS("\"a\0bc\""); + Assert.Equal("a\0bc", invokeResult); + + var expected = GetBigTestString(); + invokeResult = Runtime.InvokeJS("\"" + expected + "\""); + Assert.Equal(expected, invokeResult); + } + + [Fact] + public static void MarshalStringParametersFromJS() { + HelperMarshal._stringResource = null; + Runtime.InvokeJS("App.call_test_method(\"InvokeString\", [\"a\0bc\"])"); + Assert.Equal("a\0bc", HelperMarshal._stringResource); + + var expected = GetBigTestString(); + for (var i = 0; i < 10; i++) { + HelperMarshal._stringResource = null; + Runtime.InvokeJS("App.call_test_method(\"InvokeString\", [\"" + expected + "\"])"); + Assert.Equal(expected, HelperMarshal._stringResource); + } + } } } diff --git a/src/mono/wasm/runtime/binding_support.js b/src/mono/wasm/runtime/binding_support.js index 5131c7f678dcc3..59b229678d857d 100644 --- a/src/mono/wasm/runtime/binding_support.js +++ b/src/mono/wasm/runtime/binding_support.js @@ -52,7 +52,7 @@ var BindingSupportLib = { this.find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']); this.invoke_method = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number', 'number']); this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']); - this.js_string_to_mono_string = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']); + this.mono_wasm_string_from_utf16 = Module.cwrap ('mono_wasm_string_from_utf16', 'number', ['number', 'number']); this.mono_get_obj_type = Module.cwrap ('mono_wasm_get_obj_type', 'number', ['number']); this.mono_unbox_int = Module.cwrap ('mono_unbox_int', 'number', ['number']); this.mono_unbox_float = Module.cwrap ('mono_wasm_unbox_float', 'number', ['number']); @@ -140,6 +140,23 @@ var BindingSupportLib = { return this.call_method (this.is_simple_array, null, "mi", [ ele ]); }, + js_string_to_mono_string: function (string) { + if (string === null || typeof string === "undefined") + return 0; + + var buffer = Module._malloc (string.length * 2); + if (!buffer) + throw new Error ("out of memory"); + + var buffer16 = (buffer / 2) | 0; + for (var i = 0; i < string.length; i++) + Module.HEAP16[buffer16 + i] = string.charCodeAt (i); + + var result = this.mono_wasm_string_from_utf16 (buffer, string.length); + Module._free (buffer); + return result; + }, + mono_array_to_js_array: function (mono_array) { if (mono_array == 0) return null; diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 250f20fe8a712e..90fbc5453aa3a1 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -604,6 +604,17 @@ mono_wasm_string_from_js (const char *str) return NULL; } +EMSCRIPTEN_KEEPALIVE MonoString * +mono_wasm_string_from_utf16 (const mono_unichar2 * chars, int length) +{ + assert (length >= 0); + + if (chars) + return mono_string_new_utf16 (root_domain, chars, length); + else + return NULL; +} + static int class_is_task (MonoClass *klass) {