From 841a5888710033a2c11603ecde90221384b8f44f Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Mon, 26 Jan 2026 03:53:31 +0100 Subject: [PATCH 01/13] update codegen --- .../JSImportGenerator/JSGeneratorFactory.cs | 5 + .../JavaScript/JSMarshalerType.cs | 3 +- .../Marshaling/JSMarshalerArgument.Object.cs | 5 + .../Marshaling/JSMarshalerArgument.Single.cs | 99 +++++++++++++++++++ .../JavaScript/JavaScriptTestHelper.cs | 4 + 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs index 51b6d5764b1b76..ff9dc7a68fbbd2 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs @@ -214,6 +214,7 @@ private static ResolvedGeneratorAndType Create(TypePositionInfo info, StubCodeCo (KnownManagedType.Array, JSTypeFlags.Array, [KnownManagedType.Byte], [JSTypeFlags.Number]) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Byte]), (KnownManagedType.Array, JSTypeFlags.Array, [KnownManagedType.String], [JSTypeFlags.String]) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.String]), (KnownManagedType.Array, JSTypeFlags.Array, [KnownManagedType.Double], [JSTypeFlags.Number]) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Double]), + (KnownManagedType.Array, JSTypeFlags.Array, [KnownManagedType.Single], [JSTypeFlags.Number]) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Single]), (KnownManagedType.Array, JSTypeFlags.Array, [KnownManagedType.Int32], [JSTypeFlags.Number]) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Int32]), (KnownManagedType.Array, JSTypeFlags.Array, [KnownManagedType.JSObject], [JSTypeFlags.Object]) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.JSObject]), (KnownManagedType.Array, JSTypeFlags.Array, [KnownManagedType.Object], [JSTypeFlags.Any]) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Object]), @@ -222,6 +223,7 @@ private static ResolvedGeneratorAndType Create(TypePositionInfo info, StubCodeCo (KnownManagedType.Array, JSTypeFlags.Missing, [KnownManagedType.Byte], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Byte]), (KnownManagedType.Array, JSTypeFlags.Missing, [KnownManagedType.String], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.String]), (KnownManagedType.Array, JSTypeFlags.Missing, [KnownManagedType.Double], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Double]), + (KnownManagedType.Array, JSTypeFlags.Missing, [KnownManagedType.Single], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Single]), (KnownManagedType.Array, JSTypeFlags.Missing, [KnownManagedType.Int32], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.Int32]), (KnownManagedType.Array, JSTypeFlags.Missing, [KnownManagedType.JSObject], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Array), MarshalerType.Array, [MarshalerType.JSObject]), @@ -235,6 +237,7 @@ private static ResolvedGeneratorAndType Create(TypePositionInfo info, StubCodeCo (KnownManagedType.Span, JSTypeFlags.MemoryView, [KnownManagedType.Byte], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Span), MarshalerType.Span, [MarshalerType.Byte]), (KnownManagedType.Span, JSTypeFlags.MemoryView, [KnownManagedType.Int32], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Span), MarshalerType.Span, [MarshalerType.Int32]), (KnownManagedType.Span, JSTypeFlags.MemoryView, [KnownManagedType.Double], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Span), MarshalerType.Span, [MarshalerType.Double]), + (KnownManagedType.Span, JSTypeFlags.MemoryView, [KnownManagedType.Single], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.Span), MarshalerType.Span, [MarshalerType.Single]), (KnownManagedType.Span, JSTypeFlags.MemoryView, _, _) => failWithReason(SR.Format(SR.TypeNotSupportedName, info.ManagedType.FullTypeName)), @@ -242,12 +245,14 @@ private static ResolvedGeneratorAndType Create(TypePositionInfo info, StubCodeCo (KnownManagedType.Span, JSTypeFlags.Missing, [KnownManagedType.Byte], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), (KnownManagedType.Span, JSTypeFlags.Missing, [KnownManagedType.Int32], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), (KnownManagedType.Span, JSTypeFlags.Missing, [KnownManagedType.Double], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), + (KnownManagedType.Span, JSTypeFlags.Missing, [KnownManagedType.Single], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), // segment view (KnownManagedType.ArraySegment, JSTypeFlags.MemoryView, _, [_]) => failWithReason(null!), (KnownManagedType.ArraySegment, JSTypeFlags.MemoryView, [KnownManagedType.Byte], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.ArraySegment), MarshalerType.ArraySegment, [MarshalerType.Byte]), (KnownManagedType.ArraySegment, JSTypeFlags.MemoryView, [KnownManagedType.Int32], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.ArraySegment), MarshalerType.ArraySegment, [MarshalerType.Int32]), (KnownManagedType.ArraySegment, JSTypeFlags.MemoryView, [KnownManagedType.Double], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.ArraySegment), MarshalerType.ArraySegment, [MarshalerType.Double]), + (KnownManagedType.ArraySegment, JSTypeFlags.MemoryView, [KnownManagedType.Single], _) => resolved(new PrimitiveJSGenerator(info, context, MarshalerType.ArraySegment), MarshalerType.ArraySegment, [MarshalerType.Single]), (KnownManagedType.ArraySegment, JSTypeFlags.MemoryView, _, _) => failWithReason(SR.Format(SR.TypeNotSupportedName, info.ManagedType.FullTypeName)), diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSMarshalerType.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSMarshalerType.cs index 7a8eecf4cc2c18..7d794b99f9fe3d 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSMarshalerType.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSMarshalerType.cs @@ -462,6 +462,7 @@ internal static void CheckArray(JSMarshalerType underlyingType) if (underlying == MarshalerType.Byte || underlying == MarshalerType.Int32 || underlying == MarshalerType.Double + || underlying == MarshalerType.Single || underlying == MarshalerType.String || underlying == MarshalerType.Object || underlying == MarshalerType.JSObject @@ -475,6 +476,7 @@ internal static void CheckArraySegment(JSMarshalerType underlyingType) if (underlying == MarshalerType.Byte || underlying == MarshalerType.Int32 || underlying == MarshalerType.Double + || underlying == MarshalerType.Single ) return; throw new ArgumentException(SR.Format(SR.UnsupportedElementType, underlying), nameof(underlyingType)); } @@ -486,7 +488,6 @@ internal static void CheckTask(JSMarshalerType underlyingType) if (underlying == MarshalerType.Array || underlying == MarshalerType.ArraySegment || underlying == MarshalerType.Span - || underlying == MarshalerType.Task || underlying == MarshalerType.Action || underlying == MarshalerType.Function diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs index 31223d01d8a5f3..75011cff119b93 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs @@ -287,6 +287,11 @@ public void ToJS(object? value) int[] val = (int[])value; ToJS(val); } + else if (typeof(float[]) == type) + { + float[] val = (float[])value; + ToJS(val); + } else if (typeof(double[]) == type) { double[] val = (double[])value; diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Single.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Single.cs index f744a4e1baf9d0..4406dacc9499fc 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Single.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Single.cs @@ -77,5 +77,104 @@ public void ToJS(float? value) slot.Type = MarshalerType.None; } } + + /// + /// Implementation of the argument marshaling. + /// It's used by JSImport code generator and should not be used by developers in source code. + /// + /// The value to be marshaled. +#if !DEBUG + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public unsafe void ToManaged(out float[]? value) + { + if (slot.Type == MarshalerType.None) + { + value = null; + return; + } + value = new float[slot.Length]; + Marshal.Copy(slot.IntPtrValue, value, 0, slot.Length); + NativeMemory.Free((void*)slot.IntPtrValue); + } + + /// + /// Implementation of the argument marshaling. + /// It's used by JSImport code generator and should not be used by developers in source code. + /// + /// The value to be marshaled. +#if !DEBUG + [MethodImpl(MethodImplOptions.AggressiveInlining)] +#endif + public unsafe void ToJS(float[] value) + { + if (value == null) + { + slot.Type = MarshalerType.None; + return; + } + slot.Type = MarshalerType.Array; + slot.IntPtrValue = (IntPtr)NativeMemory.Alloc((nuint)(value.Length * sizeof(float))); + slot.Length = value.Length; + slot.ElementType = MarshalerType.Single; + Marshal.Copy(value, 0, slot.IntPtrValue, slot.Length); + } + + /// + /// Implementation of the argument marshaling. + /// It's used by JSImport code generator and should not be used by developers in source code. + /// + /// The value to be marshaled. + // this only supports array round-trip + public unsafe void ToManaged(out ArraySegment value) + { + var array = (float[])((GCHandle)slot.GCHandle).Target!; + var refPtr = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(array)); + int byteOffset = (int)(slot.IntPtrValue - (nint)refPtr); + value = new ArraySegment(array, byteOffset / sizeof(float), slot.Length); + } + + /// + /// Implementation of the argument marshaling. + /// It's used by JSImport code generator and should not be used by developers in source code. + /// + /// The value to be marshaled. + public unsafe void ToJS(ArraySegment value) + { + if (value.Array == null) + { + slot.Type = MarshalerType.None; + return; + } + slot.Type = MarshalerType.ArraySegment; + var ctx = ToJSContext; + slot.GCHandle = ctx.GetJSOwnedObjectGCHandle(value.Array, GCHandleType.Pinned); + var refPtr = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(value.Array)); + slot.IntPtrValue = refPtr + (value.Offset * sizeof(float)); + slot.Length = value.Count; + } + + /// + /// Implementation of the argument marshaling. + /// It's used by JSImport code generator and should not be used by developers in source code. + /// + /// The value to be marshaled. + public unsafe void ToManaged(out Span value) + { + value = new Span((void*)slot.IntPtrValue, slot.Length); + } + + /// + /// Implementation of the argument marshaling. + /// It's used by JSImport code generator and should not be used by developers in source code. + /// + /// caller is responsible for pinning. + /// The value to be marshaled. + public unsafe void ToJS(Span value) + { + slot.Length = value.Length; + slot.IntPtrValue = (IntPtr)Unsafe.AsPointer(ref value.GetPinnableReference()); + slot.Type = MarshalerType.Span; + } } } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index c064839d530677..b2d7f1a7cd0c86 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -263,6 +263,10 @@ internal static partial void Relaxed(string a1, Exception ex, [return: JSMarshalAs] internal static partial Span echo1_SpanOfDouble([JSMarshalAs] Span value, [JSMarshalAs] bool edit); + [JSImport("echo1view", "JavaScriptTestHelper")] + [return: JSMarshalAs] + internal static partial Span echo1_SpanOfSingle([JSMarshalAs] Span value, [JSMarshalAs] bool edit); + [JSImport("echo1view", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial ArraySegment echo1_ArraySegmentOfByte([JSMarshalAs] ArraySegment value, [JSMarshalAs] bool edit); From 3f215ae8f9b758ee39e78892e32b07ba1270c1d5 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Mon, 26 Jan 2026 03:53:53 +0100 Subject: [PATCH 02/13] update interop js for coreclr --- .../interop/marshal-to-cs.ts | 7 +++++++ .../interop/marshal-to-js.ts | 8 ++++++++ .../interop/marshaled-types.ts | 18 ++++++++++++------ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts index 78581e20e52082..e06731f8ab4adb 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts @@ -466,6 +466,11 @@ export function marshalArrayToCsImpl(arg: JSMarshalerArgument, value: Array const bufferOffset = fixupPointer(bufferPtr, 3); const targetView = dotnetApi.localHeapViewF64().subarray(bufferOffset, bufferOffset + length); targetView.set(value); + } else if (elementType == MarshalerType.Single) { + dotnetAssert.check(Array.isArray(value) || value instanceof Float32Array, "Value is not an Array or Float32Array"); + const bufferOffset = fixupPointer(bufferPtr, 1); + const targetView = dotnetApi.localHeapViewF32().subarray(bufferOffset, bufferOffset + length); + targetView.set(value); } else { throw new Error("not implemented"); } @@ -505,6 +510,8 @@ function checkViewType(elementType: MarshalerType, viewType: MemoryViewType) { dotnetAssert.check(MemoryViewType.Int32 == viewType, "Expected MemoryViewType.Int32"); } else if (elementType == MarshalerType.Double) { dotnetAssert.check(MemoryViewType.Double == viewType, "Expected MemoryViewType.Double"); + } else if (elementType == MarshalerType.Single) { + dotnetAssert.check(MemoryViewType.Single == viewType, "Expected MemoryViewType.Single"); } else { throw new Error(`NotImplementedException ${elementType} `); } diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts index 363ccc2843774c..84bc6da089783c 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts @@ -461,6 +461,10 @@ function _marshalArrayToJs_impl(arg: JSMarshalerArgument, elementType: Marshaler const bufferOffset = fixupPointer(bufferPtr, 3); const sourceView = dotnetApi.localHeapViewF64().subarray(bufferOffset, bufferOffset + length); result = sourceView.slice();//copy + } else if (elementType == MarshalerType.Single) { + const bufferOffset = fixupPointer(bufferPtr, 3); + const sourceView = dotnetApi.localHeapViewF32().subarray(bufferOffset, bufferOffset + length); + result = sourceView.slice();//copy } else { throw new Error(`NotImplementedException ${elementType}. ${jsinteropDoc}`); } @@ -480,6 +484,8 @@ function _marshalSpanToJs(arg: JSMarshalerArgument, elementType?: MarshalerType) result = new Span(bufferPtr, length, MemoryViewType.Int32); } else if (elementType == MarshalerType.Double) { result = new Span(bufferPtr, length, MemoryViewType.Double); + } else if (elementType == MarshalerType.Single) { + result = new Span(bufferPtr, length, MemoryViewType.Single); } else { throw new Error(`NotImplementedException ${elementType}. ${jsinteropDoc}`); } @@ -498,6 +504,8 @@ function _marshalArraySegmentToJs(arg: JSMarshalerArgument, elementType?: Marsha result = new ArraySegment(bufferPtr, length, MemoryViewType.Int32); } else if (elementType == MarshalerType.Double) { result = new ArraySegment(bufferPtr, length, MemoryViewType.Double); + } else if (elementType == MarshalerType.Single) { + result = new ArraySegment(bufferPtr, length, MemoryViewType.Single); } else { throw new Error(`NotImplementedException ${elementType}. ${jsinteropDoc}`); } diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshaled-types.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshaled-types.ts index 7b7e4511450065..b7f9dd98ad28a1 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshaled-types.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshaled-types.ts @@ -13,6 +13,7 @@ export const enum MemoryViewType { Byte = 0, Int32 = 1, Double = 2, + Single = 3, } abstract class MemoryView implements IMemoryView { @@ -25,12 +26,17 @@ abstract class MemoryView implements IMemoryView { _unsafe_create_view(): TypedArray { // this view must be short lived so that it doesn't fail after wasm memory growth // for that reason we also don't give the view out to end user and provide set/slice/copyTo API instead - const view = this._viewType == MemoryViewType.Byte ? new Uint8Array(dotnetApi.localHeapViewU8().buffer, this._pointer as any >>> 0, this._length) - : this._viewType == MemoryViewType.Int32 ? new Int32Array(dotnetApi.localHeapViewI32().buffer, this._pointer as any >>> 0, this._length) - : this._viewType == MemoryViewType.Double ? new Float64Array(dotnetApi.localHeapViewF64().buffer, this._pointer as any >>> 0, this._length) - : null; - if (!view) throw new Error("NotImplementedException"); - return view; + if (this._viewType == MemoryViewType.Byte) { + return new Uint8Array(dotnetApi.localHeapViewU8().buffer, this._pointer as any >>> 0, this._length); + } else if (this._viewType == MemoryViewType.Int32) { + return new Int32Array(dotnetApi.localHeapViewI32().buffer, this._pointer as any >>> 0, this._length); + } else if (this._viewType == MemoryViewType.Double) { + return new Float64Array(dotnetApi.localHeapViewF64().buffer, this._pointer as any >>> 0, this._length); + } else if (this._viewType == MemoryViewType.Single) { + return new Float32Array(dotnetApi.localHeapViewF32().buffer, this._pointer as any >>> 0, this._length); + } else { + throw new Error("NotImplementedException"); + } } set(source: TypedArray, targetOffset?: number): void { From c5d8fb52f8024dbdbfa917cdb731b4862cdb554f Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Mon, 26 Jan 2026 03:54:07 +0100 Subject: [PATCH 03/13] add span test --- .../InteropServices/JavaScript/JSImportTest.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index b862a970c4aa6b..9e5dc073537642 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs @@ -451,6 +451,23 @@ public unsafe void JsImportSpanOfDouble() Assert.Equal(actual[0], actual[1]); } + [Fact] + public unsafe void JsImportSpanOfSingle() + { + var expectedBytes = stackalloc float[] { 0, 1, -1, float.Pi, 42, float.MaxValue, float.MinValue, float.NaN, float.PositiveInfinity, float.NegativeInfinity }; + Span expected = new Span(expectedBytes, 10); + Assert.True(Unsafe.AsPointer(ref expected.GetPinnableReference()) == expectedBytes); + Span actual = JavaScriptTestHelper.echo1_SpanOfSingle(expected, false); + Assert.Equal(expected.Length, actual.Length); + Assert.NotEqual(expected[0], expected[1]); + Assert.Equal(expected.GetPinnableReference(), actual.GetPinnableReference()); + Assert.True(actual.SequenceCompareTo(expected) == 0); + Assert.Equal(expected.ToArray(), actual.ToArray()); + actual = JavaScriptTestHelper.echo1_SpanOfSingle(expected, true); + Assert.Equal(expected[0], expected[1]); + Assert.Equal(actual[0], actual[1]); + } + [Fact] public unsafe void JsImportArraySegmentOfByte() { From 66c21252a4ad27f55fb4dbc2ced5e3a5fc066394 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Mon, 26 Jan 2026 22:30:03 +0100 Subject: [PATCH 04/13] float array and arraysegment cs-js and cs-js marshalling + tests --- .../JavaScript/JSImportTest.cs | 34 ++++++++++++++++--- .../JavaScript/JSInteropTestBase.cs | 7 ++++ .../JavaScript/JavaScriptTestHelper.cs | 12 +++++++ .../interop/marshal-to-cs.ts | 2 +- .../interop/marshal-to-js.ts | 2 +- .../interop/marshal.ts | 19 ++++++----- 6 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index 9e5dc073537642..a5c40656d3a97d 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs @@ -292,6 +292,18 @@ public unsafe void JsImportDoubleArray(double[]? expected) Assert.Equal(expected[i], actualI); } } + [Theory] + [MemberData(nameof(MarshalSingleArrayCases))] + public unsafe void JsImportSingleArray(float[]? expected) + { + var actual = JavaScriptTestHelper.echo1_SingleArray(expected); + Assert.Equal(expected, actual); + if (expected != null) for (int i = 0; i < expected.Length; i++) + { + var actualI = JavaScriptTestHelper.store_SingleArray(expected, i); + Assert.Equal(expected[i], actualI); + } + } [Theory] [MemberData(nameof(MarshalStringArrayCases))] @@ -485,8 +497,8 @@ public unsafe void JsImportArraySegmentOfByte() [Fact] public unsafe void JsImportArraySegmentOfInt32() { - var expectedBytes = new int[] { 88, 0, 1, -2, 42, int.MaxValue, int.MinValue }; - ArraySegment expected = new ArraySegment(expectedBytes, 1, 6); + var expectedInts = new int[] { 88, 0, 1, -2, 42, int.MaxValue, int.MinValue }; + ArraySegment expected = new ArraySegment(expectedInts, 1, 6); ArraySegment actual = JavaScriptTestHelper.echo1_ArraySegmentOfInt32(expected, false); Assert.Equal(expected.Count, actual.Count); Assert.NotEqual(expected[0], expected[1]); @@ -499,8 +511,8 @@ public unsafe void JsImportArraySegmentOfInt32() [Fact] public unsafe void JsImportArraySegmentOfDouble() { - var expectedBytes = new double[] { 88.88, 0, 1, -1, double.Pi, 42, double.MaxValue, double.MinValue, double.NaN, double.PositiveInfinity, double.NegativeInfinity }; - ArraySegment expected = new ArraySegment(expectedBytes, 1, 10); + var expectedDoubles = new double[] { 88.88, 0, 1, -1, double.Pi, 42, double.MaxValue, double.MinValue, double.NaN, double.PositiveInfinity, double.NegativeInfinity }; + ArraySegment expected = new ArraySegment(expectedDoubles, 1, 10); ArraySegment actual = JavaScriptTestHelper.echo1_ArraySegmentOfDouble(expected, false); Assert.Equal(expected.Count, actual.Count); Assert.NotEqual(expected[0], expected[1]); @@ -510,6 +522,20 @@ public unsafe void JsImportArraySegmentOfDouble() Assert.Equal(actual[0], actual[1]); } + [Fact] + public unsafe void JsImportArraySegmentOfSingle() + { + var expectedFloats = new float[] { 88.88F, 0, 1, -1, float.Pi, 42, float.MaxValue, float.MinValue, float.NaN, float.PositiveInfinity, float.NegativeInfinity }; + ArraySegment expected = new ArraySegment(expectedFloats, 1, 10); + ArraySegment actual = JavaScriptTestHelper.echo1_ArraySegmentOfSingle(expected, false); + Assert.Equal(expected.Count, actual.Count); + Assert.NotEqual(expected[0], expected[1]); + Assert.Equal(expected.Array, actual.Array); + actual = JavaScriptTestHelper.echo1_ArraySegmentOfSingle(expected, true); + Assert.Equal(expected[0], expected[1]); + Assert.Equal(actual[0], actual[1]); + } + #endregion #region Boolean diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSInteropTestBase.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSInteropTestBase.cs index 288ad2b227d75e..c67830ced89210 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSInteropTestBase.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSInteropTestBase.cs @@ -153,6 +153,13 @@ public static IEnumerable MarshalDoubleArrayCases() yield return new object[] { null }; } + public static IEnumerable MarshalSingleArrayCases() + { + yield return new object[] { new float[] { 1, 2, 3, float.MaxValue, float.MinValue, float.Pi, float.NegativeInfinity, float.PositiveInfinity, float.NaN } }; + yield return new object[] { new float[] { } }; + yield return new object[] { null }; + } + public static IEnumerable MarshalStringArrayCases() { yield return new object[] { new string[] { "\u0050\u0159\u00ed\u006c\u0069\u0161", "\u017e\u006c\u0075\u0165\u006f\u0075\u010d\u006b\u00fd" } }; diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index b2d7f1a7cd0c86..59c14419382174 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -223,6 +223,14 @@ internal static partial void Relaxed(string a1, Exception ex, [return: JSMarshalAs] internal static partial double? store_DoubleArray([JSMarshalAs>] double[]? value, [JSMarshalAs] int index); + [JSImport("echo1", "JavaScriptTestHelper")] + [return: JSMarshalAs>] + internal static partial float[]? echo1_SingleArray([JSMarshalAs>] float[]? value); + + [JSImport("storeAt", "JavaScriptTestHelper")] + [return: JSMarshalAs] + internal static partial float? store_SingleArray([JSMarshalAs>] float[]? value, [JSMarshalAs] int index); + [JSImport("echo1", "JavaScriptTestHelper")] [return: JSMarshalAs>] internal static partial string[]? echo1_StringArray([JSMarshalAs>] string[]? value); @@ -279,6 +287,10 @@ internal static partial void Relaxed(string a1, Exception ex, [return: JSMarshalAs] internal static partial ArraySegment echo1_ArraySegmentOfDouble([JSMarshalAs] ArraySegment value, [JSMarshalAs] bool edit); + [JSImport("echo1view", "JavaScriptTestHelper")] + [return: JSMarshalAs] + internal static partial ArraySegment echo1_ArraySegmentOfSingle([JSMarshalAs] ArraySegment value, [JSMarshalAs] bool edit); + #endregion #region Int32 diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts index e06731f8ab4adb..7dbee3c4c45695 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts @@ -468,7 +468,7 @@ export function marshalArrayToCsImpl(arg: JSMarshalerArgument, value: Array targetView.set(value); } else if (elementType == MarshalerType.Single) { dotnetAssert.check(Array.isArray(value) || value instanceof Float32Array, "Value is not an Array or Float32Array"); - const bufferOffset = fixupPointer(bufferPtr, 1); + const bufferOffset = fixupPointer(bufferPtr, 2); const targetView = dotnetApi.localHeapViewF32().subarray(bufferOffset, bufferOffset + length); targetView.set(value); } else { diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts index 84bc6da089783c..34cf6c7c597d1f 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-js.ts @@ -462,7 +462,7 @@ function _marshalArrayToJs_impl(arg: JSMarshalerArgument, elementType: Marshaler const sourceView = dotnetApi.localHeapViewF64().subarray(bufferOffset, bufferOffset + length); result = sourceView.slice();//copy } else if (elementType == MarshalerType.Single) { - const bufferOffset = fixupPointer(bufferPtr, 3); + const bufferOffset = fixupPointer(bufferPtr, 2); const sourceView = dotnetApi.localHeapViewF32().subarray(bufferOffset, bufferOffset + length); result = sourceView.slice();//copy } else { diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts index eff31c4d305274..dd5825523c4f41 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts @@ -338,14 +338,17 @@ export function getSignatureMarshaler(signature: JSFunctionSignature, index: num return dotnetApi.getHeapU32(sig + JSBindingHeaderOffsets.ImportHandle); } +const elementSizeMap = new Map([ + [MarshalerType.Byte, 1], + [MarshalerType.Int32, 4], + [MarshalerType.Int52, 8], + [MarshalerType.Single, 4], + [MarshalerType.Double, 8], + [MarshalerType.String, JavaScriptMarshalerArgSize], + [MarshalerType.Object, JavaScriptMarshalerArgSize], + [MarshalerType.JSObject, JavaScriptMarshalerArgSize], +]); export function arrayElementSize(elementType: MarshalerType): number { - return elementType == MarshalerType.Byte ? 1 - : elementType == MarshalerType.Int32 ? 4 - : elementType == MarshalerType.Int52 ? 8 - : elementType == MarshalerType.Double ? 8 - : elementType == MarshalerType.String ? JavaScriptMarshalerArgSize - : elementType == MarshalerType.Object ? JavaScriptMarshalerArgSize - : elementType == MarshalerType.JSObject ? JavaScriptMarshalerArgSize - : -1; + return elementSizeMap.get(elementType) || -1; } From f07af2dfca9de84dbcc1a49225c7375a59409149 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Tue, 27 Jan 2026 20:36:42 +0100 Subject: [PATCH 05/13] add export tests --- .../JavaScript/JSExportTest.cs | 36 ++++++++++++++++ .../JavaScript/JavaScriptTestHelper.cs | 43 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs index f6e7e99abd310b..187e925ea6a8b5 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs @@ -253,6 +253,42 @@ public void JsExportString(string value) "string"); } + [Fact] + public void JsExportArraySegmentOfDouble() + { + ArraySegment segment = new ArraySegment([1, 2, 3, double.MaxValue, double.MinValue, double.Pi, double.NegativeInfinity, double.PositiveInfinity, double.NaN]); + ArraySegment res = JavaScriptTestHelper.invoke1_ArraySegmentOfDouble(segment, nameof(JavaScriptTestHelper.EchoArraySegmentOfDouble)); + Assert.Equal(segment.Count, res.Count); + Assert.Equal(segment.Array, res.Array); + } + + [Fact] + public void JsExportArraySegmentOfSingle() + { + ArraySegment segment = new ArraySegment([1, 2, 3, float.MaxValue, float.MinValue, float.Pi, float.NegativeInfinity, float.PositiveInfinity, float.NaN]); + ArraySegment res = JavaScriptTestHelper.invoke1_ArraySegmentOfSingle(segment, nameof(JavaScriptTestHelper.EchoArraySegmentOfSingle)); + Assert.Equal(segment.Count, res.Count); + Assert.Equal(segment.Array, res.Array); + } + + [Theory] + [MemberData(nameof(MarshalDoubleArrayCases))] + public void JsExportSpanOfDouble(double[] value) + { + Span span = new Span(value); + Span res = JavaScriptTestHelper.invoke1_SpanDouble(span, nameof(JavaScriptTestHelper.EchoSpanDouble)); + Assert.Equal(value, res); + } + + [Theory] + [MemberData(nameof(MarshalSingleArrayCases))] + public void JsExportSpanOfSingle(float[] value) + { + Span span = new Span(value); + Span res = JavaScriptTestHelper.invoke1_SpanSingle(span, nameof(JavaScriptTestHelper.EchoSpanSingle)); + Assert.Equal(value, res); + } + [Fact] public void JsExportStringNoNs() { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index 59c14419382174..3049f904acdc48 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -291,6 +291,49 @@ internal static partial void Relaxed(string a1, Exception ex, [return: JSMarshalAs] internal static partial ArraySegment echo1_ArraySegmentOfSingle([JSMarshalAs] ArraySegment value, [JSMarshalAs] bool edit); + [JSImport("invoke1", "JavaScriptTestHelper")] + [return: JSMarshalAs] + internal static partial ArraySegment invoke1_ArraySegmentOfSingle([JSMarshalAs] ArraySegment value, [JSMarshalAs] string name); + + [JSExport] + [return: JSMarshalAs] + internal static ArraySegment EchoArraySegmentOfSingle([JSMarshalAs] ArraySegment value) + { + return value; + } + + [JSImport("invoke1", "JavaScriptTestHelper")] + [return: JSMarshalAs] + internal static partial ArraySegment invoke1_ArraySegmentOfDouble([JSMarshalAs] ArraySegment value, [JSMarshalAs] string name); + + [JSExport] + [return: JSMarshalAs] + internal static ArraySegment EchoArraySegmentOfDouble([JSMarshalAs] ArraySegment value) + { + return value; + } + + [JSImport("invoke1", "JavaScriptTestHelper")] + [return: JSMarshalAs] + internal static partial Span invoke1_SpanSingle([JSMarshalAs] Span value, [JSMarshalAs] string name); + + [JSExport] + [return: JSMarshalAs] + internal static Span EchoSpanSingle([JSMarshalAs] Span value) + { + return value; + } + + [JSImport("invoke1", "JavaScriptTestHelper")] + [return: JSMarshalAs] + internal static partial Span invoke1_SpanDouble([JSMarshalAs] Span value, [JSMarshalAs] string name); + + [JSExport] + [return: JSMarshalAs] + internal static Span EchoSpanDouble([JSMarshalAs] Span value) + { + return value; + } #endregion #region Int32 From e349ba7b150cfc76c47be7894e7cb4c864b784a8 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Tue, 27 Jan 2026 22:10:26 +0100 Subject: [PATCH 06/13] update ref --- .../ref/System.Runtime.InteropServices.JavaScript.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs index d13c24cf0b9311..c425a04590b810 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs @@ -243,6 +243,8 @@ public struct JSMarshalerArgument public void ToJS(float value) { throw null; } public void ToManaged(out float? value) { throw null; } public void ToJS(float? value) { throw null; } + public void ToManaged(out float[]? value) { throw null; } + public void ToJS(float[]? value) { throw null; } public void ToManaged(out double value) { throw null; } public void ToJS(double value) { throw null; } public void ToManaged(out double? value) { throw null; } @@ -309,4 +311,8 @@ public struct JSMarshalerArgument public void ToJS(ArraySegment value) { throw null; } public void ToManaged(out ArraySegment value) { throw null; } public void ToJS(ArraySegment value) { throw null; } + public void ToManaged(out Span value) { throw null; } + public void ToJS(Span value) { throw null; } + public void ToManaged(out ArraySegment value) { throw null; } + public void ToJS(ArraySegment value) { throw null; } } From ca03151b5aeedc19d97030ec6330f6034b6ed8d9 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Tue, 27 Jan 2026 22:30:28 +0100 Subject: [PATCH 07/13] impl mono side --- src/mono/browser/runtime/marshal-to-cs.ts | 9 ++++- src/mono/browser/runtime/marshal-to-js.ts | 10 +++++- src/mono/browser/runtime/marshal.ts | 42 +++++++++++++---------- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/mono/browser/runtime/marshal-to-cs.ts b/src/mono/browser/runtime/marshal-to-cs.ts index 27824796fac699..ed0b13fa5760d5 100644 --- a/src/mono/browser/runtime/marshal-to-cs.ts +++ b/src/mono/browser/runtime/marshal-to-cs.ts @@ -18,7 +18,7 @@ import { set_arg_element_type, ManagedObject, JavaScriptMarshalerArgSize, proxy_debug_symbol, get_arg_gc_handle, get_arg_type, set_arg_proxy_context, get_arg_intptr } from "./marshal"; import { get_marshaler_to_js_by_type } from "./marshal-to-js"; -import { _zero_region, fixupPointer, localHeapViewF64, localHeapViewI32, localHeapViewU8, malloc } from "./memory"; +import { _zero_region, fixupPointer, localHeapViewF32, localHeapViewF64, localHeapViewI32, localHeapViewU8, malloc } from "./memory"; import { stringToMonoStringRoot, stringToUTF16 } from "./strings"; import { JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToCs, MarshalerType } from "./types/internal"; import { TypedArray } from "./types/emscripten"; @@ -502,6 +502,11 @@ export function marshal_array_to_cs_impl (arg: JSMarshalerArgument, value: Array const bufferOffset = fixupPointer(buffer_ptr, 3); const targetView = localHeapViewF64().subarray(bufferOffset, bufferOffset + length); targetView.set(value); + } else if (element_type == MarshalerType.Single) { + mono_check(Array.isArray(value) || value instanceof Float32Array, "Value is not an Array or Float32Array"); + const bufferOffset = fixupPointer(buffer_ptr, 1); + const targetView = localHeapViewF32().subarray(bufferOffset, bufferOffset + length); + targetView.set(value); } else { throw new Error("not implemented"); } @@ -541,6 +546,8 @@ function checkViewType (element_type: MarshalerType, viewType: MemoryViewType) { mono_check(MemoryViewType.Int32 == viewType, "Expected MemoryViewType.Int32"); } else if (element_type == MarshalerType.Double) { mono_check(MemoryViewType.Double == viewType, "Expected MemoryViewType.Double"); + } else if (element_type == MarshalerType.Single) { + mono_check(MemoryViewType.Single == viewType, "Expected MemoryViewType.Single"); } else { throw new Error(`NotImplementedException ${element_type} `); } diff --git a/src/mono/browser/runtime/marshal-to-js.ts b/src/mono/browser/runtime/marshal-to-js.ts index 7746a98a16843d..0036d4a0ef33cf 100644 --- a/src/mono/browser/runtime/marshal-to-js.ts +++ b/src/mono/browser/runtime/marshal-to-js.ts @@ -20,7 +20,7 @@ import { monoStringToString, utf16ToString } from "./strings"; import { GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToJs, MarshalerType, JSHandle } from "./types/internal"; import { TypedArray } from "./types/emscripten"; import { get_marshaler_to_cs_by_type, jsinteropDoc, marshal_exception_to_cs } from "./marshal-to-cs"; -import { fixupPointer, free, localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory"; +import { fixupPointer, free, localHeapViewF32, localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory"; import { call_delegate } from "./managed-exports"; import { mono_log_debug } from "./logging"; import { invoke_later_when_on_ui_thread_async } from "./invoke-js"; @@ -536,6 +536,10 @@ function _marshal_array_to_js_impl (arg: JSMarshalerArgument, element_type: Mars const bufferOffset = fixupPointer(buffer_ptr, 3); const sourceView = localHeapViewF64().subarray(bufferOffset, bufferOffset + length); result = sourceView.slice();//copy + } else if (element_type == MarshalerType.Single) { + const bufferOffset = fixupPointer(buffer_ptr, 2); + const sourceView = localHeapViewF32().subarray(bufferOffset, bufferOffset + length); + result = sourceView.slice();//copy } else { throw new Error(`NotImplementedException ${element_type}. ${jsinteropDoc}`); } @@ -555,6 +559,8 @@ function _marshal_span_to_js (arg: JSMarshalerArgument, element_type?: Marshaler result = new Span(buffer_ptr, length, MemoryViewType.Int32); } else if (element_type == MarshalerType.Double) { result = new Span(buffer_ptr, length, MemoryViewType.Double); + } else if (element_type == MarshalerType.Single) { + result = new Span(buffer_ptr, length, MemoryViewType.Single); } else { throw new Error(`NotImplementedException ${element_type}. ${jsinteropDoc}`); } @@ -573,6 +579,8 @@ function _marshal_array_segment_to_js (arg: JSMarshalerArgument, element_type?: result = new ArraySegment(buffer_ptr, length, MemoryViewType.Int32); } else if (element_type == MarshalerType.Double) { result = new ArraySegment(buffer_ptr, length, MemoryViewType.Double); + } else if (element_type == MarshalerType.Single) { + result = new ArraySegment(buffer_ptr, length, MemoryViewType.Single); } else { throw new Error(`NotImplementedException ${element_type}. ${jsinteropDoc}`); } diff --git a/src/mono/browser/runtime/marshal.ts b/src/mono/browser/runtime/marshal.ts index e369da6418e9cd..1d9f1e83542818 100644 --- a/src/mono/browser/runtime/marshal.ts +++ b/src/mono/browser/runtime/marshal.ts @@ -5,7 +5,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads"; import { js_owned_gc_handle_symbol, teardown_managed_proxy } from "./gc-handles"; import { Module, loaderHelpers, mono_assert, runtimeHelpers } from "./globals"; -import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8, localHeapViewF64, localHeapViewI32, localHeapViewU8, _zero_region, forceThreadMemoryViewRefresh, fixupPointer, setB8, getB8 } from "./memory"; +import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8, localHeapViewF32, localHeapViewF64, localHeapViewI32, localHeapViewU8, _zero_region, forceThreadMemoryViewRefresh, fixupPointer, setB8, getB8 } from "./memory"; import { mono_wasm_new_external_root } from "./roots"; import { GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot, MarshalerType, PThreadPtr, PThreadPtrNull, VoidPtrNull } from "./types/internal"; import { TypedArray, VoidPtr } from "./types/emscripten"; @@ -448,22 +448,23 @@ export function get_signature_marshaler (signature: JSFunctionSignature, index: return getU32(sig + JSBindingHeaderOffsets.ImportHandle); } - -export function array_element_size (element_type: MarshalerType): number { - return element_type == MarshalerType.Byte ? 1 - : element_type == MarshalerType.Int32 ? 4 - : element_type == MarshalerType.Int52 ? 8 - : element_type == MarshalerType.Double ? 8 - : element_type == MarshalerType.String ? JavaScriptMarshalerArgSize - : element_type == MarshalerType.Object ? JavaScriptMarshalerArgSize - : element_type == MarshalerType.JSObject ? JavaScriptMarshalerArgSize - : -1; +export function array_element_size (t: MarshalerType): number { + if (t == MarshalerType.Byte) return 1; + if (t == MarshalerType.Int32) return 4; + if (t == MarshalerType.Int52) return 8; + if (t == MarshalerType.Single) return 4; + if (t == MarshalerType.Double) return 8; + if (t == MarshalerType.String) return JavaScriptMarshalerArgSize; + if (t == MarshalerType.Object) return JavaScriptMarshalerArgSize; + if (t == MarshalerType.JSObject) return JavaScriptMarshalerArgSize; + return -1; } export const enum MemoryViewType { Byte = 0, Int32 = 1, Double = 2, + Single = 3, } abstract class MemoryView implements IMemoryView { @@ -475,14 +476,17 @@ abstract class MemoryView implements IMemoryView { abstract get isDisposed(): boolean; _unsafe_create_view (): TypedArray { - // this view must be short lived so that it doesn't fail after wasm memory growth - // for that reason we also don't give the view out to end user and provide set/slice/copyTo API instead - const view = this._viewType == MemoryViewType.Byte ? new Uint8Array(localHeapViewU8().buffer, this._pointer, this._length) - : this._viewType == MemoryViewType.Int32 ? new Int32Array(localHeapViewI32().buffer, this._pointer, this._length) - : this._viewType == MemoryViewType.Double ? new Float64Array(localHeapViewF64().buffer, this._pointer, this._length) - : null; - if (!view) throw new Error("NotImplementedException"); - return view; + if (this._viewType == MemoryViewType.Byte) { + return new Uint8Array(localHeapViewU8().buffer, this._pointer as any, this._length); + } else if (this._viewType == MemoryViewType.Int32) { + return new Int32Array(localHeapViewI32().buffer, this._pointer as any, this._length); + } else if (this._viewType == MemoryViewType.Double) { + return new Float64Array(localHeapViewF64().buffer, this._pointer as any, this._length); + } else if (this._viewType == MemoryViewType.Single) { + return new Float32Array(localHeapViewF32().buffer, this._pointer as any, this._length); + } else { + throw new Error("NotImplementedException"); + } } set (source: TypedArray, targetOffset?: number): void { From 002250e11c47300d77e755a6911a1ac64600a03e Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Tue, 27 Jan 2026 22:36:47 +0100 Subject: [PATCH 08/13] pointer offset 4bytes --- src/mono/browser/runtime/marshal-to-cs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/marshal-to-cs.ts b/src/mono/browser/runtime/marshal-to-cs.ts index ed0b13fa5760d5..e76659a3d96305 100644 --- a/src/mono/browser/runtime/marshal-to-cs.ts +++ b/src/mono/browser/runtime/marshal-to-cs.ts @@ -504,7 +504,7 @@ export function marshal_array_to_cs_impl (arg: JSMarshalerArgument, value: Array targetView.set(value); } else if (element_type == MarshalerType.Single) { mono_check(Array.isArray(value) || value instanceof Float32Array, "Value is not an Array or Float32Array"); - const bufferOffset = fixupPointer(buffer_ptr, 1); + const bufferOffset = fixupPointer(buffer_ptr, 2); const targetView = localHeapViewF32().subarray(bufferOffset, bufferOffset + length); targetView.set(value); } else { From 0f7ede3b008508fe4c0c82a69293132c60a1f095 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Wed, 28 Jan 2026 00:56:53 +0100 Subject: [PATCH 09/13] add float handling to ToManaged --- .../Marshaling/JSMarshalerArgument.Object.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs index 75011cff119b93..bc1c1b50a8215a 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs @@ -41,6 +41,11 @@ public void ToManaged(out object? value) ToManaged(out double v); value = v; } + else if (slot.Type == MarshalerType.Single) + { + ToManaged(out float v); + value = v; + } else if (slot.Type == MarshalerType.JSObject) { ToManaged(out JSObject? val); @@ -78,6 +83,11 @@ public void ToManaged(out object? value) ToManaged(out double[]? val); value = val; } + else if (slot.ElementType == MarshalerType.Single) + { + ToManaged(out float[]? val); + value = val; + } else if (slot.ElementType == MarshalerType.Int32) { ToManaged(out int[]? val); From 561786ca3a55402d2313bf074804e417671ab6df Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Wed, 28 Jan 2026 00:59:55 +0100 Subject: [PATCH 10/13] alloc free elem size --- .../interop/marshal.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts index dd5825523c4f41..2ee3614d241a4b 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts @@ -338,17 +338,15 @@ export function getSignatureMarshaler(signature: JSFunctionSignature, index: num return dotnetApi.getHeapU32(sig + JSBindingHeaderOffsets.ImportHandle); } -const elementSizeMap = new Map([ - [MarshalerType.Byte, 1], - [MarshalerType.Int32, 4], - [MarshalerType.Int52, 8], - [MarshalerType.Single, 4], - [MarshalerType.Double, 8], - [MarshalerType.String, JavaScriptMarshalerArgSize], - [MarshalerType.Object, JavaScriptMarshalerArgSize], - [MarshalerType.JSObject, JavaScriptMarshalerArgSize], -]); export function arrayElementSize(elementType: MarshalerType): number { - return elementSizeMap.get(elementType) || -1; + if (elementType == MarshalerType.Byte) return 1; + if (elementType == MarshalerType.Int32) return 4; + if (elementType == MarshalerType.Int52) return 8; + if (elementType == MarshalerType.Single) return 4; + if (elementType == MarshalerType.Double) return 8; + if (elementType == MarshalerType.String) return JavaScriptMarshalerArgSize; + if (elementType == MarshalerType.Object) return JavaScriptMarshalerArgSize; + if (elementType == MarshalerType.JSObject) return JavaScriptMarshalerArgSize; + return -1; } From 690501b57760ba39d557fc98155b290b7a73b12d Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Fri, 30 Jan 2026 23:39:07 +0100 Subject: [PATCH 11/13] Update src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Runtime/InteropServices/JavaScript/JSImportTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index 08d82c2ae785da..4cbd1ac2403ea9 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs @@ -524,9 +524,9 @@ public unsafe void JsImportSpanOfDouble() [Fact] public unsafe void JsImportSpanOfSingle() { - var expectedBytes = stackalloc float[] { 0, 1, -1, float.Pi, 42, float.MaxValue, float.MinValue, float.NaN, float.PositiveInfinity, float.NegativeInfinity }; - Span expected = new Span(expectedBytes, 10); - Assert.True(Unsafe.AsPointer(ref expected.GetPinnableReference()) == expectedBytes); + var expectedFloats = stackalloc float[] { 0, 1, -1, float.Pi, 42, float.MaxValue, float.MinValue, float.NaN, float.PositiveInfinity, float.NegativeInfinity }; + Span expected = new Span(expectedFloats, 10); + Assert.True(Unsafe.AsPointer(ref expected.GetPinnableReference()) == expectedFloats); Span actual = JavaScriptTestHelper.echo1_SpanOfSingle(expected, false); Assert.Equal(expected.Length, actual.Length); Assert.NotEqual(expected[0], expected[1]); From 31a3694c40b685dff7dbed6f74cb4128f5e72818 Mon Sep 17 00:00:00 2001 From: Marc Zwart Date: Sat, 31 Jan 2026 00:28:53 +0100 Subject: [PATCH 12/13] add tests for float[] and double[] without jsmarshalas --- .../JavaScript/JSImportTest.cs | 27 +++++++++++++++++++ .../JavaScript/JavaScriptTestHelper.cs | 11 ++++++++ 2 files changed, 38 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index 4cbd1ac2403ea9..2a8cbc1b8fe006 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs @@ -350,6 +350,20 @@ public unsafe void JsImportDoubleArray(double[]? expected) Assert.Equal(expected[i], actualI); } } + + [Theory] + [MemberData(nameof(MarshalDoubleArrayCases))] + public unsafe void JsImportDoubleArray_NoAttributes(double[]? expected) + { + var actual = JavaScriptTestHelper.echo1_DoubleArray_NoAttributes(expected); + Assert.Equal(expected, actual); + if (expected != null) for (int i = 0; i < expected.Length; i++) + { + var actualI = JavaScriptTestHelper.store_DoubleArray_NoAttributes(expected, i); + Assert.Equal(expected[i], actualI); + } + } + [Theory] [MemberData(nameof(MarshalSingleArrayCases))] public unsafe void JsImportSingleArray(float[]? expected) @@ -363,6 +377,19 @@ public unsafe void JsImportSingleArray(float[]? expected) } } + [Theory] + [MemberData(nameof(MarshalSingleArrayCases))] + public unsafe void JsImportSingleArray_NoAttributes(float[]? expected) + { + var actual = JavaScriptTestHelper.echo1_SingleArray_NoAttributes(expected); + Assert.Equal(expected, actual); + if (expected != null) for (int i = 0; i < expected.Length; i++) + { + var actualI = JavaScriptTestHelper.store_SingleArray_NoAttributes(expected, i); + Assert.Equal(expected[i], actualI); + } + } + [Theory] [MemberData(nameof(MarshalStringArrayCases))] public unsafe void JsImportStringArray(string[]? expected) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index aa2b6c03324a57..d1fffe5517452d 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -218,19 +218,30 @@ internal static partial void Relaxed(string a1, Exception ex, [JSImport("echo1", "JavaScriptTestHelper")] [return: JSMarshalAs>] internal static partial double[]? echo1_DoubleArray([JSMarshalAs>] double[]? value); + [JSImport("echo1", "JavaScriptTestHelper")] + internal static partial double[]? echo1_DoubleArray_NoAttributes(double[]? value); [JSImport("storeAt", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial double? store_DoubleArray([JSMarshalAs>] double[]? value, [JSMarshalAs] int index); + [JSImport("storeAt", "JavaScriptTestHelper")] + internal static partial double? store_DoubleArray_NoAttributes(double[]? value, int index); + [JSImport("echo1", "JavaScriptTestHelper")] [return: JSMarshalAs>] internal static partial float[]? echo1_SingleArray([JSMarshalAs>] float[]? value); + [JSImport("echo1", "JavaScriptTestHelper")] + internal static partial float[]? echo1_SingleArray_NoAttributes(float[]? value); + [JSImport("storeAt", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial float? store_SingleArray([JSMarshalAs>] float[]? value, [JSMarshalAs] int index); + [JSImport("storeAt", "JavaScriptTestHelper")] + internal static partial float? store_SingleArray_NoAttributes(float[]? value, int index); + [JSImport("echo1", "JavaScriptTestHelper")] [return: JSMarshalAs>] internal static partial string[]? echo1_StringArray([JSMarshalAs>] string[]? value); From 92dd1f2c7bb5e7c9ab75e175092fbd4f0aa617d7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 19 Feb 2026 15:30:12 +0100 Subject: [PATCH 13/13] - JSImportGenerator.UnitTest - minor improvements --- .../JSImportGenerator/JSGeneratorFactory.cs | 1 + ...stem.Runtime.InteropServices.JavaScript.cs | 4 +-- .../CodeSnippets.cs | 11 ++++--- .../JSImportGenerator.UnitTest/Compiles.cs | 31 +++++++++++-------- .../tests/JSImportGenerator.UnitTest/Fails.cs | 1 + src/mono/browser/runtime/marshal-to-cs.ts | 3 +- .../interop/marshal-to-cs.ts | 3 +- 7 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs index ff9dc7a68fbbd2..9ad243bfe29ede 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs @@ -260,6 +260,7 @@ private static ResolvedGeneratorAndType Create(TypePositionInfo info, StubCodeCo (KnownManagedType.ArraySegment, JSTypeFlags.Missing, [KnownManagedType.Byte], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), (KnownManagedType.ArraySegment, JSTypeFlags.Missing, [KnownManagedType.Int32], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), (KnownManagedType.ArraySegment, JSTypeFlags.Missing, [KnownManagedType.Double], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), + (KnownManagedType.ArraySegment, JSTypeFlags.Missing, [KnownManagedType.Single], _) => failWithReason(SR.Format(SR.UseJSMarshalAsAttribute, info.ManagedType.FullTypeName)), // function + action (KnownManagedType.Function or KnownManagedType.Action, JSTypeFlags.Function, var argTypes, var argJSTypes) when argTypes.Length != argJSTypes.Length diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs index c425a04590b810..6e663acd3207e3 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/ref/System.Runtime.InteropServices.JavaScript.cs @@ -307,12 +307,12 @@ public struct JSMarshalerArgument public void ToJS(Span value) { throw null; } public void ToManaged(out Span value) { throw null; } public void ToJS(Span value) { throw null; } + public void ToManaged(out Span value) { throw null; } + public void ToJS(Span value) { throw null; } public void ToManaged(out ArraySegment value) { throw null; } public void ToJS(ArraySegment value) { throw null; } public void ToManaged(out ArraySegment value) { throw null; } public void ToJS(ArraySegment value) { throw null; } - public void ToManaged(out Span value) { throw null; } - public void ToJS(Span value) { throw null; } public void ToManaged(out ArraySegment value) { throw null; } public void ToJS(ArraySegment value) { throw null; } } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/CodeSnippets.cs index 3e4cb0f6dcfd55..b5c9fbd854a757 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/CodeSnippets.cs @@ -28,7 +28,7 @@ internal static partial void Relaxed( Task ta5, Task ta7, JSObject jso, - string[] aa1, byte[] aab, double[] aad, int[] aai + string[] aa1, byte[] aab, double[] aad, float[] aaf, int[] aai ); } """; @@ -56,7 +56,8 @@ internal static partial void Annotated( [JSMarshalAs>] Task a12, [JSMarshalAs>] Task a13, [JSMarshalAs>] Task a14, - [JSMarshalAs>] Task a15 + [JSMarshalAs>] Task a15, + [JSMarshalAs] ArraySegment a16 ); } """; @@ -84,7 +85,8 @@ internal static void AnnotatedExport( [JSMarshalAs>] Task a12, [JSMarshalAs>] Task a13, [JSMarshalAs>] Task a14, - [JSMarshalAs>] Task a15 + [JSMarshalAs>] Task a15, + [JSMarshalAs] ArraySegment a16 ) {} } @@ -113,7 +115,8 @@ internal static partial void Missing( Task a12, Task a13, Task a14, - Task a15 + Task a15, + ArraySegment a16 ); } """; diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Compiles.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Compiles.cs index 9005db7ca21b75..0d3d91626e8d94 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Compiles.cs @@ -67,11 +67,11 @@ public async Task ValidateGeneratedSourceOutput_AllAnnotatedParameters() unsafe partial class Basic { [global::System.Diagnostics.DebuggerNonUserCode] - internal static partial void Annotated(object a1, long a2, long a3, global::System.Action a4, global::System.Func a5, global::System.Span a6, global::System.ArraySegment a7, global::System.Threading.Tasks.Task a8, object[] a9, global::System.DateTime a10, global::System.DateTimeOffset a11, global::System.Threading.Tasks.Task a12, global::System.Threading.Tasks.Task a13, global::System.Threading.Tasks.Task a14, global::System.Threading.Tasks.Task a15) + internal static partial void Annotated(object a1, long a2, long a3, global::System.Action a4, global::System.Func a5, global::System.Span a6, global::System.ArraySegment a7, global::System.Threading.Tasks.Task a8, object[] a9, global::System.DateTime a10, global::System.DateTimeOffset a11, global::System.Threading.Tasks.Task a12, global::System.Threading.Tasks.Task a13, global::System.Threading.Tasks.Task a14, global::System.Threading.Tasks.Task a15, global::System.ArraySegment a16) { - if (__signature_Annotated_1583225186 == null) + if (__signature_Annotated_2034238666 == null) { - __signature_Annotated_1583225186 = global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindJSFunction("DoesNotExist", null, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Action(), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Function(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Span(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Array(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64)]); + __signature_Annotated_2034238666 = global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindJSFunction("DoesNotExist", null, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Action(), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Function(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Span(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Array(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Single)]); } { @@ -92,11 +92,13 @@ internal static partial void Annotated(object a1, long a2, long a3, global::Syst global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native; global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native; global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native; + global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a16_native; // Setup - Perform required setup. global::System.Runtime.CompilerServices.Unsafe.SkipInit(out ____arg_return_native); ____arg_return_native.Initialize(); global::System.Runtime.CompilerServices.Unsafe.SkipInit(out ____arg_exception_native); ____arg_exception_native.Initialize(); + global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a16_native); global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a15_native); global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a14_native); global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a13_native); @@ -113,6 +115,7 @@ internal static partial void Annotated(object a1, long a2, long a3, global::Syst global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a2_native); global::System.Runtime.CompilerServices.Unsafe.SkipInit(out __a1_native); // Marshal - Convert managed data to native data. + __a16_native.ToJS(a16); __a11_native.ToJS(a11); __a10_native.ToJS(a10); __a9_native.ToJS(a9); @@ -148,18 +151,18 @@ internal static partial void Annotated(object a1, long a2, long a3, global::Syst __delegate_arg_arg1.ToJS(__delegate_arg1); }); __a4_native.ToJS(a4); - __InvokeJSFunction(____arg_exception_native, ____arg_return_native, __a1_native, __a2_native, __a3_native, __a4_native, __a5_native, __a6_native, __a7_native, __a8_native, __a9_native, __a10_native, __a11_native, __a12_native, __a13_native, __a14_native, __a15_native); + __InvokeJSFunction(____arg_exception_native, ____arg_return_native, __a1_native, __a2_native, __a3_native, __a4_native, __a5_native, __a6_native, __a7_native, __a8_native, __a9_native, __a10_native, __a11_native, __a12_native, __a13_native, __a14_native, __a15_native, __a16_native); } } [global::System.Diagnostics.DebuggerNonUserCode] - void __InvokeJSFunction(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_return_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a1_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a2_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a3_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a4_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a5_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a6_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a7_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a8_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a9_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a10_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a11_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a12_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native) + void __InvokeJSFunction(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_return_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a1_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a2_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a3_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a4_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a5_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a6_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a7_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a8_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a9_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a10_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a11_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a12_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a16_native) { - global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.InvokeJS(__signature_Annotated_1583225186, [____arg_exception_native, ____arg_return_native, __a1_native, __a2_native, __a3_native, __a4_native, __a5_native, __a6_native, __a7_native, __a8_native, __a9_native, __a10_native, __a11_native, __a12_native, __a13_native, __a14_native, __a15_native]); + global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.InvokeJS(__signature_Annotated_2034238666, [____arg_exception_native, ____arg_return_native, __a1_native, __a2_native, __a3_native, __a4_native, __a5_native, __a6_native, __a7_native, __a8_native, __a9_native, __a10_native, __a11_native, __a12_native, __a13_native, __a14_native, __a15_native, __a16_native]); } } - static global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding __signature_Annotated_1583225186; + static global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding __signature_Annotated_2034238666; } """.ReplaceLineEndings("\r\n"), Encoding.UTF8, SourceHashAlgorithm.Sha256)), @@ -179,24 +182,24 @@ static internal void __TrimmingPreserve_() { } - [global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute("__Wrapper_AnnotatedExport_1583225186", "Basic", "TestProject")] + [global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute("__Wrapper_AnnotatedExport_2034238666", "Basic", "TestProject")] static void __Register_() { if (initialized || global::System.Runtime.InteropServices.RuntimeInformation.OSArchitecture != global::System.Runtime.InteropServices.Architecture.Wasm) return; initialized = true; - global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindManagedFunction("[TestProject]Basic:AnnotatedExport", 1583225186, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Action(), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Function(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Span(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Array(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64)]); + global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindManagedFunction("[TestProject]Basic:AnnotatedExport", 2034238666, [global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Action(), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Function(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int32), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Span(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Byte), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Array(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Object), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset, global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTime), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.DateTimeOffset), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Int52), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Task(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.BigInt64), global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.ArraySegment(global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Single)]); } } } unsafe partial class Basic { [global::System.Diagnostics.DebuggerNonUserCode] - internal static unsafe void __Wrapper_AnnotatedExport_1583225186(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* __arguments_buffer) + internal static unsafe void __Wrapper_AnnotatedExport_2034238666(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* __arguments_buffer) { - __Stub(__arguments_buffer[2], __arguments_buffer[3], __arguments_buffer[4], __arguments_buffer[5], __arguments_buffer[6], __arguments_buffer[7], __arguments_buffer[8], __arguments_buffer[9], __arguments_buffer[10], __arguments_buffer[11], __arguments_buffer[12], __arguments_buffer[13], __arguments_buffer[14], __arguments_buffer[15], __arguments_buffer[16], __arguments_buffer); + __Stub(__arguments_buffer[2], __arguments_buffer[3], __arguments_buffer[4], __arguments_buffer[5], __arguments_buffer[6], __arguments_buffer[7], __arguments_buffer[8], __arguments_buffer[9], __arguments_buffer[10], __arguments_buffer[11], __arguments_buffer[12], __arguments_buffer[13], __arguments_buffer[14], __arguments_buffer[15], __arguments_buffer[16], __arguments_buffer[17], __arguments_buffer); [global::System.Diagnostics.DebuggerNonUserCode] - void __Stub(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a1_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a2_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a3_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a4_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a5_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a6_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a7_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a8_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a9_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a10_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a11_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a12_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* ____arg_exception_native__param) + void __Stub(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a1_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a2_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a3_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a4_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a5_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a6_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a7_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a8_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a9_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a10_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a11_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a12_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a13_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a14_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a15_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __a16_native, global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* ____arg_exception_native__param) { object a1 = default; long a2 = default; @@ -213,10 +216,12 @@ void __Stub(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgumen global::System.Threading.Tasks.Task a13 = default; global::System.Threading.Tasks.Task a14 = default; global::System.Threading.Tasks.Task a15 = default; + global::System.ArraySegment a16 = default; ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument ____arg_exception_native = ref *____arg_exception_native__param; try { // UnmarshalCapture - Capture the native data into marshaller instances in case conversion to managed data throws an exception. + __a16_native.ToManaged(out a16); __a11_native.ToManaged(out a11); __a10_native.ToManaged(out a10); __a9_native.ToManaged(out a9); @@ -251,7 +256,7 @@ void __Stub(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgumen __delegate_arg_arg1.ToManaged(out __delegate_arg1); }); __a4_native.ToManaged(out a4); - global::Basic.AnnotatedExport(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); + global::Basic.AnnotatedExport(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16); } catch (global::System.Exception __arg_exception) { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs index 04783f7966da9b..4cce74a34b3896 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/JSImportGenerator.UnitTest/Fails.cs @@ -43,6 +43,7 @@ public class Fails "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a13'. For more information see https://aka.ms/dotnet-wasm-jsinterop", "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a14'. For more information see https://aka.ms/dotnet-wasm-jsinterop", "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.Threading.Tasks.Task. The generated source will not handle marshalling of parameter 'a15'. For more information see https://aka.ms/dotnet-wasm-jsinterop", + "Please annotate the argument with 'JSMarshalAsAttribute' to specify marshaling of global::System.ArraySegment. The generated source will not handle marshalling of parameter 'a16'. For more information see https://aka.ms/dotnet-wasm-jsinterop", },null }; yield return new object?[] { CodeSnippets.InOutRef, new string[] { "Parameters with 'in', 'out' and 'ref' modifiers are not supported by source-generated JavaScript interop. The generated source will not handle marshalling of parameter 'a1'. For more information see https://aka.ms/dotnet-wasm-jsinterop", diff --git a/src/mono/browser/runtime/marshal-to-cs.ts b/src/mono/browser/runtime/marshal-to-cs.ts index e76659a3d96305..d180aca6d12c7d 100644 --- a/src/mono/browser/runtime/marshal-to-cs.ts +++ b/src/mono/browser/runtime/marshal-to-cs.ts @@ -400,6 +400,8 @@ export function marshal_cs_object_to_cs (arg: JSMarshalerArgument, value: any): marshal_exception_to_cs(arg, value); } else if (value instanceof Uint8Array) { marshal_array_to_cs_impl(arg, value, MarshalerType.Byte); + } else if (value instanceof Float32Array) { + marshal_array_to_cs_impl(arg, value, MarshalerType.Single); } else if (value instanceof Float64Array) { marshal_array_to_cs_impl(arg, value, MarshalerType.Double); } else if (value instanceof Int32Array) { @@ -411,7 +413,6 @@ export function marshal_cs_object_to_cs (arg: JSMarshalerArgument, value: any): || value instanceof Uint8ClampedArray || value instanceof Uint16Array || value instanceof Uint32Array - || value instanceof Float32Array ) { throw new Error("NotImplementedException: TypedArray"); } else if (isThenable(value)) { diff --git a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts index 7dbee3c4c45695..b9e5cfbd6f030a 100644 --- a/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts +++ b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal-to-cs.ts @@ -373,6 +373,8 @@ export function marshalCsObjectToCs(arg: JSMarshalerArgument, value: any): void marshalArrayToCsImpl(arg, value, MarshalerType.Byte); } else if (value instanceof Float64Array) { marshalArrayToCsImpl(arg, value, MarshalerType.Double); + } else if (value instanceof Float32Array) { + marshalArrayToCsImpl(arg, value, MarshalerType.Single); } else if (value instanceof Int32Array) { marshalArrayToCsImpl(arg, value, MarshalerType.Int32); } else if (Array.isArray(value)) { @@ -382,7 +384,6 @@ export function marshalCsObjectToCs(arg: JSMarshalerArgument, value: any): void || value instanceof Uint8ClampedArray || value instanceof Uint16Array || value instanceof Uint32Array - || value instanceof Float32Array ) { throw new Error("NotImplementedException: TypedArray"); } else if (isThenable(value)) {