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/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; } } 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..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); @@ -287,6 +297,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/JSExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs index 9d74128c107601..33bed2a64d6481 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/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index 254338ea4cee29..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 @@ -351,6 +351,45 @@ public unsafe void JsImportDoubleArray(double[]? expected) } } + [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) + { + 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(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) @@ -509,6 +548,23 @@ public unsafe void JsImportSpanOfDouble() Assert.Equal(actual[0], actual[1]); } + [Fact] + public unsafe void JsImportSpanOfSingle() + { + 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]); + 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() { @@ -526,8 +582,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]); @@ -540,8 +596,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]); @@ -551,6 +607,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 8d0ca9efe49422..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,11 +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); @@ -267,6 +286,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); @@ -279,6 +302,53 @@ 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); + + [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 diff --git a/src/mono/browser/runtime/marshal-to-cs.ts b/src/mono/browser/runtime/marshal-to-cs.ts index 27824796fac699..e76659a3d96305 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, 2); + 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 f3186d7cf2592a..bd2ad455a2211c 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"; @@ -451,22 +451,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 { @@ -478,14 +479,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 { 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..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 @@ -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, 2); + 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..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 @@ -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, 2); + 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/marshal.ts b/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/marshal.ts index 7814c24f8be87d..b937624441becb 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 @@ -342,13 +342,14 @@ export function getSignatureMarshaler(signature: JSFunctionSignature, index: num } 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; + 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; } 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 {