[wasm] reduce legacy interop usage (#72021)
authorPavel Savara <pavel.savara@gmail.com>
Thu, 28 Jul 2022 20:33:04 +0000 (22:33 +0200)
committerGitHub <noreply@github.com>
Thu, 28 Jul 2022 20:33:04 +0000 (22:33 +0200)
51 files changed:
src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs
src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/JavaScriptTests.cs
src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/MarshalTests.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/LegacyExports.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSFunctionBinding.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Legacy/Runtime.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Byte.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Double.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Exception.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Func.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Int32.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.JSObject.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Object.cs
src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Task.cs
src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs
src/libraries/System.Runtime.InteropServices.JavaScript/tests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs
src/mono/sample/wasm/browser-profile/README.md
src/mono/wasm/runtime/buffers.ts [deleted file]
src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js [new file with mode: 0644]
src/mono/wasm/runtime/corebindings.c
src/mono/wasm/runtime/corebindings.ts [deleted file]
src/mono/wasm/runtime/cwraps.ts
src/mono/wasm/runtime/dotnet.d.ts
src/mono/wasm/runtime/es6/dotnet.es6.lib.js
src/mono/wasm/runtime/export-types.ts
src/mono/wasm/runtime/exports-internal.ts [new file with mode: 0644]
src/mono/wasm/runtime/exports-linker.ts [new file with mode: 0644]
src/mono/wasm/runtime/exports.ts
src/mono/wasm/runtime/gc-handles.ts
src/mono/wasm/runtime/imports.ts
src/mono/wasm/runtime/invoke-cs.ts
src/mono/wasm/runtime/invoke-js.ts
src/mono/wasm/runtime/managed-exports.ts [new file with mode: 0644]
src/mono/wasm/runtime/marshal-to-cs.ts
src/mono/wasm/runtime/marshal-to-js.ts
src/mono/wasm/runtime/marshal.ts
src/mono/wasm/runtime/memory.ts
src/mono/wasm/runtime/net6-legacy/buffers.ts [new file with mode: 0644]
src/mono/wasm/runtime/net6-legacy/corebindings.ts [new file with mode: 0644]
src/mono/wasm/runtime/net6-legacy/cs-to-js.ts [moved from src/mono/wasm/runtime/cs-to-js.ts with 77% similarity]
src/mono/wasm/runtime/net6-legacy/exports-legacy.ts [new file with mode: 0644]
src/mono/wasm/runtime/net6-legacy/js-to-cs.ts [moved from src/mono/wasm/runtime/js-to-cs.ts with 80% similarity]
src/mono/wasm/runtime/net6-legacy/method-binding.ts [moved from src/mono/wasm/runtime/method-binding.ts with 83% similarity]
src/mono/wasm/runtime/net6-legacy/method-calls.ts [moved from src/mono/wasm/runtime/method-calls.ts with 52% similarity]
src/mono/wasm/runtime/run.ts
src/mono/wasm/runtime/startup.ts
src/mono/wasm/runtime/types.ts
src/mono/wasm/test-main.js

index 1653585..693a88b 100644 (file)
@@ -43,11 +43,7 @@ internal static partial class Interop
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         internal static extern void CreateCSOwnedObjectRef(in string className, in object[] parms, out int exceptionalResult, out object result);
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern void TypedArrayCopyToRef(IntPtr jsHandle, int arrayPtr, int begin, int end, int bytesPerElement, out int exceptionalResult, out object result);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
         internal static extern void TypedArrayFromRef(int arrayPtr, int begin, int end, int bytesPerElement, int type, out int exceptionalResult, out object result);
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern void TypedArrayCopyFromRef(IntPtr jsHandle, int arrayPtr, int begin, int end, int bytesPerElement, out int exceptionalResult, out object result);
 
         #endregion
 
index dd2351a..c78c422 100644 (file)
@@ -153,6 +153,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
                 {
                     throw new Exception($"At attempt={attempt}, index={index}: {ex.Message}", ex);
                 }
+                await Task.Yield();
             }
         }
 
index cdc79e5..1f207e6 100644 (file)
@@ -38,9 +38,6 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             Assert.Equal(16, HelperMarshal._byteBuffer.Length);
         }
 
-
-
-
         [Fact]
         public static void MarshalStringToCS()
         {
@@ -279,7 +276,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             HelperMarshal._intValue = 0;
             Utils.InvokeJS(@$"
-                var invoke_int = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
                 invoke_int (200);
             ");
 
@@ -291,7 +288,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             HelperMarshal._intPtrValue = IntPtr.Zero;
             Utils.InvokeJS(@$"
-                var invoke_int_ptr = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeIntPtr"");
+                var invoke_int_ptr = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeIntPtr"");
                 invoke_int_ptr (42);
             ");
             Assert.Equal(42, (int)HelperMarshal._intPtrValue);
@@ -302,7 +299,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             HelperMarshal._marshaledIntPtrValue = IntPtr.Zero;
             Utils.InvokeJS(@$"
-                var invokeMarshalIntPtr = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeMarshalIntPtr"");
+                var invokeMarshalIntPtr = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeMarshalIntPtr"");
                 var r = invokeMarshalIntPtr ();
 
                 if (r != 42) throw `Invalid int_ptr value`;
@@ -311,17 +308,6 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         }
 
         [Fact]
-        public static void InvokeStaticMethod()
-        {
-            HelperMarshal._intValue = 0;
-            Utils.InvokeJS(@$"
-                INTERNAL.call_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"", [ 300 ]);
-            ");
-
-            Assert.Equal(300, HelperMarshal._intValue);
-        }
-
-        [Fact]
         public static void ResolveMethod()
         {
             HelperMarshal._intValue = 0;
@@ -407,6 +393,17 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             Assert.Equal(16, HelperMarshal._byteBuffer.Length);
         }
 
+        [Fact]
+        public static void MarshalUri()
+        {
+            HelperMarshal._blobURI = null;
+            Utils.InvokeJS(@"
+                App.call_test_method (""SetBlobAsUri"", [ ""https://dotnet.microsoft.com/en-us/"" ]);
+            ");
+
+            Assert.NotNull(HelperMarshal._blobURI);
+        }
+
         private static void RunMarshalTypedArrayJS(string type)
         {
             Utils.InvokeJS(@"
@@ -426,8 +423,6 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             Assert.Equal("hic sunt dracones", System.Text.Encoding.Default.GetString(HelperMarshal._taByte));
         }
 
-
-
         [Fact]
         public static void TestFunctionSum()
         {
@@ -455,7 +450,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             HelperMarshal._intValue = 1;
             var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
-                var invoke_int = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
                 invoke_int ();
             "));
             Assert.Contains("Value is not an integer: undefined (undefined)", ex.Message);
@@ -467,7 +462,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             HelperMarshal._intValue = 0;
             Utils.InvokeJS(@$"
-                var invoke_int = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
                 invoke_int (200, 400);
             ");
             Assert.Equal(200, HelperMarshal._intValue);
@@ -479,7 +474,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             HelperMarshal._intValue = 0;
             // no numbers bigger than 32 bits
             var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
-                var invoke_int = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
                 invoke_int (Number.MAX_SAFE_INTEGER);
             "));
             Assert.Contains("Overflow: value 9007199254740991 is out of -2147483648 2147483647 range", ex.Message);
@@ -492,7 +487,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             HelperMarshal._intValue = 0;
             // no floating point rounding
             var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
-                var invoke_int = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
                 invoke_int (3.14);
             "));
             Assert.Contains("Value is not an integer: 3.14 (number)", ex.Message);
@@ -505,7 +500,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             HelperMarshal._intValue = 0;
             // no string conversion
             var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
-                var invoke_int = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
+                var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
                 invoke_int (""200"");
             "));
             Assert.Contains("Value is not an integer: 200 (string)", ex.Message);
@@ -517,7 +512,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             HelperMarshal._uintValue = 0;
             Utils.InvokeJS(@$"
-                var invoke_uint = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeUInt"");
+                var invoke_uint = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeUInt"");
                 invoke_uint (0xFFFFFFFE);
             ");
 
@@ -530,9 +525,9 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             HelperMarshal._uintValue = 0;
             HelperMarshal._enumValue = TestEnum.BigValue;
             Utils.InvokeJS(@$"
-                var get_value = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}GetEnumValue"");
+                var get_value = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}GetEnumValue"");
                 var e = get_value ();
-                var invoke_uint = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeUInt"");
+                var invoke_uint = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeUInt"");
                 invoke_uint (e);
             ");
             Assert.Equal((uint)TestEnum.BigValue, HelperMarshal._uintValue);
@@ -543,7 +538,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             HelperMarshal._enumValue = TestEnum.Zero;
             Utils.InvokeJS(@$"
-                var set_enum = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}SetEnumValue"", ""j"");
+                var set_enum = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}SetEnumValue"", ""j"");
                 set_enum (0xFFFFFFFE);
             ");
             Assert.Equal(TestEnum.BigValue, HelperMarshal._enumValue);
@@ -555,7 +550,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             HelperMarshal._enumValue = TestEnum.Zero;
             var exc = Assert.Throws<JSException>(() =>
                Utils.InvokeJS(@$"
-                    var set_enum = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}SetEnumValue"", ""j"");
+                    var set_enum = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}SetEnumValue"", ""j"");
                     set_enum (""BigValue"");
                 ")
             );
@@ -567,7 +562,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             var exc = Assert.Throws<JSException>(() =>
                Utils.InvokeJS(@$"
-                    var get_u64 = INTERNAL.mono_bind_static_method (""{HelperMarshal.INTEROP_CLASS}GetUInt64"", """");
+                    var get_u64 = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}GetUInt64"", """");
                     var u64 = get_u64();
                 ")
             );
@@ -679,8 +674,8 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
             HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
             var fqn = "[System.Private.Runtime.InteropServices.JavaScript.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:StoreArgumentAndReturnLiteral";
             Utils.InvokeJS(
-                $"var a = INTERNAL.mono_bind_static_method('{fqn}')('test');\r\n" +
-                $"var b = INTERNAL.mono_bind_static_method('{fqn}')(a);\r\n" +
+                $"var a = BINDING.bind_static_method('{fqn}')('test');\r\n" +
+                $"var b = BINDING.bind_static_method('{fqn}')(a);\r\n" +
                 "App.call_test_method ('InvokeString2', [ b ]);"
             );
             Assert.Equal("s: 1 length: 1", HelperMarshal._stringResource);
@@ -721,7 +716,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
                 @"globalThis.__test_promise_completed = false; " +
                 @"globalThis.__test_promise_resolved = false; " +
                 @"globalThis.__test_promise_failed = false; " +
-                $@"var t = App.call_test_method ('{helperMethodName}', [ {helperMethodArgs} ], 'i'); " +
+                $@"var t = App.call_test_method ('{helperMethodName}', [ {helperMethodArgs} ]); " +
                 "t.then(result => { globalThis.__test_promise_resolved = true; " + resolvedBody + " })" +
                 " .catch(e => { globalThis.__test_promise_failed = true; })" +
                 " .finally(result => { globalThis.__test_promise_completed = true; }); " +
index da7cac5..0605e25 100644 (file)
@@ -19,6 +19,7 @@
     <Compile Include="System\Runtime\InteropServices\JavaScript\Interop\JavaScriptImports.Generated.cs" />
     <Compile Include="System\Runtime\InteropServices\JavaScript\Interop\JavaScriptExports.cs" />
     <Compile Include="System\Runtime\InteropServices\JavaScript\Interop\JavaScriptImports.cs" />
+    <Compile Include="System\Runtime\InteropServices\JavaScript\Interop\LegacyExports.cs" />
 
     <Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Runtime.cs" />
     <Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Array.cs" />
index ea24f8e..c0aa35f 100644 (file)
 ï»¿// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-using System.Diagnostics;
-using System.Reflection;
 using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
 
 namespace System.Runtime.InteropServices.JavaScript
 {
-    // this maps to src\mono\wasm\runtime\corebindings.c
-    // the methods are protected from trimming by DynamicDependency on JSFunctionBinding
+    // this maps to src\mono\wasm\runtime\corebindings.ts
+    // the methods are protected from trimming by DynamicDependency on JSFunctionBinding.BindJSFunction
     internal static unsafe partial class JavaScriptExports
     {
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void GetCSOwnedObjectByJSHandleRef(IntPtr jsHandle, int shouldAddInflight, out JSObject? result)
-        {
-            lock (JSHostImplementation.s_csOwnedObjects)
+
+        // The JS layer invokes this method when the JS wrapper for a JS owned object
+        //  has been collected by the JS garbage collector
+        [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        // the marshaled signature is:
+        // void ReleaseJSOwnedObjectByGCHandle(GCHandle gcHandle)
+        public static void ReleaseJSOwnedObjectByGCHandle(JSMarshalerArgument* arguments_buffer)
+        {
+            ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame()
+            ref JSMarshalerArgument arg_1 = ref arguments_buffer[2]; // initialized and set by caller
+            try
             {
-                if (JSHostImplementation.s_csOwnedObjects.TryGetValue((int)jsHandle, out WeakReference<JSObject>? reference))
+                GCHandle handle = (GCHandle)arg_1.slot.GCHandle;
+
+                lock (JSHostImplementation.s_gcHandleFromJSOwnedObject)
                 {
-                    reference.TryGetTarget(out JSObject? jsObject);
-                    if (shouldAddInflight != 0)
-                    {
-                        jsObject?.AddInFlight();
-                    }
-                    result = jsObject;
-                    return;
+                    JSHostImplementation.s_gcHandleFromJSOwnedObject.Remove(handle.Target!);
+                    handle.Free();
                 }
             }
-            result = null;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static IntPtr GetCSOwnedObjectJSHandleRef(in JSObject jsObject, int shouldAddInflight)
-        {
-            jsObject.AssertNotDisposed();
-
-            if (shouldAddInflight != 0)
+            catch (Exception ex)
             {
-                jsObject.AddInFlight();
+                arg_exc.ToJS(ex);
             }
-            return jsObject.JSHandle;
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static IntPtr TryGetCSOwnedObjectJSHandleRef(in object rawObj, int shouldAddInflight)
+        [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        // the marshaled signature is:
+        // GCHandle CreateTaskCallback()
+        public static void CreateTaskCallback(JSMarshalerArgument* arguments_buffer)
         {
-            JSObject? jsObject = rawObj as JSObject;
-            if (jsObject != null && shouldAddInflight != 0)
+            ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame()
+            ref JSMarshalerArgument arg_return = ref arguments_buffer[1]; // used as return vaule
+            try
             {
-                jsObject.AddInFlight();
+                JSHostImplementation.TaskCallback holder = new JSHostImplementation.TaskCallback();
+                arg_return.slot.Type = MarshalerType.Object;
+                arg_return.slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(holder);
+            }
+            catch (Exception ex)
+            {
+                arg_exc.ToJS(ex);
             }
-            return jsObject?.JSHandle ?? IntPtr.Zero;
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void CreateCSOwnedProxyRef(IntPtr jsHandle, JSHostImplementation.MappedType mappedType, int shouldAddInflight, out JSObject jsObject)
+        [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        // the marshaled signature is:
+        // TRes? CallDelegate<T1,T2,T3TRes>(GCHandle callback, T1? arg1, T2? arg2, T3? arg3)
+        public static void CallDelegate(JSMarshalerArgument* arguments_buffer)
         {
-            JSObject? res = null;
-
-            lock (JSHostImplementation.s_csOwnedObjects)
+            ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by JS caller in alloc_stack_frame()
+            // arg_res is initialized by JS caller
+            ref JSMarshalerArgument arg_1 = ref arguments_buffer[2];// initialized and set by JS caller
+            // arg_2 set by JS caller when there are arguments
+            // arg_3 set by JS caller when there are arguments
+            // arg_4 set by JS caller when there are arguments
+            try
             {
-                if (!JSHostImplementation.s_csOwnedObjects.TryGetValue((int)jsHandle, out WeakReference<JSObject>? reference) ||
-                    !reference.TryGetTarget(out res) ||
-                    res.IsDisposed)
+                GCHandle callback_gc_handle = (GCHandle)arg_1.slot.GCHandle;
+                if (callback_gc_handle.Target is JSHostImplementation.ToManagedCallback callback)
+                {
+                    // arg_2, arg_3, arg_4, arg_res are processed by the callback
+                    callback(arguments_buffer);
+                }
+                else
                 {
-#pragma warning disable CS0612 // Type or member is obsolete
-                    res = mappedType switch
-                    {
-                        JSHostImplementation.MappedType.JSObject => new JSObject(jsHandle),
-                        JSHostImplementation.MappedType.Array => new Array(jsHandle),
-                        JSHostImplementation.MappedType.ArrayBuffer => new ArrayBuffer(jsHandle),
-                        JSHostImplementation.MappedType.DataView => new DataView(jsHandle),
-                        JSHostImplementation.MappedType.Function => new Function(jsHandle),
-                        JSHostImplementation.MappedType.Uint8Array => new Uint8Array(jsHandle),
-                        _ => throw new ArgumentOutOfRangeException(nameof(mappedType))
-                    };
-#pragma warning restore CS0612 // Type or member is obsolete
-                    JSHostImplementation.s_csOwnedObjects[(int)jsHandle] = new WeakReference<JSObject>(res, trackResurrection: true);
+                    throw new InvalidOperationException("ToManagedCallback is null");
                 }
             }
-            if (shouldAddInflight != 0)
+            catch (Exception ex)
             {
-                res.AddInFlight();
+                arg_exc.ToJS(ex);
             }
-            jsObject = res;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void GetJSOwnedObjectByGCHandleRef(int gcHandle, out object result)
-        {
-            GCHandle h = (GCHandle)(IntPtr)gcHandle;
-            result = h.Target!;
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static IntPtr GetJSOwnedObjectGCHandleRef(in object obj)
-        {
-            return JSHostImplementation.GetJSOwnedObjectGCHandleRef(obj, GCHandleType.Normal);
-        }
-
-        // The JS layer invokes this method when the JS wrapper for a JS owned object
-        //  has been collected by the JS garbage collector
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void ReleaseJSOwnedObjectByGCHandle(IntPtr gcHandle)
-        {
-            GCHandle handle = (GCHandle)gcHandle;
-            lock (JSHostImplementation.s_gcHandleFromJSOwnedObject)
-            {
-                JSHostImplementation.s_gcHandleFromJSOwnedObject.Remove(handle.Target!);
-                handle.Free();
-            }
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static IntPtr CreateTaskSource()
-        {
-            var tcs = new TaskCompletionSource<object>();
-            return GetJSOwnedObjectGCHandleRef(tcs);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void SetTaskSourceResultRef(int tcsGCHandle, in object result)
-        {
-            GCHandle handle = (GCHandle)(IntPtr)tcsGCHandle;
-            // this is JS owned Normal handle. We always have a Target
-            TaskCompletionSource<object> tcs = (TaskCompletionSource<object>)handle.Target!;
-            tcs.SetResult(result);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void SetTaskSourceFailure(int tcsGCHandle, string reason)
-        {
-            GCHandle handle = (GCHandle)(IntPtr)tcsGCHandle;
-            // this is JS owned Normal handle. We always have a Target
-            TaskCompletionSource<object> tcs = (TaskCompletionSource<object>)handle.Target!;
-            tcs.SetException(new JSException(reason));
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void GetTaskSourceTaskRef(int tcsGCHandle, out object result)
-        {
-            GCHandle handle = (GCHandle)(IntPtr)tcsGCHandle;
-            // this is JS owned Normal handle. We always have a Target
-            TaskCompletionSource<object> tcs = (TaskCompletionSource<object>)handle.Target!;
-            result = tcs.Task;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void TaskFromResultRef(in object obj, out object result)
-        {
-            result = Task.FromResult(obj);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void SetupJSContinuationRef(in Task _task, JSObject continuationObj)
+        [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        // the marshaled signature is:
+        // void CompleteTask<T>(GCHandle holder, Exception? exceptionResult, T? result)
+        public static void CompleteTask(JSMarshalerArgument* arguments_buffer)
         {
-            // HACK: Attempting to use the in-param will produce CS1628, so we make a temporary copy
-            //  on the stack that can be captured by our local functions below
-            var task = _task;
-
-            if (task.IsCompleted)
-                Complete();
-            else
-                task.GetAwaiter().OnCompleted(Complete);
-
-            void Complete()
+            ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame()
+            ref JSMarshalerArgument arg_1 = ref arguments_buffer[2];// initialized and set by caller
+            // arg_2 set by caller when this is SetException call
+            // arg_3 set by caller when this is SetResult call
+            try
             {
-                try
-                {
-                    if (task.Exception == null)
-                    {
-                        object? result;
-                        Type task_type = task.GetType();
-                        if (task_type == typeof(Task))
-                        {
-                            result = System.Array.Empty<object>();
-                        }
-                        else
-                        {
-                            result = JSHostImplementation.GetTaskResultMethodInfo(task_type)?.Invoke(task, null);
-                        }
-
-                        continuationObj.Invoke("resolve", result);
-                    }
-                    else
-                    {
-                        continuationObj.Invoke("reject", task.Exception.ToString());
-                    }
-                }
-                catch (Exception e)
+                GCHandle callback_gc_handle = (GCHandle)arg_1.slot.GCHandle;
+                if (callback_gc_handle.Target is JSHostImplementation.TaskCallback holder && holder.Callback is not null)
                 {
-                    continuationObj.Invoke("reject", e.ToString());
+                    // arg_2, arg_3 are processed by the callback
+                    holder.Callback(arguments_buffer);
                 }
-                finally
+                else
                 {
-                    continuationObj.Dispose();
+                    throw new InvalidOperationException("TaskCallback is null");
                 }
             }
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static string ObjectToStringRef(ref object o)
-        {
-            return o.ToString() ?? string.Empty;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static double GetDateValueRef(ref object dtv)
-        {
-            ArgumentNullException.ThrowIfNull(dtv);
-
-            if (!(dtv is DateTime dt))
-                throw new InvalidCastException(SR.Format(SR.UnableCastObjectToType, dtv.GetType(), typeof(DateTime)));
-            if (dt.Kind == DateTimeKind.Local)
-                dt = dt.ToUniversalTime();
-            else if (dt.Kind == DateTimeKind.Unspecified)
-                dt = new DateTime(dt.Ticks, DateTimeKind.Utc);
-            return new DateTimeOffset(dt).ToUnixTimeMilliseconds();
-        }
-
-        // HACK: We need to implicitly box by using an 'object' out-param.
-        // Note that the return value would have been boxed on the C#->JS transition anyway.
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void CreateDateTimeRef(double ticks, out object result)
-        {
-            DateTimeOffset unixTime = DateTimeOffset.FromUnixTimeMilliseconds((long)ticks);
-            result = unixTime.DateTime;
-        }
-
-        // TODO remove this to allow trimming of Uri assembly
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void CreateUriRef(string uri, out Uri result)
-        {
-            result = new Uri(uri);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static bool IsSimpleArrayRef(ref object a)
-        {
-            return a is System.Array arr && arr.Rank == 1 && arr.GetLowerBound(0) == 0;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static string GetCallSignatureRef(IntPtr _methodHandle, in object objForRuntimeType)
-        {
-            var methodHandle = JSHostImplementation.GetMethodHandleFromIntPtr(_methodHandle);
-
-            MethodBase? mb = objForRuntimeType is null ? MethodBase.GetMethodFromHandle(methodHandle) : MethodBase.GetMethodFromHandle(methodHandle, Type.GetTypeHandle(objForRuntimeType));
-            if (mb is null)
-                return string.Empty;
-
-            ParameterInfo[] parms = mb.GetParameters();
-            int parmsLength = parms.Length;
-            if (parmsLength == 0)
-                return string.Empty;
-
-            var result = new char[parmsLength];
-            for (int i = 0; i < parmsLength; i++)
+            catch (Exception ex)
             {
-                Type t = parms[i].ParameterType;
-                var mt = JSHostImplementation.GetMarshalTypeFromType(t);
-                result[i] = JSHostImplementation.GetCallSignatureCharacterForMarshalType(mt, null);
+                arg_exc.ToJS(ex);
             }
-
-            return new string(result);
         }
 
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
         public static void StopProfile()
         {
         }
 
         // Called by the AOT profiler to save profile data into INTERNAL.aot_profile_data
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
         public static unsafe void DumpAotProfileData(ref byte buf, int len, string extraArg)
         {
             if (len == 0)
@@ -291,45 +136,5 @@ namespace System.Runtime.InteropServices.JavaScript
                 module.SetProperty("aot_profile_data", span.ToArray());
             }
         }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        internal static JSObject CreateCSOwnedProxy(IntPtr jsHandle)
-        {
-            CreateCSOwnedProxyRef(jsHandle, JSHostImplementation.MappedType.JSObject, 0, out JSObject? res);
-            return res;
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static IntPtr CreateTaskCallback()
-        {
-            JSHostImplementation.TaskCallback holder = new JSHostImplementation.TaskCallback();
-            return GetJSOwnedObjectGCHandleRef(holder);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void CallDelegate(JSMarshalerArgument* arguments_buffer)
-        {
-            ref JSMarshalerArgument arg_return = ref arguments_buffer[1];
-            GCHandle callback_gc_handle = (GCHandle)arg_return.slot.GCHandle;
-
-            JSHostImplementation.ToManagedCallback? cb = (JSHostImplementation.ToManagedCallback?)callback_gc_handle.Target;
-            if (cb == null)
-                throw new InvalidOperationException("ToManagedCallback is null");
-
-            cb(arguments_buffer);
-        }
-
-        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
-        public static void CompleteTask(JSMarshalerArgument* arguments_buffer)
-        {
-            ref JSMarshalerArgument arg_return = ref arguments_buffer[1];
-            GCHandle callback_gc_handle = (GCHandle)arg_return.slot.GCHandle;
-
-            JSHostImplementation.TaskCallback? holder = (JSHostImplementation.TaskCallback?)callback_gc_handle.Target;
-            if (holder == null || holder.Callback == null)
-                throw new InvalidOperationException("TaskCallback is null");
-
-            holder.Callback(arguments_buffer);
-        }
     }
 }
diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/LegacyExports.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/LegacyExports.cs
new file mode 100644 (file)
index 0000000..faf196d
--- /dev/null
@@ -0,0 +1,255 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+
+namespace System.Runtime.InteropServices.JavaScript
+{
+    // this maps to src\mono\wasm\runtime\legacy\corebindings.ts
+    // the methods are protected from trimming by DynamicDependency on JSFunctionBinding.BindJSFunction
+    internal static unsafe partial class LegacyExports
+    {
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void GetCSOwnedObjectByJSHandleRef(IntPtr jsHandle, int shouldAddInflight, out JSObject? result)
+        {
+            lock (JSHostImplementation.s_csOwnedObjects)
+            {
+                if (JSHostImplementation.s_csOwnedObjects.TryGetValue((int)jsHandle, out WeakReference<JSObject>? reference))
+                {
+                    reference.TryGetTarget(out JSObject? jsObject);
+                    if (shouldAddInflight != 0)
+                    {
+                        jsObject?.AddInFlight();
+                    }
+                    result = jsObject;
+                    return;
+                }
+            }
+            result = null;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static IntPtr GetCSOwnedObjectJSHandleRef(in JSObject jsObject, int shouldAddInflight)
+        {
+            jsObject.AssertNotDisposed();
+
+            if (shouldAddInflight != 0)
+            {
+                jsObject.AddInFlight();
+            }
+            return jsObject.JSHandle;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static IntPtr TryGetCSOwnedObjectJSHandleRef(in object rawObj, int shouldAddInflight)
+        {
+            JSObject? jsObject = rawObj as JSObject;
+            if (jsObject != null && shouldAddInflight != 0)
+            {
+                jsObject.AddInFlight();
+            }
+            return jsObject?.JSHandle ?? IntPtr.Zero;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void CreateCSOwnedProxyRef(IntPtr jsHandle, JSHostImplementation.MappedType mappedType, int shouldAddInflight, out JSObject jsObject)
+        {
+            JSObject? res = null;
+
+            lock (JSHostImplementation.s_csOwnedObjects)
+            {
+                if (!JSHostImplementation.s_csOwnedObjects.TryGetValue((int)jsHandle, out WeakReference<JSObject>? reference) ||
+                    !reference.TryGetTarget(out res) ||
+                    res.IsDisposed)
+                {
+#pragma warning disable CS0612 // Type or member is obsolete
+                    res = mappedType switch
+                    {
+                        JSHostImplementation.MappedType.JSObject => new JSObject(jsHandle),
+                        JSHostImplementation.MappedType.Array => new Array(jsHandle),
+                        JSHostImplementation.MappedType.ArrayBuffer => new ArrayBuffer(jsHandle),
+                        JSHostImplementation.MappedType.DataView => new DataView(jsHandle),
+                        JSHostImplementation.MappedType.Function => new Function(jsHandle),
+                        JSHostImplementation.MappedType.Uint8Array => new Uint8Array(jsHandle),
+                        _ => throw new ArgumentOutOfRangeException(nameof(mappedType))
+                    };
+#pragma warning restore CS0612 // Type or member is obsolete
+                    JSHostImplementation.s_csOwnedObjects[(int)jsHandle] = new WeakReference<JSObject>(res, trackResurrection: true);
+                }
+            }
+            if (shouldAddInflight != 0)
+            {
+                res.AddInFlight();
+            }
+            jsObject = res;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void GetJSOwnedObjectByGCHandleRef(int gcHandle, out object result)
+        {
+            GCHandle h = (GCHandle)(IntPtr)gcHandle;
+            result = h.Target!;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static IntPtr GetJSOwnedObjectGCHandleRef(in object obj)
+        {
+            return JSHostImplementation.GetJSOwnedObjectGCHandle(obj, GCHandleType.Normal);
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static IntPtr CreateTaskSource()
+        {
+            var tcs = new TaskCompletionSource<object>();
+            return GetJSOwnedObjectGCHandleRef(tcs);
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void SetTaskSourceResultRef(int tcsGCHandle, in object result)
+        {
+            GCHandle handle = (GCHandle)(IntPtr)tcsGCHandle;
+            // this is JS owned Normal handle. We always have a Target
+            TaskCompletionSource<object> tcs = (TaskCompletionSource<object>)handle.Target!;
+            tcs.SetResult(result);
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void SetTaskSourceFailure(int tcsGCHandle, string reason)
+        {
+            GCHandle handle = (GCHandle)(IntPtr)tcsGCHandle;
+            // this is JS owned Normal handle. We always have a Target
+            TaskCompletionSource<object> tcs = (TaskCompletionSource<object>)handle.Target!;
+            tcs.SetException(new JSException(reason));
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void GetTaskSourceTaskRef(int tcsGCHandle, out object result)
+        {
+            GCHandle handle = (GCHandle)(IntPtr)tcsGCHandle;
+            // this is JS owned Normal handle. We always have a Target
+            TaskCompletionSource<object> tcs = (TaskCompletionSource<object>)handle.Target!;
+            result = tcs.Task;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void SetupJSContinuationRef(in Task _task, JSObject continuationObj)
+        {
+            // HACK: Attempting to use the in-param will produce CS1628, so we make a temporary copy
+            //  on the stack that can be captured by our local functions below
+            var task = _task;
+
+            if (task.IsCompleted)
+                Complete();
+            else
+                task.GetAwaiter().OnCompleted(Complete);
+
+            void Complete()
+            {
+                try
+                {
+                    if (task.Exception == null)
+                    {
+                        object? result;
+                        Type task_type = task.GetType();
+                        if (task_type == typeof(Task))
+                        {
+                            result = System.Array.Empty<object>();
+                        }
+                        else
+                        {
+                            result = JSHostImplementation.GetTaskResultMethodInfo(task_type)?.Invoke(task, null);
+                        }
+
+                        continuationObj.Invoke("resolve", result);
+                    }
+                    else
+                    {
+                        continuationObj.Invoke("reject", task.Exception.ToString());
+                    }
+                }
+                catch (Exception e)
+                {
+                    continuationObj.Invoke("reject", e.ToString());
+                }
+                finally
+                {
+                    continuationObj.Dispose();
+                }
+            }
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static string ObjectToStringRef(ref object o)
+        {
+            return o.ToString() ?? string.Empty;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static double GetDateValueRef(ref object dtv)
+        {
+            ArgumentNullException.ThrowIfNull(dtv);
+
+            if (!(dtv is DateTime dt))
+                throw new InvalidCastException(SR.Format(SR.UnableCastObjectToType, dtv.GetType(), typeof(DateTime)));
+            if (dt.Kind == DateTimeKind.Local)
+                dt = dt.ToUniversalTime();
+            else if (dt.Kind == DateTimeKind.Unspecified)
+                dt = new DateTime(dt.Ticks, DateTimeKind.Utc);
+            return new DateTimeOffset(dt).ToUnixTimeMilliseconds();
+        }
+
+        // HACK: We need to implicitly box by using an 'object' out-param.
+        // Note that the return value would have been boxed on the C#->JS transition anyway.
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void CreateDateTimeRef(double ticks, out object result)
+        {
+            DateTimeOffset unixTime = DateTimeOffset.FromUnixTimeMilliseconds((long)ticks);
+            result = unixTime.DateTime;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static void CreateUriRef(string uri, out object? result)
+        {
+            // we do this via reflection to allow linker to trim dependency on URI and it's assembly
+            // if the user code has methods with Uri signature, this should work too
+            // System.Private.Uri is large assembly so it's worth trimming
+            var uriType = Type.GetType("System.Uri, System.Private.Uri");
+            if (uriType == null) throw new InvalidProgramException();
+            result = Activator.CreateInstance(uriType, uri);
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static bool IsSimpleArrayRef(ref object a)
+        {
+            return a is System.Array arr && arr.Rank == 1 && arr.GetLowerBound(0) == 0;
+        }
+
+        [MethodImplAttribute(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425
+        public static string GetCallSignatureRef(IntPtr _methodHandle, in object objForRuntimeType)
+        {
+            var methodHandle = JSHostImplementation.GetMethodHandleFromIntPtr(_methodHandle);
+
+            MethodBase? mb = objForRuntimeType is null ? MethodBase.GetMethodFromHandle(methodHandle) : MethodBase.GetMethodFromHandle(methodHandle, Type.GetTypeHandle(objForRuntimeType));
+            if (mb is null)
+                return string.Empty;
+
+            ParameterInfo[] parms = mb.GetParameters();
+            int parmsLength = parms.Length;
+            if (parmsLength == 0)
+                return string.Empty;
+
+            var result = new char[parmsLength];
+            for (int i = 0; i < parmsLength; i++)
+            {
+                Type t = parms[i].ParameterType;
+                var mt = JSHostImplementation.GetMarshalTypeFromType(t);
+                result[i] = JSHostImplementation.GetCallSignatureCharacterForMarshalType(mt, null);
+            }
+
+            return new string(result);
+        }
+    }
+}
index 3455f53..8ec2764 100644 (file)
@@ -130,6 +130,8 @@ namespace System.Runtime.InteropServices.JavaScript
         /// </summary>
         // JavaScriptExports need to be protected from trimming because they are used from C/JS code which IL linker can't see
         [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.JavaScriptExports", "System.Runtime.InteropServices.JavaScript")]
+        // TODO make this DynamicDependency conditional
+        [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.LegacyExports", "System.Runtime.InteropServices.JavaScript")]
         public static JSFunctionBinding BindJSFunction(string functionName, string moduleName, ReadOnlySpan<JSMarshalerType> signatures)
         {
             if (RuntimeInformation.OSArchitecture != Architecture.Wasm)
@@ -174,7 +176,7 @@ namespace System.Runtime.InteropServices.JavaScript
             if (isException != 0)
                 throw new JSException((string)exceptionMessage);
 
-            signature.JSFunction = JavaScriptExports.CreateCSOwnedProxy(jsFunctionHandle);
+            signature.JSFunction = JSHostImplementation.CreateCSOwnedProxy(jsFunctionHandle);
 
             return signature;
         }
index aa1ad66..f42902e 100644 (file)
@@ -66,7 +66,7 @@ namespace System.Runtime.InteropServices.JavaScript
         //  strong references, allowing the managed object to be collected.
         // This ensures that things like delegates and promises will never 'go away' while JS
         //  is expecting to be able to invoke or await them.
-        public static IntPtr GetJSOwnedObjectGCHandleRef(object obj, GCHandleType handleType)
+        public static IntPtr GetJSOwnedObjectGCHandle(object obj, GCHandleType handleType = GCHandleType.Normal)
         {
             if (obj == null)
                 return IntPtr.Zero;
@@ -176,6 +176,8 @@ namespace System.Runtime.InteropServices.JavaScript
                 return MarshalType.DELEGATE;
             else if ((type == typeof(Task)) || typeof(Task).IsAssignableFrom(type))
                 return MarshalType.TASK;
+            else if (type.FullName == "System.Uri")
+                return MarshalType.URI;
             else if (type.IsPointer)
                 return MarshalType.POINTER;
 
@@ -256,7 +258,7 @@ namespace System.Runtime.InteropServices.JavaScript
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static void ThrowException(ref JSMarshalerArgument arg)
+        public static void ThrowException(ref JSMarshalerArgument arg)
         {
             arg.ToManaged(out Exception? ex);
 
@@ -275,7 +277,7 @@ namespace System.Runtime.InteropServices.JavaScript
             return await wrappedTask.ConfigureAwait(true);
         }
 
-        private static async Task<JSObject> CancelationHelper(Task<JSObject> jsTask, CancellationToken cancellationToken)
+        public static async Task<JSObject> CancelationHelper(Task<JSObject> jsTask, CancellationToken cancellationToken)
         {
             if (jsTask.IsCompletedSuccessfully)
             {
@@ -291,7 +293,7 @@ namespace System.Runtime.InteropServices.JavaScript
         }
 
         // res type is first argument
-        internal static unsafe JSFunctionBinding GetMethodSignature(ReadOnlySpan<JSMarshalerType> types)
+        public static unsafe JSFunctionBinding GetMethodSignature(ReadOnlySpan<JSMarshalerType> types)
         {
             int argsCount = types.Length - 1;
             int size = JSFunctionBinding.JSBindingHeader.JSMarshalerSignatureHeaderSize + ((argsCount + 2) * sizeof(JSFunctionBinding.JSBindingType));
@@ -315,5 +317,22 @@ namespace System.Runtime.InteropServices.JavaScript
 
             return signature;
         }
+
+        public static JSObject CreateCSOwnedProxy(IntPtr jsHandle)
+        {
+            JSObject? res = null;
+
+            lock (s_csOwnedObjects)
+            {
+                if (!s_csOwnedObjects.TryGetValue((int)jsHandle, out WeakReference<JSObject>? reference) ||
+                    !reference.TryGetTarget(out res) ||
+                    res.IsDisposed)
+                {
+                    res = new JSObject(jsHandle);
+                    s_csOwnedObjects[(int)jsHandle] = new WeakReference<JSObject>(res, trackResurrection: true);
+                }
+            }
+            return res;
+        }
     }
 }
index 1516024..469f71c 100644 (file)
@@ -10,6 +10,7 @@ namespace System.Runtime.InteropServices.JavaScript
     public static class Runtime
     {
         [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.JavaScriptExports", "System.Runtime.InteropServices.JavaScript")]
+        [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.LegacyExports", "System.Runtime.InteropServices.JavaScript")]
         public static object GetGlobalObject(string str)
             => JavaScriptImports.GetGlobalObject(str);
 
index 218b403..0c97341 100644 (file)
@@ -125,7 +125,7 @@ namespace System.Runtime.InteropServices.JavaScript
                 return;
             }
             slot.Type = MarshalerType.ArraySegment;
-            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandleRef(value.Array, GCHandleType.Pinned);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(value.Array, GCHandleType.Pinned);
             var refPtr = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(value.Array));
             slot.IntPtrValue = refPtr + value.Offset;
             slot.Length = value.Count;
index 2dcb1d4..43c48be 100644 (file)
@@ -127,7 +127,7 @@ namespace System.Runtime.InteropServices.JavaScript
                 return;
             }
             slot.Type = MarshalerType.ArraySegment;
-            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandleRef(value.Array, GCHandleType.Pinned);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(value.Array, GCHandleType.Pinned);
             var refPtr = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(value.Array));
             slot.IntPtrValue = refPtr + (value.Offset * sizeof(double));
             slot.Length = value.Count;
index 674b589..8c2ec3f 100644 (file)
@@ -32,7 +32,7 @@ namespace System.Runtime.InteropServices.JavaScript
             if (slot.JSHandle != IntPtr.Zero)
             {
                 // this is JSException round-trip
-                jsException = JavaScriptExports.CreateCSOwnedProxy(slot.JSHandle);
+                jsException = JSHostImplementation.CreateCSOwnedProxy(slot.JSHandle);
             }
 
             string? message;
@@ -75,7 +75,7 @@ namespace System.Runtime.InteropServices.JavaScript
                 {
                     ToJS(cpy.Message);
                     slot.Type = MarshalerType.Exception;
-                    slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cpy);
+                    slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cpy);
                 }
             }
         }
index dd09fc2..e631f89 100644 (file)
@@ -11,7 +11,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public ActionJS(IntPtr jsHandle)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
             }
 
             public void InvokeJS()
@@ -37,7 +37,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public ActionJS(IntPtr jsHandle, ArgumentToJSCallback<T> arg1Marshaler)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
                 Arg1Marshaler = arg1Marshaler;
             }
 
@@ -64,7 +64,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public ActionJS(IntPtr jsHandle, ArgumentToJSCallback<T1> arg1Marshaler, ArgumentToJSCallback<T2> arg2Marshaler)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
                 Arg1Marshaler = arg1Marshaler;
                 Arg2Marshaler = arg2Marshaler;
             }
@@ -95,7 +95,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public ActionJS(IntPtr jsHandle, ArgumentToJSCallback<T1> arg1Marshaler, ArgumentToJSCallback<T2> arg2Marshaler, ArgumentToJSCallback<T3> arg3Marshaler)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
                 Arg1Marshaler = arg1Marshaler;
                 Arg2Marshaler = arg2Marshaler;
                 Arg3Marshaler = arg3Marshaler;
@@ -187,7 +187,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public FuncJS(IntPtr jsHandle, ArgumentToManagedCallback<TResult> resMarshaler)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
                 ResMarshaler = resMarshaler;
             }
 
@@ -218,7 +218,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public FuncJS(IntPtr jsHandle, ArgumentToJSCallback<T> arg1Marshaler, ArgumentToManagedCallback<TResult> resMarshaler)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
                 Arg1Marshaler = arg1Marshaler;
                 ResMarshaler = resMarshaler;
             }
@@ -250,7 +250,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public FuncJS(IntPtr jsHandle, ArgumentToJSCallback<T1> arg1Marshaler, ArgumentToJSCallback<T2> arg2Marshaler, ArgumentToManagedCallback<TResult> resMarshaler)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
                 Arg1Marshaler = arg1Marshaler;
                 Arg2Marshaler = arg2Marshaler;
                 ResMarshaler = resMarshaler;
@@ -286,7 +286,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             public FuncJS(IntPtr jsHandle, ArgumentToJSCallback<T1> arg1Marshaler, ArgumentToJSCallback<T2> arg2Marshaler, ArgumentToJSCallback<T3> arg3Marshaler, ArgumentToManagedCallback<TResult> resMarshaler)
             {
-                JSObject = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+                JSObject = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
                 Arg1Marshaler = arg1Marshaler;
                 Arg2Marshaler = arg2Marshaler;
                 Arg3Marshaler = arg3Marshaler;
@@ -386,18 +386,11 @@ namespace System.Runtime.InteropServices.JavaScript
             // TODO: we could try to cache value -> existing GCHandle
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
-                try
-                {
-                    cpy.Invoke();
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                cpy.Invoke();
+                // eventual exception is handled by C# caller
             };
             slot.Type = MarshalerType.Function;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
 
         /// <summary>
@@ -409,20 +402,13 @@ namespace System.Runtime.InteropServices.JavaScript
             Action<T> cpy = value;
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
-                ref JSMarshalerArgument arg1 = ref arguments[2];
-                try
-                {
-                    arg1Marshaler(ref arg1, out T arg1cs);
-                    cpy.Invoke(arg1cs);
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                ref JSMarshalerArgument arg2 = ref arguments[3]; // set by JS caller
+                arg1Marshaler(ref arg2, out T arg1cs);
+                cpy.Invoke(arg1cs);
+                // eventual exception is handled by C# caller
             };
             slot.Type = MarshalerType.Action;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
 
         /// <summary>
@@ -434,22 +420,15 @@ namespace System.Runtime.InteropServices.JavaScript
             Action<T1, T2> cpy = value;
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
-                ref JSMarshalerArgument arg1 = ref arguments[2];
-                ref JSMarshalerArgument arg2 = ref arguments[3];
-                try
-                {
-                    arg1Marshaler(ref arg1, out T1 arg1cs);
-                    arg2Marshaler(ref arg2, out T2 arg2cs);
-                    cpy.Invoke(arg1cs, arg2cs);
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                ref JSMarshalerArgument arg2 = ref arguments[3];// set by JS caller
+                ref JSMarshalerArgument arg3 = ref arguments[4];// set by JS caller
+                arg1Marshaler(ref arg2, out T1 arg1cs);
+                arg2Marshaler(ref arg3, out T2 arg2cs);
+                cpy.Invoke(arg1cs, arg2cs);
+                // eventual exception is handled by C# caller
             };
             slot.Type = MarshalerType.Action;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
 
         /// <summary>
@@ -461,24 +440,17 @@ namespace System.Runtime.InteropServices.JavaScript
             Action<T1, T2, T3> cpy = value;
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
-                ref JSMarshalerArgument arg1 = ref arguments[2];
-                ref JSMarshalerArgument arg2 = ref arguments[3];
-                ref JSMarshalerArgument arg3 = ref arguments[4];
-                try
-                {
-                    arg1Marshaler(ref arg1, out T1 arg1cs);
-                    arg2Marshaler(ref arg2, out T2 arg2cs);
-                    arg3Marshaler(ref arg3, out T3 arg3cs);
-                    cpy.Invoke(arg1cs, arg2cs, arg3cs);
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                ref JSMarshalerArgument arg2 = ref arguments[3];// set by JS caller
+                ref JSMarshalerArgument arg3 = ref arguments[4];// set by JS caller
+                ref JSMarshalerArgument arg4 = ref arguments[5];// set by JS caller
+                arg1Marshaler(ref arg2, out T1 arg1cs);
+                arg2Marshaler(ref arg3, out T2 arg2cs);
+                arg3Marshaler(ref arg4, out T3 arg3cs);
+                cpy.Invoke(arg1cs, arg2cs, arg3cs);
+                // eventual exception is handled by C# caller
             };
             slot.Type = MarshalerType.Action;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
 
         /// <summary>
@@ -490,20 +462,13 @@ namespace System.Runtime.InteropServices.JavaScript
             Func<TResult> cpy = value;
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
                 ref JSMarshalerArgument res = ref arguments[1];
-                try
-                {
-                    TResult resCs = cpy.Invoke();
-                    resMarshaler(ref res, resCs);
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                TResult resCs = cpy.Invoke();
+                resMarshaler(ref res, resCs);
+                // eventual exception is handled by C# caller
             };
             slot.Type = MarshalerType.Function;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
 
         /// <summary>
@@ -515,22 +480,15 @@ namespace System.Runtime.InteropServices.JavaScript
             Func<T, TResult> cpy = value;
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
                 ref JSMarshalerArgument res = ref arguments[1];
-                ref JSMarshalerArgument arg1 = ref arguments[2];
-                try
-                {
-                    arg1Marshaler(ref arg1, out T arg1cs);
-                    TResult resCs = cpy.Invoke(arg1cs);
-                    resMarshaler(ref res, resCs);
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                ref JSMarshalerArgument arg2 = ref arguments[3];// set by JS caller
+                arg1Marshaler(ref arg2, out T arg1cs);
+                TResult resCs = cpy.Invoke(arg1cs);
+                resMarshaler(ref res, resCs);
+                // eventual exception is handled by C# caller
             };
             slot.Type = MarshalerType.Function;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
 
         /// <summary>
@@ -542,26 +500,17 @@ namespace System.Runtime.InteropServices.JavaScript
             Func<T1, T2, TResult> cpy = value;
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
                 ref JSMarshalerArgument res = ref arguments[1];
-                ref JSMarshalerArgument arg1 = ref arguments[2];
-                ref JSMarshalerArgument arg2 = ref arguments[3];
-                try
-                {
-                    arg1Marshaler(ref arg1, out T1 arg1cs);
-                    arg2Marshaler(ref arg2, out T2 arg2cs);
-                    TResult resCs = cpy.Invoke(arg1cs, arg2cs);
-                    resMarshaler(ref res, resCs);
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                ref JSMarshalerArgument arg2 = ref arguments[3];// set by JS caller
+                ref JSMarshalerArgument arg3 = ref arguments[4];// set by JS caller
+                arg1Marshaler(ref arg2, out T1 arg1cs);
+                arg2Marshaler(ref arg3, out T2 arg2cs);
+                TResult resCs = cpy.Invoke(arg1cs, arg2cs);
+                resMarshaler(ref res, resCs);
+                // eventual exception is handled by C# caller
             };
-
-
             slot.Type = MarshalerType.Function;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
 
         /// <summary>
@@ -573,28 +522,19 @@ namespace System.Runtime.InteropServices.JavaScript
             Func<T1, T2, T3, TResult> cpy = value;
             JSHostImplementation.ToManagedCallback cb = (JSMarshalerArgument* arguments) =>
             {
-                ref JSMarshalerArgument exc = ref arguments[0];
                 ref JSMarshalerArgument res = ref arguments[1];
-                ref JSMarshalerArgument arg1 = ref arguments[2];
-                ref JSMarshalerArgument arg2 = ref arguments[3];
-                ref JSMarshalerArgument arg3 = ref arguments[4];
-                try
-                {
-                    arg1Marshaler(ref arg1, out T1 arg1cs);
-                    arg2Marshaler(ref arg2, out T2 arg2cs);
-                    arg3Marshaler(ref arg3, out T3 arg3cs);
-                    TResult resCs = cpy.Invoke(arg1cs, arg2cs, arg3cs);
-                    resMarshaler(ref res, resCs);
-                }
-                catch (Exception ex)
-                {
-                    exc.ToJS(ex);
-                }
+                ref JSMarshalerArgument arg2 = ref arguments[3];// set by JS caller
+                ref JSMarshalerArgument arg3 = ref arguments[4];// set by JS caller
+                ref JSMarshalerArgument arg4 = ref arguments[5];// set by JS caller
+                arg1Marshaler(ref arg2, out T1 arg1cs);
+                arg2Marshaler(ref arg3, out T2 arg2cs);
+                arg3Marshaler(ref arg4, out T3 arg3cs);
+                TResult resCs = cpy.Invoke(arg1cs, arg2cs, arg3cs);
+                resMarshaler(ref res, resCs);
+                // eventual exception is handled by C# caller
             };
-
-
             slot.Type = MarshalerType.Function;
-            slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(cb);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(cb);
         }
     }
 }
index 05ddab0..75b2549 100644 (file)
@@ -125,7 +125,7 @@ namespace System.Runtime.InteropServices.JavaScript
                 return;
             }
             slot.Type = MarshalerType.ArraySegment;
-            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandleRef(value.Array, GCHandleType.Pinned);
+            slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(value.Array, GCHandleType.Pinned);
             var refPtr = (IntPtr)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(value.Array));
             slot.IntPtrValue = refPtr + (value.Offset * sizeof(int));
             slot.Length = value.Count;
index ea632d0..58522b4 100644 (file)
@@ -19,7 +19,7 @@ namespace System.Runtime.InteropServices.JavaScript
                 value = null;
                 return;
             }
-            value = JavaScriptExports.CreateCSOwnedProxy(slot.JSHandle);
+            value = JSHostImplementation.CreateCSOwnedProxy(slot.JSHandle);
         }
 
         /// <summary>
index 76fa8ab..ac93951 100644 (file)
@@ -316,7 +316,7 @@ namespace System.Runtime.InteropServices.JavaScript
             else
             {
                 slot.Type = MarshalerType.Object;
-                slot.GCHandle = JavaScriptExports.GetJSOwnedObjectGCHandleRef(value);
+                slot.GCHandle = JSHostImplementation.GetJSOwnedObjectGCHandle(value);
             }
         }
 
index 608443c..e504bb1 100644 (file)
@@ -40,24 +40,18 @@ namespace System.Runtime.InteropServices.JavaScript
             TaskCompletionSource tcs = new TaskCompletionSource(gcHandle);
             JSHostImplementation.ToManagedCallback callback = (JSMarshalerArgument* arguments_buffer) =>
             {
-                ref JSMarshalerArgument arg_exception = ref arguments_buffer[0];
-                try
+                ref JSMarshalerArgument arg_2 = ref arguments_buffer[3]; // set by caller when this is SetException call
+                // arg_3 set by caller when this is SetResult call, un-used here
+                if (arg_2.slot.Type != MarshalerType.None)
                 {
-                    if (arg_exception.slot.Type != MarshalerType.None)
-                    {
-                        arg_exception.ToManaged(out Exception? fail);
-                        tcs.SetException(fail!);
-                    }
-                    else
-                    {
-                        tcs.SetResult();
-                    }
-                    arg_exception.slot.Type = MarshalerType.None;
+                    arg_2.ToManaged(out Exception? fail);
+                    tcs.SetException(fail!);
                 }
-                catch (Exception ex)
+                else
                 {
-                    arg_exception.ToJS(ex);
+                    tcs.SetResult();
                 }
+                // eventual exception is handled by caller
             };
             holder.Callback = callback;
             value = tcs.Task;
@@ -82,27 +76,20 @@ namespace System.Runtime.InteropServices.JavaScript
             TaskCompletionSource<T> tcs = new TaskCompletionSource<T>(gcHandle);
             JSHostImplementation.ToManagedCallback callback = (JSMarshalerArgument* arguments_buffer) =>
             {
-                ref JSMarshalerArgument arg_exception = ref arguments_buffer[0];
-                ref JSMarshalerArgument arg1 = ref arguments_buffer[2];
-                try
+                ref JSMarshalerArgument arg_2 = ref arguments_buffer[3]; // set by caller when this is SetException call
+                ref JSMarshalerArgument arg_3 = ref arguments_buffer[4]; // set by caller when this is SetResult call
+                if (arg_2.slot.Type != MarshalerType.None)
                 {
-                    if (arg_exception.slot.Type != MarshalerType.None)
-                    {
-                        arg_exception.ToManaged(out Exception? fail);
-                        if (fail == null) throw new NullReferenceException("Exception");
-                        tcs.SetException(fail);
-                    }
-                    else
-                    {
-                        marshaler(ref arg1, out T result);
-                        tcs.SetResult(result);
-                    }
-                    arg_exception.slot.Type = MarshalerType.None;
+                    arg_2.ToManaged(out Exception? fail);
+                    if (fail == null) throw new NullReferenceException("Exception");
+                    tcs.SetException(fail);
                 }
-                catch (Exception ex)
+                else
                 {
-                    arg_exception.ToJS(ex);
+                    marshaler(ref arg_3, out T result);
+                    tcs.SetResult(result);
                 }
+                // eventual exception is handled by caller
             };
             holder.Callback = callback;
             value = tcs.Task;
@@ -138,7 +125,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             IntPtr jsHandle = CreatePendingPromise();
             slot.JSHandle = jsHandle;
-            JSObject promise = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+            JSObject promise = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
 
             task.GetAwaiter().OnCompleted(Complete);
 
@@ -216,7 +203,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             IntPtr jsHandle = CreatePendingPromise();
             slot.JSHandle = jsHandle;
-            JSObject promise = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+            JSObject promise = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
 
             task.GetAwaiter().OnCompleted(Complete);
 
@@ -289,7 +276,7 @@ namespace System.Runtime.InteropServices.JavaScript
 
             IntPtr jsHandle = CreatePendingPromise();
             slot.JSHandle = jsHandle;
-            JSObject promise = JavaScriptExports.CreateCSOwnedProxy(jsHandle);
+            JSObject promise = JSHostImplementation.CreateCSOwnedProxy(jsHandle);
 
             task.GetAwaiter().OnCompleted(Complete);
 
index e5bcf47..71a7955 100644 (file)
@@ -150,8 +150,8 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         [Fact]
         public unsafe void CreateFunctionInternal()
         {
-            Func<string> internals = Utils.CreateFunctionString("return INTERNAL.BINDING_ASM");
-            Assert.Equal("[System.Runtime.InteropServices.JavaScript]System.Runtime.InteropServices.JavaScript.JavaScriptExports", internals());
+            Func<bool> internals = Utils.CreateFunctionBool("return INTERNAL.mono_wasm_runtime_is_ready");
+            Assert.True(internals());
         }
 
         #endregion
index 272e854..4750152 100644 (file)
@@ -923,9 +923,9 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
         {
             if (_module == null)
             {
-                Log("JavaScriptTestHelper.mjs importing");
+                // Log("JavaScriptTestHelper.mjs importing");
                 _module = await JSHost.ImportAsync("JavaScriptTestHelper", "./JavaScriptTestHelper.mjs");
-                Log("JavaScriptTestHelper.mjs imported");
+                // Log("JavaScriptTestHelper.mjs imported");
             }
         }
     }
index 83a3fd3..08bedff 100644 (file)
@@ -26,7 +26,7 @@ await createDotnetRuntime(() => ({
 
 3. Call the `write_at` method at the end of the app, either in C# or in JS. To call the `write_at` method in JS, make use of bindings:
 
-`INTERNAL.call_static_method("<[ProjectName] Namespace.Class::StopProfile">, []);`
+`BINDING.bind_static_method("<[ProjectName] Namespace.Class::StopProfile">)();`
 
 When the `write_at` method is called, the `send_to` method `DumpAotProfileData` stores the profile data into `INTERNAL.aot_profile_data`
 
diff --git a/src/mono/wasm/runtime/buffers.ts b/src/mono/wasm/runtime/buffers.ts
deleted file mode 100644 (file)
index ccbc7dc..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-import { JSHandle, MonoArray, MonoObject, MonoObjectRef, is_nullish } from "./types";
-import { Module } from "./imports";
-import { mono_wasm_get_jsobj_from_js_handle } from "./gc-handles";
-import { wrap_error_root } from "./method-calls";
-import { js_to_mono_obj_root } from "./js-to-cs";
-import { Int32Ptr, TypedArray, VoidPtr } from "./types/emscripten";
-import { mono_wasm_new_external_root } from "./roots";
-
-// Creates a new typed array from pinned array address from pinned_array allocated on the heap to the typed array.
-//      address of managed pinned array -> copy from heap -> typed array memory
-function typed_array_from(pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number, type: number) {
-
-    // typed array
-    let newTypedArray: TypedArray | null = null;
-
-    switch (type) {
-        case 5:
-            newTypedArray = new Int8Array(end - begin);
-            break;
-        case 6:
-            newTypedArray = new Uint8Array(end - begin);
-            break;
-        case 7:
-            newTypedArray = new Int16Array(end - begin);
-            break;
-        case 8:
-            newTypedArray = new Uint16Array(end - begin);
-            break;
-        case 9:
-            newTypedArray = new Int32Array(end - begin);
-            break;
-        case 10:
-            newTypedArray = new Uint32Array(end - begin);
-            break;
-        case 13:
-            newTypedArray = new Float32Array(end - begin);
-            break;
-        case 14:
-            newTypedArray = new Float64Array(end - begin);
-            break;
-        case 15:  // This is a special case because the typed array is also byte[]
-            newTypedArray = new Uint8ClampedArray(end - begin);
-            break;
-        default:
-            throw new Error("Unknown array type " + type);
-    }
-
-    typedarray_copy_from(newTypedArray, pinned_array, begin, end, bytes_per_element);
-    return newTypedArray;
-}
-
-// Copy the existing typed array to the heap pointed to by the pinned array address
-//      typed array memory -> copy to heap -> address of managed pinned array
-function typedarray_copy_to(typed_array: TypedArray, pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number) {
-
-    // JavaScript typed arrays are array-like objects and provide a mechanism for accessing
-    // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays
-    // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
-    //  is an object representing a chunk of data; it has no format to speak of, and offers no
-    // mechanism for accessing its contents. In order to access the memory contained in a buffer,
-    // you need to use a view. A view provides a context - that is, a data type, starting offset,
-    // and number of elements - that turns the data into an actual typed array.
-    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
-    if (has_backing_array_buffer(typed_array) && typed_array.BYTES_PER_ELEMENT) {
-        // Some sanity checks of what is being asked of us
-        // lets play it safe and throw an error here instead of assuming to much.
-        // Better safe than sorry later
-        if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT)
-            throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'");
-
-        // how much space we have to work with
-        let num_of_bytes = (end - begin) * bytes_per_element;
-        // how much typed buffer space are we talking about
-        const view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT;
-        // only use what is needed.
-        if (num_of_bytes > view_bytes)
-            num_of_bytes = view_bytes;
-
-        // offset index into the view
-        const offset = begin * bytes_per_element;
-
-        // Create a view over the heap pointed to by the pinned array address
-        const heapBytes = new Uint8Array(Module.HEAPU8.buffer, <any>pinned_array + offset, num_of_bytes);
-        // Copy the bytes of the typed array to the heap.
-        heapBytes.set(new Uint8Array(typed_array.buffer, typed_array.byteOffset, num_of_bytes));
-
-        return num_of_bytes;
-    }
-    else {
-        throw new Error("Object '" + typed_array + "' is not a typed array");
-    }
-
-}
-
-// Copy the pinned array address from pinned_array allocated on the heap to the typed array.
-//      address of managed pinned array -> copy from heap -> typed array memory
-function typedarray_copy_from(typed_array: TypedArray, pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number) {
-
-    // JavaScript typed arrays are array-like objects and provide a mechanism for accessing
-    // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays
-    // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
-    //  is an object representing a chunk of data; it has no format to speak of, and offers no
-    // mechanism for accessing its contents. In order to access the memory contained in a buffer,
-    // you need to use a view. A view provides a context - that is, a data type, starting offset,
-    // and number of elements - that turns the data into an actual typed array.
-    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
-    if (has_backing_array_buffer(typed_array) && typed_array.BYTES_PER_ELEMENT) {
-        // Some sanity checks of what is being asked of us
-        // lets play it safe and throw an error here instead of assuming to much.
-        // Better safe than sorry later
-        if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT)
-            throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'");
-
-        // how much space we have to work with
-        let num_of_bytes = (end - begin) * bytes_per_element;
-        // how much typed buffer space are we talking about
-        const view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT;
-        // only use what is needed.
-        if (num_of_bytes > view_bytes)
-            num_of_bytes = view_bytes;
-
-        // Create a new view for mapping
-        const typedarrayBytes = new Uint8Array(typed_array.buffer, 0, num_of_bytes);
-        // offset index into the view
-        const offset = begin * bytes_per_element;
-        // Set view bytes to value from HEAPU8
-        typedarrayBytes.set(Module.HEAPU8.subarray(<any>pinned_array + offset, <any>pinned_array + offset + num_of_bytes));
-        return num_of_bytes;
-    }
-    else {
-        throw new Error("Object '" + typed_array + "' is not a typed array");
-    }
-}
-
-export function mono_wasm_typed_array_copy_to_ref(js_handle: JSHandle, pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
-    const resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
-    try {
-        const js_obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
-        if (is_nullish(js_obj)) {
-            wrap_error_root(is_exception, "ERR07: Invalid JS object handle '" + js_handle + "'", resultRoot);
-            return;
-        }
-
-        const res = typedarray_copy_to(js_obj, pinned_array, begin, end, bytes_per_element);
-        // FIXME: We should just return an int
-        // returns num_of_bytes boxed
-        js_to_mono_obj_root(res, resultRoot, false);
-    } catch (exc) {
-        wrap_error_root(is_exception, String(exc), resultRoot);
-    } finally {
-        resultRoot.release();
-    }
-}
-
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export function mono_wasm_typed_array_from_ref(pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number, type: number, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
-    const resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
-    try {
-        const res = typed_array_from(pinned_array, begin, end, bytes_per_element, type);
-        // returns JS typed array like Int8Array, to be wraped with JSObject proxy
-        js_to_mono_obj_root(res, resultRoot, true);
-    } catch (exc) {
-        wrap_error_root(is_exception, String(exc), resultRoot);
-    } finally {
-        resultRoot.release();
-    }
-}
-
-export function mono_wasm_typed_array_copy_from_ref(js_handle: JSHandle, pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
-    const resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
-    try {
-        const js_obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
-        if (is_nullish(js_obj)) {
-            wrap_error_root(is_exception, "ERR08: Invalid JS object handle '" + js_handle + "'", resultRoot);
-            return;
-        }
-
-        const res = typedarray_copy_from(js_obj, pinned_array, begin, end, bytes_per_element);
-        // FIXME: We should just return an int
-        // returns num_of_bytes boxed
-        js_to_mono_obj_root(res, resultRoot, false);
-    } catch (exc) {
-        wrap_error_root(is_exception, String(exc), resultRoot);
-    } finally {
-        resultRoot.release();
-    }
-}
-
-export function has_backing_array_buffer(js_obj: TypedArray): boolean {
-    return typeof SharedArrayBuffer !== "undefined"
-        ? js_obj.buffer instanceof ArrayBuffer || js_obj.buffer instanceof SharedArrayBuffer
-        : js_obj.buffer instanceof ArrayBuffer;
-}
-
-// @bytes must be a typed array. space is allocated for it in the native heap
-//  and it is copied to that location. returns the address of the allocation.
-export function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr {
-    const memoryOffset = Module._malloc(bytes.length);
-    const heapBytes = new Uint8Array(Module.HEAPU8.buffer, <any>memoryOffset, bytes.length);
-    heapBytes.set(bytes);
-    return memoryOffset;
-}
diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
new file mode 100644 (file)
index 0000000..2c815a3
--- /dev/null
@@ -0,0 +1,117 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+/* eslint-disable no-undef */
+
+"use strict";
+
+#if USE_PTHREADS
+const usePThreads = `true`;
+const isPThread = `ENVIRONMENT_IS_PTHREAD`;
+#else
+const usePThreads = `false`;
+const isPThread = `false`;
+#endif
+
+const DotnetSupportLib = {
+    $DOTNET: {},
+    // these lines will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE
+    // we replace implementation of fetch
+    // replacement of require is there for consistency with ES6 code
+    $DOTNET__postset: `
+let __dotnet_replacement_PThread = ${usePThreads} ? {} : undefined;
+if (${usePThreads}) {
+    __dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
+    __dotnet_replacement_PThread.threadInitTLS = PThread.threadInitTLS;
+}
+let __dotnet_replacements = {scriptUrl: undefined, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
+if (ENVIRONMENT_IS_NODE) {
+    __dotnet_replacements.requirePromise = Promise.resolve(require);
+}
+let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports(
+    { isESM:false, isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, quit_, ExitStatus, requirePromise:Promise.resolve(require)},
+    { mono:MONO, binding:BINDING, internal:INTERNAL, module:Module, marshaled_exports: EXPORTS, marshaled_imports: IMPORTS  },
+    __dotnet_replacements);
+updateGlobalBufferAndViews = __dotnet_replacements.updateGlobalBufferAndViews;
+var fetch = __dotnet_replacements.fetch;
+_scriptDir = __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory;
+if (ENVIRONMENT_IS_NODE) {
+    __dotnet_replacements.requirePromise.then(someRequire => {
+        require = someRequire;
+    });
+}
+var noExitRuntime = __dotnet_replacements.noExitRuntime;
+if (${usePThreads}) {
+    PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;
+    PThread.threadInitTLS = __dotnet_replacements.pthreadReplacements.threadInitTS;
+}
+`,
+};
+
+// the methods would be visible to EMCC linker
+// --- keep in sync with exports.ts ---
+const linked_functions = [
+    // mini-wasm.c
+    "mono_set_timeout",
+
+    // mini-wasm-debugger.c
+    "mono_wasm_asm_loaded",
+    "mono_wasm_fire_debugger_agent_message",
+    "mono_wasm_debugger_log",
+    "mono_wasm_add_dbg_command_received",
+
+    // mono-threads-wasm.c
+    "schedule_background_exec",
+
+    // driver.c
+    "mono_wasm_invoke_js_blazor",
+    "mono_wasm_trace_logger",
+    "mono_wasm_set_entrypoint_breakpoint",
+    "mono_wasm_event_pipe_early_startup_callback",
+
+    // corebindings.c
+    "mono_wasm_invoke_js_with_args_ref",
+    "mono_wasm_get_object_property_ref",
+    "mono_wasm_set_object_property_ref",
+    "mono_wasm_get_by_index_ref",
+    "mono_wasm_set_by_index_ref",
+    "mono_wasm_get_global_object_ref",
+    "mono_wasm_create_cs_owned_object_ref",
+    "mono_wasm_release_cs_owned_object",
+    "mono_wasm_typed_array_to_array_ref",
+    "mono_wasm_typed_array_from_ref",
+    "mono_wasm_compile_function_ref",
+    "mono_wasm_bind_js_function",
+    "mono_wasm_invoke_bound_function",
+    "mono_wasm_bind_cs_function",
+    "mono_wasm_marshal_promise",
+
+    // pal_icushim_static.c
+    "mono_wasm_load_icu_data",
+    "mono_wasm_get_icudt_name",
+
+    // pal_crypto_webworker.c
+    "dotnet_browser_can_use_subtle_crypto_impl",
+    "dotnet_browser_simple_digest_hash",
+    "dotnet_browser_sign",
+    "dotnet_browser_encrypt_decrypt",
+    "dotnet_browser_derive_bits",
+
+    #if USE_PTHREADS
+    /// mono-threads-wasm.c
+    "mono_wasm_pthread_on_pthread_attached",
+    /// diagnostics_server.c
+    "mono_wasm_diagnostic_server_on_server_thread_created",
+    "mono_wasm_diagnostic_server_on_runtime_server_init",
+    "mono_wasm_diagnostic_server_stream_signal_work_available",
+    #endif
+];
+
+// -- this javascript file is evaluated by emcc during compilation! --
+// we generate simple proxy for each exported function so that emcc will include them in the final output
+for (let linked_function of linked_functions) {
+    const fn_template = `return __dotnet_runtime.__linker_exports.${linked_function}.apply(__dotnet_runtime, arguments)`;
+    DotnetSupportLib[linked_function] = new Function(fn_template);
+}
+
+autoAddDeps(DotnetSupportLib, "$DOTNET");
+mergeInto(LibraryManager.library, DotnetSupportLib);
index 11bd47e..1d4267a 100644 (file)
@@ -26,9 +26,7 @@ extern void mono_wasm_get_global_object_ref (MonoString **global_name, int *is_e
 extern void mono_wasm_release_cs_owned_object (int js_handle);
 extern void mono_wasm_create_cs_owned_object_ref (MonoString **core_name, MonoArray **args, int *is_exception, MonoObject** result);
 extern void mono_wasm_typed_array_to_array_ref (int js_handle, int *is_exception, MonoObject **result);
-extern void mono_wasm_typed_array_copy_to_ref (int js_handle, int ptr, int begin, int end, int bytes_per_element, int *is_exception, MonoObject** result);
 extern void mono_wasm_typed_array_from_ref (int ptr, int begin, int end, int bytes_per_element, int type, int *is_exception, MonoObject** result);
-extern void mono_wasm_typed_array_copy_from_ref (int js_handle, int ptr, int begin, int end, int bytes_per_element, int *is_exception, MonoObject** result);
 
 extern void mono_wasm_bind_js_function(MonoString **function_name, MonoString **module_name, void *signature, int* function_js_handle, int *is_exception, MonoObject **result);
 extern void mono_wasm_invoke_bound_function(int function_js_handle, void *data);
@@ -47,9 +45,7 @@ void core_initialize_internals ()
        mono_add_internal_call ("Interop/Runtime::CreateCSOwnedObjectRef", mono_wasm_create_cs_owned_object_ref);
        mono_add_internal_call ("Interop/Runtime::ReleaseCSOwnedObject", mono_wasm_release_cs_owned_object);
        mono_add_internal_call ("Interop/Runtime::TypedArrayToArrayRef", mono_wasm_typed_array_to_array_ref);
-       mono_add_internal_call ("Interop/Runtime::TypedArrayCopyToRef", mono_wasm_typed_array_copy_to_ref);
        mono_add_internal_call ("Interop/Runtime::TypedArrayFromRef", mono_wasm_typed_array_from_ref);
-       mono_add_internal_call ("Interop/Runtime::TypedArrayCopyFromRef", mono_wasm_typed_array_copy_from_ref);
 
        mono_add_internal_call ("Interop/Runtime::BindJSFunction", mono_wasm_bind_js_function);
        mono_add_internal_call ("Interop/Runtime::InvokeJSFunction", mono_wasm_invoke_bound_function);
diff --git a/src/mono/wasm/runtime/corebindings.ts b/src/mono/wasm/runtime/corebindings.ts
deleted file mode 100644 (file)
index 0a843c5..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-import { JSHandle, GCHandle, MonoObjectRef } from "./types";
-import { PromiseController } from "./promise-controller";
-import { runtimeHelpers } from "./imports";
-
-// TODO replace all of this with [JSExport]
-const fn_signatures: [jsname: string, csname: string, signature: string/*ArgsMarshalString*/][] = [
-    ["_get_cs_owned_object_by_js_handle_ref", "GetCSOwnedObjectByJSHandleRef", "iim"],
-    ["_get_cs_owned_object_js_handle_ref", "GetCSOwnedObjectJSHandleRef", "mi"],
-    ["_try_get_cs_owned_object_js_handle_ref", "TryGetCSOwnedObjectJSHandleRef", "mi"],
-    ["_create_cs_owned_proxy_ref", "CreateCSOwnedProxyRef", "iiim"],
-
-    ["_get_js_owned_object_by_gc_handle_ref", "GetJSOwnedObjectByGCHandleRef", "im"],
-    ["_get_js_owned_object_gc_handle_ref", "GetJSOwnedObjectGCHandleRef", "m"],
-    ["_release_js_owned_object_by_gc_handle", "ReleaseJSOwnedObjectByGCHandle", "i"],
-
-    ["_create_tcs", "CreateTaskSource", ""],
-    ["_create_task_callback", "CreateTaskCallback", ""],
-    ["_set_tcs_result_ref", "SetTaskSourceResultRef", "iR"],
-    ["_set_tcs_failure", "SetTaskSourceFailure", "is"],
-    ["_get_tcs_task_ref", "GetTaskSourceTaskRef", "im"],
-    ["_task_from_result_ref", "TaskFromResultRef", "Rm"],
-    ["_setup_js_cont_ref", "SetupJSContinuationRef", "mo"],
-
-    ["_object_to_string_ref", "ObjectToStringRef", "m"],
-    ["_get_date_value_ref", "GetDateValueRef", "m"],
-    ["_create_date_time_ref", "CreateDateTimeRef", "dm"],
-    ["_create_uri_ref", "CreateUriRef", "sm"],
-    ["_is_simple_array_ref", "IsSimpleArrayRef", "m"],
-];
-
-export interface t_CSwraps {
-    // BINDING
-    _get_cs_owned_object_by_js_handle_ref(jsHandle: JSHandle, shouldAddInflight: 0 | 1, result: MonoObjectRef): void;
-    _get_cs_owned_object_js_handle_ref(obj: MonoObjectRef, shouldAddInflight: 0 | 1): JSHandle;
-    _try_get_cs_owned_object_js_handle_ref(obj: MonoObjectRef, shouldAddInflight: 0 | 1): JSHandle;
-    _create_cs_owned_proxy_ref(jsHandle: JSHandle, mappedType: number, shouldAddInflight: 0 | 1, result: MonoObjectRef): void;
-
-    _get_js_owned_object_by_gc_handle_ref(gcHandle: GCHandle, result: MonoObjectRef): void;
-    _get_js_owned_object_gc_handle_ref(obj: MonoObjectRef): GCHandle
-    _release_js_owned_object_by_gc_handle(gcHandle: GCHandle): void;
-
-    _create_tcs(): GCHandle;
-    _set_tcs_result_ref(gcHandle: GCHandle, result: any): void
-    _set_tcs_failure(gcHandle: GCHandle, result: string): void
-    _get_tcs_task_ref(gcHandle: GCHandle, result: MonoObjectRef): void;
-    _task_from_result_ref(value: any, result: MonoObjectRef): void;
-    _setup_js_cont_ref(task: MonoObjectRef, continuation: PromiseController): void;
-
-    _object_to_string_ref(obj: MonoObjectRef): string;
-    _get_date_value_ref(obj: MonoObjectRef): number;
-    _create_date_time_ref(ticks: number, result: MonoObjectRef): void;
-    _create_uri_ref(uri: string, result: MonoObjectRef): void;
-    _is_simple_array_ref(obj: MonoObjectRef): boolean;
-
-    _create_task_callback(): GCHandle;
-}
-
-const wrapped_cs_functions: t_CSwraps = <any>{};
-for (const sig of fn_signatures) {
-    const wf: any = wrapped_cs_functions;
-    // lazy init on first run
-    wf[sig[0]] = function (...args: any[]) {
-        const fce = runtimeHelpers.bind_runtime_method(sig[1], sig[2]);
-        wf[sig[0]] = fce;
-        return fce(...args);
-    };
-}
-
-export default wrapped_cs_functions;
index 317ad12..2bfe354 100644 (file)
@@ -2,7 +2,6 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import {
-    mono_assert,
     MonoArray, MonoAssembly, MonoClass,
     MonoMethod, MonoObject, MonoString,
     MonoType, MonoObjectRef, MonoStringRef
@@ -11,87 +10,85 @@ import { Module } from "./imports";
 import { JSMarshalerArguments } from "./marshal";
 import { VoidPtr, CharPtrPtr, Int32Ptr, CharPtr, ManagedPointer } from "./types/emscripten";
 
-const fn_signatures: [ident: string, returnType: string | null, argTypes?: string[], opts?: any][] = [
+type SigLine = [lazy: boolean, name: string, returnType: string | null, argTypes?: string[], opts?: any];
+
+// when the method is assigned/cached at usage, instead of being invoked directly from cwraps, it can't be marked lazy, because it would be re-bound on each call
+const fn_signatures: SigLine[] = [
     // MONO
-    ["mono_wasm_register_root", "number", ["number", "number", "string"]],
-    ["mono_wasm_deregister_root", null, ["number"]],
-    ["mono_wasm_string_get_data", null, ["number", "number", "number", "number"]],
-    ["mono_wasm_string_get_data_ref", null, ["number", "number", "number", "number"]],
-    ["mono_wasm_set_is_debugger_attached", "void", ["bool"]],
-    ["mono_wasm_send_dbg_command", "bool", ["number", "number", "number", "number", "number"]],
-    ["mono_wasm_send_dbg_command_with_parms", "bool", ["number", "number", "number", "number", "number", "number", "string"]],
-    ["mono_wasm_setenv", null, ["string", "string"]],
-    ["mono_wasm_parse_runtime_options", null, ["number", "number"]],
-    ["mono_wasm_strdup", "number", ["string"]],
-    ["mono_background_exec", null, []],
-    ["mono_set_timeout_exec", null, []],
-    ["mono_wasm_load_icu_data", "number", ["number"]],
-    ["mono_wasm_get_icudt_name", "string", ["string"]],
-    ["mono_wasm_add_assembly", "number", ["string", "number", "number"]],
-    ["mono_wasm_add_satellite_assembly", "void", ["string", "string", "number", "number"]],
-    ["mono_wasm_load_runtime", null, ["string", "number"]],
-    ["mono_wasm_exit", null, ["number"]],
-    ["mono_wasm_change_debugger_log_level", "void", ["number"]],
+    [true, "mono_wasm_register_root", "number", ["number", "number", "string"]],
+    [true, "mono_wasm_deregister_root", null, ["number"]],
+    [true, "mono_wasm_string_get_data", null, ["number", "number", "number", "number"]],
+    [true, "mono_wasm_string_get_data_ref", null, ["number", "number", "number", "number"]],
+    [true, "mono_wasm_set_is_debugger_attached", "void", ["bool"]],
+    [true, "mono_wasm_send_dbg_command", "bool", ["number", "number", "number", "number", "number"]],
+    [true, "mono_wasm_send_dbg_command_with_parms", "bool", ["number", "number", "number", "number", "number", "number", "string"]],
+    [true, "mono_wasm_setenv", null, ["string", "string"]],
+    [true, "mono_wasm_parse_runtime_options", null, ["number", "number"]],
+    [true, "mono_wasm_strdup", "number", ["string"]],
+    [true, "mono_background_exec", null, []],
+    [true, "mono_set_timeout_exec", null, []],
+    [true, "mono_wasm_load_icu_data", "number", ["number"]],
+    [true, "mono_wasm_get_icudt_name", "string", ["string"]],
+    [false, "mono_wasm_add_assembly", "number", ["string", "number", "number"]],
+    [true, "mono_wasm_add_satellite_assembly", "void", ["string", "string", "number", "number"]],
+    [false, "mono_wasm_load_runtime", null, ["string", "number"]],
+    [true, "mono_wasm_change_debugger_log_level", "void", ["number"]],
 
     // BINDING
-    ["mono_wasm_get_corlib", "number", []],
-    ["mono_wasm_assembly_load", "number", ["string"]],
-    ["mono_wasm_find_corlib_class", "number", ["string", "string"]],
-    ["mono_wasm_assembly_find_class", "number", ["number", "string", "string"]],
-    ["mono_wasm_runtime_run_module_cctor", "void", ["number"]],
-    ["mono_wasm_find_corlib_type", "number", ["string", "string"]],
-    ["mono_wasm_assembly_find_type", "number", ["number", "string", "string"]],
-    ["mono_wasm_assembly_find_method", "number", ["number", "string", "number"]],
-    ["mono_wasm_invoke_method", "number", ["number", "number", "number", "number"]],
-    ["mono_wasm_invoke_method_ref", "void", ["number", "number", "number", "number", "number"]],
-    ["mono_wasm_string_get_utf8", "number", ["number"]],
-    ["mono_wasm_string_from_utf16_ref", "void", ["number", "number", "number"]],
-    ["mono_wasm_get_obj_type", "number", ["number"]],
-    ["mono_wasm_array_length", "number", ["number"]],
-    ["mono_wasm_array_get", "number", ["number", "number"]],
-    ["mono_wasm_array_get_ref", "void", ["number", "number", "number"]],
-    ["mono_wasm_obj_array_new", "number", ["number"]],
-    ["mono_wasm_obj_array_new_ref", "void", ["number", "number"]],
-    ["mono_wasm_obj_array_set", "void", ["number", "number", "number"]],
-    ["mono_wasm_obj_array_set_ref", "void", ["number", "number", "number"]],
-    ["mono_wasm_register_bundled_satellite_assemblies", "void", []],
-    ["mono_wasm_try_unbox_primitive_and_get_type_ref", "number", ["number", "number", "number"]],
-    ["mono_wasm_box_primitive_ref", "void", ["number", "number", "number", "number"]],
-    ["mono_wasm_intern_string_ref", "void", ["number"]],
-    ["mono_wasm_assembly_get_entry_point", "number", ["number"]],
-    ["mono_wasm_get_delegate_invoke_ref", "number", ["number"]],
-    ["mono_wasm_string_array_new_ref", "void", ["number", "number"]],
-    ["mono_wasm_typed_array_new_ref", "void", ["number", "number", "number", "number", "number"]],
-    ["mono_wasm_class_get_type", "number", ["number"]],
-    ["mono_wasm_type_get_class", "number", ["number"]],
-    ["mono_wasm_get_type_name", "string", ["number"]],
-    ["mono_wasm_get_type_aqn", "string", ["number"]],
+    [true, "mono_wasm_get_corlib", "number", []],
+    [true, "mono_wasm_assembly_load", "number", ["string"]],
+    [true, "mono_wasm_find_corlib_class", "number", ["string", "string"]],
+    [true, "mono_wasm_assembly_find_class", "number", ["number", "string", "string"]],
+    [true, "mono_wasm_runtime_run_module_cctor", "void", ["number"]],
+    [true, "mono_wasm_find_corlib_type", "number", ["string", "string"]],
+    [true, "mono_wasm_assembly_find_type", "number", ["number", "string", "string"]],
+    [true, "mono_wasm_assembly_find_method", "number", ["number", "string", "number"]],
+    [true, "mono_wasm_invoke_method", "number", ["number", "number", "number", "number"]],
+    [false, "mono_wasm_invoke_method_ref", "void", ["number", "number", "number", "number", "number"]],
+    [true, "mono_wasm_string_get_utf8", "number", ["number"]],
+    [true, "mono_wasm_string_from_utf16_ref", "void", ["number", "number", "number"]],
+    [true, "mono_wasm_get_obj_type", "number", ["number"]],
+    [true, "mono_wasm_array_length", "number", ["number"]],
+    [true, "mono_wasm_array_get", "number", ["number", "number"]],
+    [true, "mono_wasm_array_get_ref", "void", ["number", "number", "number"]],
+    [false, "mono_wasm_obj_array_new", "number", ["number"]],
+    [false, "mono_wasm_obj_array_new_ref", "void", ["number", "number"]],
+    [false, "mono_wasm_obj_array_set", "void", ["number", "number", "number"]],
+    [false, "mono_wasm_obj_array_set_ref", "void", ["number", "number", "number"]],
+    [true, "mono_wasm_register_bundled_satellite_assemblies", "void", []],
+    [false, "mono_wasm_try_unbox_primitive_and_get_type_ref", "number", ["number", "number", "number"]],
+    [true, "mono_wasm_box_primitive_ref", "void", ["number", "number", "number", "number"]],
+    [true, "mono_wasm_intern_string_ref", "void", ["number"]],
+    [true, "mono_wasm_assembly_get_entry_point", "number", ["number"]],
+    [true, "mono_wasm_get_delegate_invoke_ref", "number", ["number"]],
+    [true, "mono_wasm_string_array_new_ref", "void", ["number", "number"]],
+    [true, "mono_wasm_typed_array_new_ref", "void", ["number", "number", "number", "number", "number"]],
+    [true, "mono_wasm_class_get_type", "number", ["number"]],
+    [true, "mono_wasm_type_get_class", "number", ["number"]],
+    [true, "mono_wasm_get_type_name", "string", ["number"]],
+    [true, "mono_wasm_get_type_aqn", "string", ["number"]],
 
     // MONO.diagnostics
-    ["mono_wasm_event_pipe_enable", "bool", ["string", "number", "number", "string", "bool", "number"]],
-    ["mono_wasm_event_pipe_session_start_streaming", "bool", ["number"]],
-    ["mono_wasm_event_pipe_session_disable", "bool", ["number"]],
-    ["mono_wasm_diagnostic_server_create_thread", "bool", ["string", "number"]],
-    ["mono_wasm_diagnostic_server_thread_attach_to_runtime", "void", []],
-    ["mono_wasm_diagnostic_server_post_resume_runtime", "void", []],
-    ["mono_wasm_diagnostic_server_create_stream", "number", []],
+    [true, "mono_wasm_event_pipe_enable", "bool", ["string", "number", "string", "bool", "number"]],
+    [true, "mono_wasm_event_pipe_session_start_streaming", "bool", ["number"]],
+    [true, "mono_wasm_event_pipe_session_disable", "bool", ["number"]],
 
     //DOTNET
-    ["mono_wasm_string_from_js", "number", ["string"]],
+    [true, "mono_wasm_string_from_js", "number", ["string"]],
 
     //INTERNAL
-    ["mono_wasm_exit", "void", ["number"]],
-    ["mono_wasm_set_main_args", "void", ["number", "number"]],
-    ["mono_wasm_enable_on_demand_gc", "void", ["number"]],
-    ["mono_profiler_init_aot", "void", ["number"]],
-    ["mono_wasm_exec_regression", "number", ["number", "string"]],
-    ["mono_wasm_invoke_method_bound", "number", ["number", "number"]],
-    ["mono_wasm_write_managed_pointer_unsafe", "void", ["number", "number"]],
-    ["mono_wasm_copy_managed_pointer", "void", ["number", "number"]],
-    ["mono_wasm_i52_to_f64", "number", ["number", "number"]],
-    ["mono_wasm_u52_to_f64", "number", ["number", "number"]],
-    ["mono_wasm_f64_to_i52", "number", ["number", "number"]],
-    ["mono_wasm_f64_to_u52", "number", ["number", "number"]],
+    [false, "mono_wasm_exit", "void", ["number"]],
+    [true, "mono_wasm_set_main_args", "void", ["number", "number"]],
+    [false, "mono_wasm_enable_on_demand_gc", "void", ["number"]],
+    [false, "mono_profiler_init_aot", "void", ["number"]],
+    [false, "mono_wasm_exec_regression", "number", ["number", "string"]],
+    [false, "mono_wasm_invoke_method_bound", "number", ["number", "number"]],
+    [true, "mono_wasm_write_managed_pointer_unsafe", "void", ["number", "number"]],
+    [true, "mono_wasm_copy_managed_pointer", "void", ["number", "number"]],
+    [true, "mono_wasm_i52_to_f64", "number", ["number", "number"]],
+    [true, "mono_wasm_u52_to_f64", "number", ["number", "number"]],
+    [true, "mono_wasm_f64_to_i52", "number", ["number", "number"]],
+    [true, "mono_wasm_f64_to_u52", "number", ["number", "number"]],
 ];
 
 export interface t_Cwraps {
@@ -204,25 +201,8 @@ export interface t_Cwraps {
 }
 
 const wrapped_c_functions: t_Cwraps = <any>{};
-for (const sig of fn_signatures) {
-    const wf: any = wrapped_c_functions;
-    // lazy init on first run
-    wf[sig[0]] = function (...args: any[]) {
-        const fce = Module.cwrap(sig[0], sig[1], sig[2], sig[3]);
-        wf[sig[0]] = fce;
-        return fce(...args);
-    };
-}
 
 export default wrapped_c_functions;
-export function wrap_c_function(name: string): Function {
-    const wf: any = wrapped_c_functions;
-    const sig = fn_signatures.find(s => s[0] === name);
-    mono_assert(sig, () => `Function ${name} not found`);
-    const fce = Module.cwrap(sig[0], sig[1], sig[2], sig[3]);
-    wf[sig[0]] = fce;
-    return fce;
-}
 
 // see src/mono/wasm/driver.c I52_ERROR_xxx
 export const enum I52Error {
@@ -230,3 +210,21 @@ export const enum I52Error {
     NON_INTEGRAL = 1,
     OUT_OF_RANGE = 2,
 }
+
+export function init_c_exports(): void {
+    for (const sig of fn_signatures) {
+        const wf: any = wrapped_c_functions;
+        const [lazy, name, returnType, argTypes, opts] = sig;
+        if (lazy) {
+            // lazy init on first run
+            wf[name] = function (...args: any[]) {
+                const fce = Module.cwrap(name, returnType, argTypes, opts);
+                wf[name] = fce;
+                return fce(...args);
+            };
+        } else {
+            const fce = Module.cwrap(name, returnType, argTypes, opts);
+            wf[name] = fce;
+        }
+    }
+}
\ No newline at end of file
index 5e5c5a5..f51c7a4 100644 (file)
@@ -61,6 +61,8 @@ declare interface EmscriptenModule {
 }
 declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array;
 
+declare function mono_wasm_runtime_ready(): void;
+
 /**
  * Allocates a block of memory that can safely contain pointers into the managed heap.
  * The result object has get(index) and set(index, value) methods that can be used to retrieve and store managed pointers.
@@ -128,6 +130,47 @@ interface WasmRoot<T extends MonoObject> {
     toString(): string;
 }
 
+interface IDisposable {
+    dispose(): void;
+    get isDisposed(): boolean;
+}
+declare class ManagedObject implements IDisposable {
+    dispose(): void;
+    get isDisposed(): boolean;
+    toString(): string;
+}
+declare class ManagedError extends Error implements IDisposable {
+    constructor(message: string);
+    get stack(): string | undefined;
+    dispose(): void;
+    get isDisposed(): boolean;
+    toString(): string;
+}
+declare const enum MemoryViewType {
+    Byte = 0,
+    Int32 = 1,
+    Double = 2
+}
+interface IMemoryView {
+    /**
+     * copies elements from provided source to the wasm memory.
+     * target has to have the elements of the same type as the underlying C# array.
+     * same as TypedArray.set()
+     */
+    set(source: TypedArray, targetOffset?: number): void;
+    /**
+     * copies elements from wasm memory to provided target.
+     * target has to have the elements of the same type as the underlying C# array.
+     */
+    copyTo(target: TypedArray, sourceOffset?: number): void;
+    /**
+     * same as TypedArray.slice()
+     */
+    slice(start?: number, end?: number): TypedArray;
+    get length(): number;
+    get byteLength(): number;
+}
+
 interface MonoObject extends ManagedPointer {
     __brandMonoObject: "MonoObject";
 }
@@ -245,6 +288,19 @@ interface LoadingResource {
     response: Promise<Response>;
 }
 declare type EventPipeSessionID = bigint;
+interface DotnetPublicAPI {
+    MONO: MONOType;
+    BINDING: BINDINGType;
+    INTERNAL: any;
+    EXPORTS: any;
+    IMPORTS: any;
+    Module: EmscriptenModule;
+    RuntimeId: number;
+    RuntimeBuildInfo: {
+        ProductVersion: string;
+        Configuration: string;
+    };
+}
 
 declare const eventLevel: {
     readonly LogAlways: 0;
@@ -291,57 +347,9 @@ interface Diagnostics {
     getStartupSessions(): (EventPipeSession | null)[];
 }
 
-declare function mono_wasm_runtime_ready(): void;
-
-declare function mono_wasm_setenv(name: string, value: string): void;
-declare function mono_wasm_load_runtime(unused?: string, debug_level?: number): void;
-declare function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean;
-/**
- * Loads the mono config file (typically called mono-config.json) asynchroniously
- * Note: the run dependencies are so emsdk actually awaits it in order.
- *
- * @param {string} configFilePath - relative path to the config file
- * @throws Will throw an error if the config file loading fails
- */
-declare function mono_wasm_load_config(configFilePath: string): Promise<void>;
-/**
-* @deprecated
-*/
-declare function mono_load_runtime_and_bcl_args(cfg?: MonoConfig | MonoConfigError | undefined): Promise<void>;
-
 declare function mono_wasm_load_icu_data(offset: VoidPtr): boolean;
 
-/**
- * @deprecated Not GC or thread safe
- */
-declare function conv_string(mono_obj: MonoString): string | null;
-declare function conv_string_root(root: WasmRoot<MonoString>): string | null;
-declare function js_string_to_mono_string_root(string: string, result: WasmRoot<MonoString>): void;
-/**
- * @deprecated Not GC or thread safe
- */
-declare function js_string_to_mono_string(string: string): MonoString;
-
-/**
- * @deprecated Not GC or thread safe. For blazor use only
- */
-declare function js_to_mono_obj(js_obj: any): MonoObject;
-declare function js_to_mono_obj_root(js_obj: any, result: WasmRoot<MonoObject>, should_add_in_flight: boolean): void;
-declare function js_typed_array_to_array_root(js_obj: any, result: WasmRoot<MonoArray>): void;
-/**
- * @deprecated Not GC or thread safe
- */
-declare function js_typed_array_to_array(js_obj: any): MonoArray;
-
-declare function unbox_mono_obj(mono_obj: MonoObject): any;
-declare function unbox_mono_obj_root(root: WasmRoot<any>): any;
-declare function mono_array_to_js_array(mono_array: MonoArray): any[] | null;
-declare function mono_array_root_to_js_array(arrayRoot: WasmRoot<MonoArray>): any[] | null;
-
-declare function mono_bind_static_method(fqn: string, signature?: string): Function;
-declare function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: string): number;
-
-declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr;
+declare function mono_wasm_get_assembly_exports(assembly: string): Promise<any>;
 
 declare type _MemOffset = number | VoidPtr | NativePointer | ManagedPointer;
 declare type _NumberOrPointer = number | VoidPtr | NativePointer | ManagedPointer;
@@ -381,54 +389,101 @@ declare function getU52(offset: _MemOffset): number;
 declare function getI64Big(offset: _MemOffset): bigint;
 declare function getF32(offset: _MemOffset): number;
 declare function getF64(offset: _MemOffset): number;
+declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr;
 
 declare function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise<void>;
 declare function mono_run_main(main_assembly_name: string, args: string[]): Promise<number>;
 
-interface IDisposable {
-    dispose(): void;
-    get isDisposed(): boolean;
-}
-declare class ManagedObject implements IDisposable {
-    dispose(): void;
-    get isDisposed(): boolean;
-    toString(): string;
-}
-declare class ManagedError extends Error implements IDisposable {
-    constructor(message: string);
-    get stack(): string | undefined;
-    dispose(): void;
-    get isDisposed(): boolean;
-    toString(): string;
-}
-declare const enum MemoryViewType {
-    Byte = 0,
-    Int32 = 1,
-    Double = 2
-}
-interface IMemoryView {
+declare function mono_wasm_setenv(name: string, value: string): void;
+declare function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean;
+/**
+ * Loads the mono config file (typically called mono-config.json) asynchroniously
+ * Note: the run dependencies are so emsdk actually awaits it in order.
+ *
+ * @param {string} configFilePath - relative path to the config file
+ * @throws Will throw an error if the config file loading fails
+ */
+declare function mono_wasm_load_config(configFilePath: string): Promise<void>;
+/**
+* @deprecated
+*/
+declare function mono_load_runtime_and_bcl_args(cfg?: MonoConfig | MonoConfigError | undefined): Promise<void>;
+
+/**
+ * @deprecated Not GC or thread safe
+ */
+declare function conv_string(mono_obj: MonoString): string | null;
+declare function conv_string_root(root: WasmRoot<MonoString>): string | null;
+declare function js_string_to_mono_string_root(string: string, result: WasmRoot<MonoString>): void;
+/**
+ * @deprecated Not GC or thread safe
+ */
+declare function js_string_to_mono_string(string: string): MonoString;
+
+declare function unbox_mono_obj(mono_obj: MonoObject): any;
+declare function unbox_mono_obj_root(root: WasmRoot<any>): any;
+declare function mono_array_to_js_array(mono_array: MonoArray): any[] | null;
+declare function mono_array_root_to_js_array(arrayRoot: WasmRoot<MonoArray>): any[] | null;
+
+/**
+ * @deprecated Not GC or thread safe. For blazor use only
+ */
+declare function js_to_mono_obj(js_obj: any): MonoObject;
+declare function js_to_mono_obj_root(js_obj: any, result: WasmRoot<MonoObject>, should_add_in_flight: boolean): void;
+declare function js_typed_array_to_array_root(js_obj: any, result: WasmRoot<MonoArray>): void;
+/**
+ * @deprecated Not GC or thread safe
+ */
+declare function js_typed_array_to_array(js_obj: any): MonoArray;
+
+declare function mono_bind_static_method(fqn: string, signature?: string): Function;
+declare function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: string): number;
+
+declare type BINDINGType = {
+    bind_static_method: typeof mono_bind_static_method;
+    call_assembly_entry_point: typeof mono_call_assembly_entry_point;
     /**
-     * copies elements from provided source to the wasm memory.
-     * target has to have the elements of the same type as the underlying C# array.
-     * same as TypedArray.set()
+     * @deprecated Not GC or thread safe
      */
-    set(source: TypedArray, targetOffset?: number): void;
+    mono_obj_array_new: (size: number) => MonoArray;
     /**
-     * copies elements from wasm memory to provided target.
-     * target has to have the elements of the same type as the underlying C# array.
+     * @deprecated Not GC or thread safe
      */
-    copyTo(target: TypedArray, sourceOffset?: number): void;
+    mono_obj_array_set: (array: MonoArray, idx: number, obj: MonoObject) => void;
     /**
-     * same as TypedArray.slice()
+     * @deprecated Not GC or thread safe
      */
-    slice(start?: number, end?: number): TypedArray;
-    get length(): number;
-    get byteLength(): number;
-}
-
-declare function mono_wasm_get_assembly_exports(assembly: string): Promise<any>;
-
-declare const MONO: {
+    js_string_to_mono_string: typeof js_string_to_mono_string;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    js_typed_array_to_array: typeof js_typed_array_to_array;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    mono_array_to_js_array: typeof mono_array_to_js_array;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    js_to_mono_obj: typeof js_to_mono_obj;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    conv_string: typeof conv_string;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    unbox_mono_obj: typeof unbox_mono_obj;
+    mono_obj_array_new_ref: (size: number, result: MonoObjectRef) => void;
+    mono_obj_array_set_ref: (array: MonoObjectRef, idx: number, obj: MonoObjectRef) => void;
+    js_string_to_mono_string_root: typeof js_string_to_mono_string_root;
+    js_typed_array_to_array_root: typeof js_typed_array_to_array_root;
+    js_to_mono_obj_root: typeof js_to_mono_obj_root;
+    conv_string_root: typeof conv_string_root;
+    unbox_mono_obj_root: typeof unbox_mono_obj_root;
+    mono_array_root_to_js_array: typeof mono_array_root_to_js_array;
+};
+declare type MONOType = {
     mono_wasm_setenv: typeof mono_wasm_setenv;
     mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap;
     mono_wasm_load_icu_data: typeof mono_wasm_load_icu_data;
@@ -444,7 +499,7 @@ declare const MONO: {
     mono_run_main_and_exit: typeof mono_run_main_and_exit;
     mono_wasm_get_assembly_exports: typeof mono_wasm_get_assembly_exports;
     mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number;
-    mono_wasm_load_runtime: typeof mono_wasm_load_runtime;
+    mono_wasm_load_runtime: (unused: string, debug_level: number) => void;
     config: MonoConfig | MonoConfigError;
     loaded_files: string[];
     setB32: typeof setB32;
@@ -473,69 +528,6 @@ declare const MONO: {
     getF64: typeof getF64;
     diagnostics: Diagnostics;
 };
-declare type MONOType = typeof MONO;
-declare const BINDING: {
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    mono_obj_array_new: (size: number) => MonoArray;
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    mono_obj_array_set: (array: MonoArray, idx: number, obj: MonoObject) => void;
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    js_string_to_mono_string: typeof js_string_to_mono_string;
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    js_typed_array_to_array: typeof js_typed_array_to_array;
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    mono_array_to_js_array: typeof mono_array_to_js_array;
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    js_to_mono_obj: typeof js_to_mono_obj;
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    conv_string: typeof conv_string;
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    unbox_mono_obj: typeof unbox_mono_obj;
-    /**
-     * @deprecated Renamed to conv_string_root
-     */
-    conv_string_rooted: typeof conv_string_root;
-    mono_obj_array_new_ref: (size: number, result: MonoObjectRef) => void;
-    mono_obj_array_set_ref: (array: MonoObjectRef, idx: number, obj: MonoObjectRef) => void;
-    js_string_to_mono_string_root: typeof js_string_to_mono_string_root;
-    js_typed_array_to_array_root: typeof js_typed_array_to_array_root;
-    js_to_mono_obj_root: typeof js_to_mono_obj_root;
-    conv_string_root: typeof conv_string_root;
-    unbox_mono_obj_root: typeof unbox_mono_obj_root;
-    mono_array_root_to_js_array: typeof mono_array_root_to_js_array;
-    bind_static_method: typeof mono_bind_static_method;
-    call_assembly_entry_point: typeof mono_call_assembly_entry_point;
-};
-declare type BINDINGType = typeof BINDING;
-interface DotnetPublicAPI {
-    MONO: typeof MONO;
-    BINDING: typeof BINDING;
-    INTERNAL: any;
-    EXPORTS: any;
-    IMPORTS: any;
-    Module: EmscriptenModule;
-    RuntimeId: number;
-    RuntimeBuildInfo: {
-        ProductVersion: string;
-        Configuration: string;
-    };
-}
 
 declare function createDotnetRuntime(moduleFactory: DotnetModuleConfig | ((api: DotnetPublicAPI) => DotnetModuleConfig)): Promise<DotnetPublicAPI>;
 declare type CreateDotnetRuntimeType = typeof createDotnetRuntime;
index 7539fa8..82fd6ab 100644 (file)
@@ -82,9 +82,7 @@ const linked_functions = [
     "mono_wasm_create_cs_owned_object_ref",
     "mono_wasm_release_cs_owned_object",
     "mono_wasm_typed_array_to_array_ref",
-    "mono_wasm_typed_array_copy_to_ref",
     "mono_wasm_typed_array_from_ref",
-    "mono_wasm_typed_array_copy_from_ref",
     "mono_wasm_compile_function_ref",
     "mono_wasm_bind_js_function",
     "mono_wasm_invoke_bound_function",
index 9f70faf..2087094 100644 (file)
@@ -1,9 +1,9 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-import { BINDINGType, DotnetPublicAPI, MONOType } from "./exports";
+import { BINDINGType, MONOType } from "./net6-legacy/exports-legacy";
 import { IDisposable, IMemoryView, ManagedError, ManagedObject, MemoryViewType } from "./marshal";
-import { AssetBehaviours, AssetEntry, DotnetModuleConfig, LoadingResource, MonoArray, MonoConfig, MonoObject, MonoString, ResourceRequest } from "./types";
+import { AssetBehaviours, AssetEntry, DotnetModuleConfig, DotnetPublicAPI, LoadingResource, MonoArray, MonoConfig, MonoObject, MonoString, ResourceRequest } from "./types";
 import { EmscriptenModule, TypedArray, VoidPtr } from "./types/emscripten";
 
 // -----------------------------------------------------------
diff --git a/src/mono/wasm/runtime/exports-internal.ts b/src/mono/wasm/runtime/exports-internal.ts
new file mode 100644 (file)
index 0000000..a5c9219
--- /dev/null
@@ -0,0 +1,87 @@
+import { mono_wasm_cancel_promise } from "./cancelable-promise";
+import cwraps from "./cwraps";
+import { mono_wasm_symbolicate_string, mono_wasm_stringify_as_error_with_stack, mono_wasm_get_loaded_files, mono_wasm_send_dbg_command_with_parms, mono_wasm_send_dbg_command, mono_wasm_get_dbg_command_info, mono_wasm_get_details, mono_wasm_release_object, mono_wasm_call_function_on, mono_wasm_debugger_resume, mono_wasm_detach_debugger, mono_wasm_raise_debug_event, mono_wasm_change_debugger_log_level, mono_wasm_debugger_attached } from "./debug";
+import { get_dotnet_instance } from "./exports";
+import { http_wasm_supports_streaming_response, http_wasm_create_abort_controler, http_wasm_abort_request, http_wasm_abort_response, http_wasm_fetch, http_wasm_fetch_bytes, http_wasm_get_response_header_names, http_wasm_get_response_header_values, http_wasm_get_response_bytes, http_wasm_get_response_length, http_wasm_get_streamed_response_bytes } from "./http";
+import { Module, runtimeHelpers } from "./imports";
+import { get_property, set_property, has_property, get_typeof_property, get_global_this, dynamic_import } from "./invoke-js";
+import { mono_method_resolve } from "./net6-legacy/method-binding";
+import { mono_wasm_set_runtime_options } from "./startup";
+import { mono_intern_string } from "./strings";
+import { ws_wasm_create, ws_wasm_open, ws_wasm_send, ws_wasm_receive, ws_wasm_close, ws_wasm_abort } from "./web-socket";
+
+export function export_internal(): any {
+    return {
+        // tests
+        mono_wasm_exit: (exit_code: number) => { Module.printErr("MONO_WASM: early exit " + exit_code); },
+        mono_wasm_enable_on_demand_gc: cwraps.mono_wasm_enable_on_demand_gc,
+        mono_profiler_init_aot: cwraps.mono_profiler_init_aot,
+        mono_wasm_set_runtime_options,
+        mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
+        mono_method_resolve,//MarshalTests.cs
+        mono_intern_string,// MarshalTests.cs
+
+        // with mono_wasm_debugger_log and mono_wasm_trace_logger
+        logging: undefined,
+
+        //
+        mono_wasm_symbolicate_string,
+        mono_wasm_stringify_as_error_with_stack,
+
+        // used in debugger DevToolsHelper.cs
+        mono_wasm_get_loaded_files,
+        mono_wasm_send_dbg_command_with_parms,
+        mono_wasm_send_dbg_command,
+        mono_wasm_get_dbg_command_info,
+        mono_wasm_get_details,
+        mono_wasm_release_object,
+        mono_wasm_call_function_on,
+        mono_wasm_debugger_resume,
+        mono_wasm_detach_debugger,
+        mono_wasm_raise_debug_event,
+        mono_wasm_change_debugger_log_level,
+        mono_wasm_debugger_attached,
+        mono_wasm_runtime_is_ready: runtimeHelpers.mono_wasm_runtime_is_ready,
+
+        // interop
+        get_property,
+        set_property,
+        has_property,
+        get_typeof_property,
+        get_global_this,
+        get_dotnet_instance,
+        dynamic_import,
+
+        // BrowserWebSocket
+        mono_wasm_cancel_promise,
+        ws_wasm_create,
+        ws_wasm_open,
+        ws_wasm_send,
+        ws_wasm_receive,
+        ws_wasm_close,
+        ws_wasm_abort,
+
+        // BrowserHttpHandler
+        http_wasm_supports_streaming_response,
+        http_wasm_create_abort_controler,
+        http_wasm_abort_request,
+        http_wasm_abort_response,
+        http_wasm_fetch,
+        http_wasm_fetch_bytes,
+        http_wasm_get_response_header_names,
+        http_wasm_get_response_header_values,
+        http_wasm_get_response_bytes,
+        http_wasm_get_response_length,
+        http_wasm_get_streamed_response_bytes,
+    };
+}
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export function cwraps_internal(internal: any): void {
+    Object.assign(internal, {
+        mono_wasm_exit: cwraps.mono_wasm_exit,
+        mono_wasm_enable_on_demand_gc: cwraps.mono_wasm_enable_on_demand_gc,
+        mono_profiler_init_aot: cwraps.mono_profiler_init_aot,
+        mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
+    });
+}
diff --git a/src/mono/wasm/runtime/exports-linker.ts b/src/mono/wasm/runtime/exports-linker.ts
new file mode 100644 (file)
index 0000000..a8d2c08
--- /dev/null
@@ -0,0 +1,87 @@
+import MonoWasmThreads from "consts:monoWasmThreads";
+import { dotnet_browser_can_use_subtle_crypto_impl, dotnet_browser_simple_digest_hash, dotnet_browser_sign, dotnet_browser_encrypt_decrypt, dotnet_browser_derive_bits } from "./crypto-worker";
+import { mono_wasm_fire_debugger_agent_message, mono_wasm_debugger_log, mono_wasm_add_dbg_command_received, mono_wasm_trace_logger, mono_wasm_set_entrypoint_breakpoint } from "./debug";
+import { mono_wasm_release_cs_owned_object } from "./gc-handles";
+import { mono_wasm_load_icu_data, mono_wasm_get_icudt_name } from "./icu";
+import { mono_wasm_bind_cs_function } from "./invoke-cs";
+import { mono_wasm_bind_js_function, mono_wasm_invoke_bound_function } from "./invoke-js";
+import { mono_wasm_typed_array_from_ref } from "./net6-legacy/buffers";
+import {
+    mono_wasm_invoke_js_blazor, mono_wasm_invoke_js_with_args_ref, mono_wasm_get_object_property_ref, mono_wasm_set_object_property_ref,
+    mono_wasm_get_by_index_ref, mono_wasm_set_by_index_ref, mono_wasm_get_global_object_ref
+} from "./net6-legacy/method-calls";
+import { mono_wasm_marshal_promise } from "./marshal-to-js";
+import { mono_wasm_pthread_on_pthread_attached } from "./pthreads/worker";
+import { mono_set_timeout, schedule_background_exec } from "./scheduling";
+import { mono_wasm_asm_loaded } from "./startup";
+import { mono_wasm_diagnostic_server_on_server_thread_created } from "./diagnostics/server_pthread";
+import { mono_wasm_diagnostic_server_on_runtime_server_init, mono_wasm_event_pipe_early_startup_callback } from "./diagnostics";
+import { mono_wasm_diagnostic_server_stream_signal_work_available } from "./diagnostics/server_pthread/stream-queue";
+import { mono_wasm_create_cs_owned_object_ref } from "./net6-legacy/cs-to-js";
+import { mono_wasm_typed_array_to_array_ref } from "./net6-legacy/js-to-cs";
+
+// the methods would be visible to EMCC linker
+// --- keep in sync with dotnet.cjs.lib.js ---
+const mono_wasm_threads_exports = !MonoWasmThreads ? undefined : {
+    // mono-threads-wasm.c
+    mono_wasm_pthread_on_pthread_attached,
+    // diagnostics_server.c
+    mono_wasm_diagnostic_server_on_server_thread_created,
+    mono_wasm_diagnostic_server_on_runtime_server_init,
+    mono_wasm_diagnostic_server_stream_signal_work_available,
+};
+
+// the methods would be visible to EMCC linker
+// --- keep in sync with dotnet.cjs.lib.js ---
+// --- keep in sync with dotnet.es6.lib.js ---
+export function export_linker(): any {
+    return {
+        // mini-wasm.c
+        mono_set_timeout,
+
+        // mini-wasm-debugger.c
+        mono_wasm_asm_loaded,
+        mono_wasm_fire_debugger_agent_message,
+        mono_wasm_debugger_log,
+        mono_wasm_add_dbg_command_received,
+
+        // mono-threads-wasm.c
+        schedule_background_exec,
+
+        // also keep in sync with driver.c
+        mono_wasm_invoke_js_blazor,
+        mono_wasm_trace_logger,
+        mono_wasm_set_entrypoint_breakpoint,
+        mono_wasm_event_pipe_early_startup_callback,
+
+        // also keep in sync with corebindings.c
+        mono_wasm_invoke_js_with_args_ref,
+        mono_wasm_get_object_property_ref,
+        mono_wasm_set_object_property_ref,
+        mono_wasm_get_by_index_ref,
+        mono_wasm_set_by_index_ref,
+        mono_wasm_get_global_object_ref,
+        mono_wasm_create_cs_owned_object_ref,
+        mono_wasm_release_cs_owned_object,
+        mono_wasm_typed_array_to_array_ref,
+        mono_wasm_typed_array_from_ref,
+        mono_wasm_bind_js_function,
+        mono_wasm_invoke_bound_function,
+        mono_wasm_bind_cs_function,
+        mono_wasm_marshal_promise,
+
+        //  also keep in sync with pal_icushim_static.c
+        mono_wasm_load_icu_data,
+        mono_wasm_get_icudt_name,
+
+        // pal_crypto_webworker.c
+        dotnet_browser_can_use_subtle_crypto_impl,
+        dotnet_browser_simple_digest_hash,
+        dotnet_browser_sign,
+        dotnet_browser_encrypt_decrypt,
+        dotnet_browser_derive_bits,
+
+        // threading exports, if threading is enabled
+        ...mono_wasm_threads_exports,
+    };
+}
\ No newline at end of file
index d9f679a..e995f40 100644 (file)
 
 import ProductVersion from "consts:productVersion";
 import Configuration from "consts:configuration";
-import MonoWasmThreads from "consts:monoWasmThreads";
 
-import {
-    mono_wasm_new_root, mono_wasm_release_roots, mono_wasm_new_external_root,
-    mono_wasm_new_root_buffer
-} from "./roots";
-import {
-    mono_wasm_send_dbg_command_with_parms,
-    mono_wasm_send_dbg_command,
-    mono_wasm_get_dbg_command_info,
-    mono_wasm_get_details,
-    mono_wasm_release_object,
-    mono_wasm_call_function_on,
-    mono_wasm_debugger_resume,
-    mono_wasm_detach_debugger,
-    mono_wasm_runtime_ready,
-    mono_wasm_get_loaded_files,
-    mono_wasm_raise_debug_event,
-    mono_wasm_fire_debugger_agent_message,
-    mono_wasm_debugger_log,
-    mono_wasm_trace_logger,
-    mono_wasm_add_dbg_command_received,
-    mono_wasm_change_debugger_log_level,
-    mono_wasm_symbolicate_string,
-    mono_wasm_stringify_as_error_with_stack,
-    mono_wasm_debugger_attached,
-    mono_wasm_set_entrypoint_breakpoint,
-} from "./debug";
-import { ENVIRONMENT_IS_WORKER, runtimeHelpers, set_imports_exports } from "./imports";
-import { DotnetModule, is_nullish, MonoConfig, MonoConfigError, EarlyImports, EarlyExports, EarlyReplacements } from "./types";
-import {
-    mono_load_runtime_and_bcl_args, mono_wasm_load_config,
-    mono_wasm_setenv, mono_wasm_set_runtime_options,
-    mono_wasm_load_data_archive, mono_wasm_asm_loaded,
-    configure_emscripten_startup,
-    mono_wasm_load_runtime,
-} from "./startup";
-import { mono_set_timeout, schedule_background_exec } from "./scheduling";
-import { mono_wasm_load_icu_data, mono_wasm_get_icudt_name } from "./icu";
-import { conv_string, conv_string_root, js_string_to_mono_string, js_string_to_mono_string_root, mono_intern_string } from "./strings";
-import { js_to_mono_obj, js_typed_array_to_array, mono_wasm_typed_array_to_array_ref, js_to_mono_obj_root, js_typed_array_to_array_root } from "./js-to-cs";
-import {
-    mono_array_to_js_array, mono_wasm_create_cs_owned_object_ref, unbox_mono_obj, unbox_mono_obj_root, mono_array_root_to_js_array
-} from "./cs-to-js";
-import {
-    call_static_method, mono_bind_static_method, mono_call_assembly_entry_point,
-    mono_method_resolve,
-    mono_wasm_get_by_index_ref, mono_wasm_get_global_object_ref, mono_wasm_get_object_property_ref,
-    mono_wasm_invoke_js_blazor,
-    mono_wasm_invoke_js_with_args_ref, mono_wasm_set_by_index_ref, mono_wasm_set_object_property_ref
-} from "./method-calls";
-import {
-    mono_wasm_event_pipe_early_startup_callback,
-    mono_wasm_diagnostic_server_on_runtime_server_init
-} from "./diagnostics";
-import {
-    mono_wasm_diagnostic_server_on_server_thread_created,
-} from "./diagnostics/server_pthread";
-import {
-    mono_wasm_diagnostic_server_stream_signal_work_available
-} from "./diagnostics/server_pthread/stream-queue";
-import { mono_wasm_typed_array_copy_to_ref, mono_wasm_typed_array_from_ref, mono_wasm_typed_array_copy_from_ref, mono_wasm_load_bytes_into_heap } from "./buffers";
-import { mono_wasm_release_cs_owned_object } from "./gc-handles";
-import cwraps from "./cwraps";
-import {
-    setI8, setI16, setI32, setI52,
-    setU8, setU16, setU32, setF32, setF64,
-    getI8, getI16, getI32, getI52,
-    getU8, getU16, getU32, getF32, getF64, getI64Big, setI64Big, getU52, setU52, setB32, getB32,
-} from "./memory";
+import { ENVIRONMENT_IS_WORKER, set_imports_exports } from "./imports";
+import { DotnetModule, is_nullish, DotnetPublicAPI, EarlyImports, EarlyExports, EarlyReplacements } from "./types";
+import { configure_emscripten_startup } from "./startup";
+import { mono_bind_static_method } from "./net6-legacy/method-calls";
+
 import { create_weak_ref } from "./weak-ref";
-import { EmscriptenModule } from "./types/emscripten";
-import { mono_run_main, mono_run_main_and_exit } from "./run";
-import { dynamic_import, get_global_this, get_property, get_typeof_property, has_property, mono_wasm_bind_js_function, mono_wasm_invoke_bound_function, set_property } from "./invoke-js";
-import { mono_wasm_bind_cs_function, mono_wasm_get_assembly_exports } from "./invoke-cs";
-import { mono_wasm_marshal_promise } from "./marshal-to-js";
-import { ws_wasm_abort, ws_wasm_close, ws_wasm_create, ws_wasm_open, ws_wasm_receive, ws_wasm_send } from "./web-socket";
-import { http_wasm_abort_request, http_wasm_abort_response, http_wasm_create_abort_controler, http_wasm_fetch, http_wasm_fetch_bytes, http_wasm_get_response_bytes, http_wasm_get_response_header_names, http_wasm_get_response_header_values, http_wasm_get_response_length, http_wasm_get_streamed_response_bytes, http_wasm_supports_streaming_response } from "./http";
-import { diagnostics } from "./diagnostics";
-import { mono_wasm_cancel_promise } from "./cancelable-promise";
-import {
-    dotnet_browser_can_use_subtle_crypto_impl,
-    dotnet_browser_simple_digest_hash,
-    dotnet_browser_sign,
-    dotnet_browser_encrypt_decrypt,
-    dotnet_browser_derive_bits,
-} from "./crypto-worker";
-import { mono_wasm_pthread_on_pthread_attached } from "./pthreads/worker";
+import { export_binding_api, export_mono_api } from "./net6-legacy/exports-legacy";
+import { export_internal } from "./exports-internal";
+import { export_linker } from "./exports-linker";
 import { init_polyfills } from "./polyfills";
 
-const MONO = {
-    // current "public" MONO API
-    mono_wasm_setenv,
-    mono_wasm_load_bytes_into_heap,
-    mono_wasm_load_icu_data,
-    mono_wasm_runtime_ready,
-    mono_wasm_load_data_archive,
-    mono_wasm_load_config,
-    mono_load_runtime_and_bcl_args,
-    mono_wasm_new_root_buffer,
-    mono_wasm_new_root,
-    mono_wasm_new_external_root,
-    mono_wasm_release_roots,
-    mono_run_main,
-    mono_run_main_and_exit,
-    mono_wasm_get_assembly_exports,
-
-    mono_wasm_add_assembly: cwraps.mono_wasm_add_assembly,
-    mono_wasm_load_runtime,
-
-    config: <MonoConfig | MonoConfigError>runtimeHelpers.config,
-    loaded_files: <string[]>[],
-
-    // memory accessors
-    setB32,
-    setI8,
-    setI16,
-    setI32,
-    setI52,
-    setU52,
-    setI64Big,
-    setU8,
-    setU16,
-    setU32,
-    setF32,
-    setF64,
-    getB32,
-    getI8,
-    getI16,
-    getI32,
-    getI52,
-    getU52,
-    getI64Big,
-    getU8,
-    getU16,
-    getU32,
-    getF32,
-    getF64,
-
-    // Diagnostics
-    diagnostics
-};
-export type MONOType = typeof MONO;
-
-const BINDING = {
-    //current "public" BINDING API
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    mono_obj_array_new: cwraps.mono_wasm_obj_array_new,
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    mono_obj_array_set: cwraps.mono_wasm_obj_array_set,
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    js_string_to_mono_string,
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    js_typed_array_to_array,
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    mono_array_to_js_array,
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    js_to_mono_obj,
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    conv_string,
-    /**
-     * @deprecated Not GC or thread safe
-     */
-    unbox_mono_obj,
-    /**
-     * @deprecated Renamed to conv_string_root
-     */
-    conv_string_rooted: conv_string_root,
-
-    mono_obj_array_new_ref: cwraps.mono_wasm_obj_array_new_ref,
-    mono_obj_array_set_ref: cwraps.mono_wasm_obj_array_set_ref,
-    js_string_to_mono_string_root,
-    js_typed_array_to_array_root,
-    js_to_mono_obj_root,
-    conv_string_root,
-    unbox_mono_obj_root,
-    mono_array_root_to_js_array,
-
-    bind_static_method: mono_bind_static_method,
-    call_assembly_entry_point: mono_call_assembly_entry_point,
-};
-export type BINDINGType = typeof BINDING;
-
+export const __initializeImportsAndExports: any = initializeImportsAndExports; // don't want to export the type
+export let __linker_exports: any = null;
 let exportedAPI: DotnetPublicAPI;
 
+
 // this is executed early during load of emscripten runtime
 // it exports methods to global objects MONO, BINDING and Module in backward compatible way
 // At runtime this will be referred to as 'createDotnetRuntime'
@@ -219,9 +37,10 @@ function initializeImportsAndExports(
     init_polyfills(replacements);
 
     // here we merge methods from the local objects into exported objects
-    Object.assign(exports.mono, MONO);
-    Object.assign(exports.binding, BINDING);
-    Object.assign(exports.internal, INTERNAL);
+    Object.assign(exports.mono, export_mono_api());
+    Object.assign(exports.binding, export_binding_api());
+    Object.assign(exports.internal, export_internal());
+    __linker_exports = export_linker();
 
     exportedAPI = <any>{
         MONO: exports.mono,
@@ -317,157 +136,6 @@ function initializeImportsAndExports(
     return exportedAPI;
 }
 
-export const __initializeImportsAndExports: any = initializeImportsAndExports; // don't want to export the type
-
-// the methods would be visible to EMCC linker
-// --- keep in sync with dotnet.es6.lib.js ---
-const mono_wasm_threads_exports = !MonoWasmThreads ? undefined : {
-    // mono-threads-wasm.c
-    mono_wasm_pthread_on_pthread_attached,
-    // diagnostics_server.c
-    mono_wasm_diagnostic_server_on_server_thread_created,
-    mono_wasm_diagnostic_server_on_runtime_server_init,
-    mono_wasm_diagnostic_server_stream_signal_work_available,
-};
-
-// the methods would be visible to EMCC linker
-// --- keep in sync with dotnet.es6.lib.js ---
-export const __linker_exports: any = {
-    // mini-wasm.c
-    mono_set_timeout,
-
-    // mini-wasm-debugger.c
-    mono_wasm_asm_loaded,
-    mono_wasm_fire_debugger_agent_message,
-    mono_wasm_debugger_log,
-    mono_wasm_add_dbg_command_received,
-
-    // mono-threads-wasm.c
-    schedule_background_exec,
-
-    // also keep in sync with driver.c
-    mono_wasm_invoke_js_blazor,
-    mono_wasm_trace_logger,
-    mono_wasm_set_entrypoint_breakpoint,
-    mono_wasm_event_pipe_early_startup_callback,
-
-    // also keep in sync with corebindings.c
-    mono_wasm_invoke_js_with_args_ref,
-    mono_wasm_get_object_property_ref,
-    mono_wasm_set_object_property_ref,
-    mono_wasm_get_by_index_ref,
-    mono_wasm_set_by_index_ref,
-    mono_wasm_get_global_object_ref,
-    mono_wasm_create_cs_owned_object_ref,
-    mono_wasm_release_cs_owned_object,
-    mono_wasm_typed_array_to_array_ref,
-    mono_wasm_typed_array_copy_to_ref,
-    mono_wasm_typed_array_from_ref,
-    mono_wasm_typed_array_copy_from_ref,
-    mono_wasm_bind_js_function,
-    mono_wasm_invoke_bound_function,
-    mono_wasm_bind_cs_function,
-    mono_wasm_marshal_promise,
-
-    //  also keep in sync with pal_icushim_static.c
-    mono_wasm_load_icu_data,
-    mono_wasm_get_icudt_name,
-
-    // pal_crypto_webworker.c
-    dotnet_browser_can_use_subtle_crypto_impl,
-    dotnet_browser_simple_digest_hash,
-    dotnet_browser_sign,
-    dotnet_browser_encrypt_decrypt,
-    dotnet_browser_derive_bits,
-
-    // threading exports, if threading is enabled
-    ...mono_wasm_threads_exports,
-};
-
-const INTERNAL: any = {
-    // startup
-    BINDING_ASM: "[System.Runtime.InteropServices.JavaScript]System.Runtime.InteropServices.JavaScript.JavaScriptExports",
-
-    // tests
-    call_static_method,
-    mono_wasm_exit: cwraps.mono_wasm_exit,
-    mono_wasm_enable_on_demand_gc: cwraps.mono_wasm_enable_on_demand_gc,
-    mono_profiler_init_aot: cwraps.mono_profiler_init_aot,
-    mono_wasm_set_runtime_options,
-    mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
-    mono_method_resolve,//MarshalTests.cs
-    mono_bind_static_method,// MarshalTests.cs
-    mono_intern_string,// MarshalTests.cs
-
-    // with mono_wasm_debugger_log and mono_wasm_trace_logger
-    logging: undefined,
-
-    //
-    mono_wasm_symbolicate_string,
-    mono_wasm_stringify_as_error_with_stack,
-
-    // used in debugger DevToolsHelper.cs
-    mono_wasm_get_loaded_files,
-    mono_wasm_send_dbg_command_with_parms,
-    mono_wasm_send_dbg_command,
-    mono_wasm_get_dbg_command_info,
-    mono_wasm_get_details,
-    mono_wasm_release_object,
-    mono_wasm_call_function_on,
-    mono_wasm_debugger_resume,
-    mono_wasm_detach_debugger,
-    mono_wasm_raise_debug_event,
-    mono_wasm_change_debugger_log_level,
-    mono_wasm_debugger_attached,
-    mono_wasm_runtime_is_ready: <boolean>runtimeHelpers.mono_wasm_runtime_is_ready,
-
-    // interop
-    get_property,
-    set_property,
-    has_property,
-    get_typeof_property,
-    get_global_this,
-    get_dotnet_instance,
-    dynamic_import,
-
-    // BrowserWebSocket
-    mono_wasm_cancel_promise,
-    ws_wasm_create,
-    ws_wasm_open,
-    ws_wasm_send,
-    ws_wasm_receive,
-    ws_wasm_close,
-    ws_wasm_abort,
-
-    // BrowserHttpHandler
-    http_wasm_supports_streaming_response,
-    http_wasm_create_abort_controler,
-    http_wasm_abort_request,
-    http_wasm_abort_response,
-    http_wasm_fetch,
-    http_wasm_fetch_bytes,
-    http_wasm_get_response_header_names,
-    http_wasm_get_response_header_values,
-    http_wasm_get_response_bytes,
-    http_wasm_get_response_length,
-    http_wasm_get_streamed_response_bytes,
-};
-
-// this represents visibility in the javascript
-// like https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web.JS/src/Platform/Mono/MonoTypes.ts
-export interface DotnetPublicAPI {
-    MONO: typeof MONO,
-    BINDING: typeof BINDING,
-    INTERNAL: any,
-    EXPORTS: any,
-    IMPORTS: any,
-    Module: EmscriptenModule,
-    RuntimeId: number,
-    RuntimeBuildInfo: {
-        ProductVersion: string,
-        Configuration: string,
-    }
-}
 
 class RuntimeList {
     private list: { [runtimeId: number]: WeakRef<DotnetPublicAPI> } = {};
index 39d9462..af0f477 100644 (file)
@@ -1,9 +1,8 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-import corebindings from "./corebindings";
-import { GCHandle, GCHandleNull, JSHandle, JSHandleDisposed, JSHandleNull, MonoObjectRef, mono_assert } from "./types";
-import { setI32_unchecked } from "./memory";
+import { runtimeHelpers } from "./imports";
+import { GCHandle, GCHandleNull, JSHandle, JSHandleDisposed, JSHandleNull, mono_assert } from "./types";
 import { create_weak_ref } from "./weak-ref";
 
 const _use_finalization_registry = typeof globalThis.FinalizationRegistry === "function";
@@ -31,16 +30,6 @@ export function mono_wasm_get_jsobj_from_js_handle(js_handle: JSHandle): any {
     return null;
 }
 
-// when should_add_in_flight === true, the JSObject would be temporarily hold by Normal gc_handle, so that it would not get collected during transition to the managed stack.
-// its InFlight gc_handle would be freed when the instance arrives to managed side via Interop.Runtime.ReleaseInFlight
-export function get_cs_owned_object_by_js_handle_ref(js_handle: JSHandle, should_add_in_flight: boolean, result: MonoObjectRef): void {
-    if (js_handle === JSHandleNull || js_handle === JSHandleDisposed) {
-        setI32_unchecked(result, 0);
-        return;
-    }
-    corebindings._get_cs_owned_object_by_js_handle_ref(js_handle, should_add_in_flight ? 1 : 0, result);
-}
-
 export function get_js_obj(js_handle: JSHandle): any {
     if (js_handle !== JSHandleNull && js_handle !== JSHandleDisposed)
         return mono_wasm_get_jsobj_from_js_handle(js_handle);
@@ -116,7 +105,7 @@ export function teardown_managed_proxy(result: any, gc_handle: GCHandle): void {
         }
     }
     if (gc_handle !== GCHandleNull && _js_owned_object_table.delete(gc_handle)) {
-        corebindings._release_js_owned_object_by_gc_handle(gc_handle);
+        runtimeHelpers.javaScriptExports._release_js_owned_object_by_gc_handle(gc_handle);
     }
 }
 
@@ -142,12 +131,3 @@ export function _lookup_js_owned_object(gc_handle: GCHandle): any {
     }
     return null;
 }
-
-export function get_js_owned_object_by_gc_handle_ref(gc_handle: GCHandle, result: MonoObjectRef): void {
-    if (!gc_handle) {
-        setI32_unchecked(result, 0);
-        return;
-    }
-    // this is always strong gc_handle
-    corebindings._get_js_owned_object_by_gc_handle_ref(gc_handle, result);
-}
index 5bec05a..29772c2 100644 (file)
@@ -4,13 +4,14 @@
 /* eslint-disable @typescript-eslint/triple-slash-reference */
 /// <reference path="./types/v8.d.ts" />
 
+import { BINDINGType, MONOType } from "./net6-legacy/exports-legacy";
 import { DotnetModule, EarlyExports, EarlyImports, MonoConfig, RuntimeHelpers } from "./types";
 import { EmscriptenModule } from "./types/emscripten";
 
 // these are our public API (except internal)
 export let Module: EmscriptenModule & DotnetModule;
-export let MONO: any;
-export let BINDING: any;
+export let MONO: MONOType;
+export let BINDING: BINDINGType;
 export let INTERNAL: any;
 export let EXPORTS: any;
 export let IMPORTS: any;
@@ -49,8 +50,7 @@ let monoConfig: MonoConfig = {} as any;
 let runtime_is_ready = false;
 
 export const runtimeHelpers: RuntimeHelpers = <any>{
-    namespace: "System.Runtime.InteropServices.JavaScript",
-    classname: "Runtime",
+    javaScriptExports: {},
     mono_wasm_load_runtime_done: false,
     mono_wasm_bindings_is_ready: false,
     get mono_wasm_runtime_is_ready() {
index 9075100..d4e91aa 100644 (file)
@@ -1,24 +1,22 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-import { MonoObject, MonoString } from "./export-types";
 import { EXPORTS, Module, runtimeHelpers } from "./imports";
 import { generate_arg_marshal_to_cs } from "./marshal-to-cs";
 import { marshal_exception_to_js, generate_arg_marshal_to_js } from "./marshal-to-js";
 import {
     JSMarshalerArguments, JavaScriptMarshalerArgSize, JSFunctionSignature,
     JSMarshalerTypeSize, JSMarshalerSignatureHeaderSize,
-    get_arg, get_sig, set_arg_type,
-    get_signature_argument_count, is_args_exception, bound_cs_function_symbol, get_signature_version, MarshalerType,
+    get_arg, get_sig,
+    get_signature_argument_count, is_args_exception, bound_cs_function_symbol, get_signature_version, MarshalerType, alloc_stack_frame,
 } from "./marshal";
-import { parseFQN, wrap_error_root } from "./method-calls";
-import { mono_wasm_new_external_root, mono_wasm_new_root } from "./roots";
+import { mono_wasm_new_external_root } from "./roots";
 import { conv_string, conv_string_root } from "./strings";
-import { mono_assert, MonoObjectRef, MonoStringRef } from "./types";
+import { mono_assert, MonoObjectRef, MonoStringRef, MonoString, MonoObject, MonoMethod } from "./types";
 import { Int32Ptr } from "./types/emscripten";
-import cwraps, { wrap_c_function } from "./cwraps";
-import { find_method } from "./method-binding";
+import cwraps from "./cwraps";
 import { assembly_load } from "./class-loader";
+import { wrap_error_root } from "./invoke-js";
 
 const exportedMethods = new Map<string, Function>();
 
@@ -48,16 +46,15 @@ export function mono_wasm_bind_cs_function(fully_qualified_name: MonoStringRef,
             throw new Error("Could not find class: " + namespace + ":" + classname + " in assembly " + assembly);
 
         const wrapper_name = `__Wrapper_${methodname}_${signature_hash}`;
-        const method = find_method(klass, wrapper_name, -1);
+        const method = cwraps.mono_wasm_assembly_find_method(klass, wrapper_name, -1);
         if (!method)
             throw new Error(`Could not find method: ${wrapper_name} in ${klass} [${assembly}]`);
 
         const closure: any = {
-            method, get_arg, signature,
-            stackSave: anyModule.stackSave, stackAlloc: anyModule.stackAlloc, stackRestore: anyModule.stackRestore,
-            conv_string,
-            mono_wasm_new_root, init_void, init_result, /*init_argument,*/ marshal_exception_to_js, is_args_exception,
-            mono_wasm_invoke_method_bound: wrap_c_function("mono_wasm_invoke_method_bound"),
+            method, signature,
+            stackSave: anyModule.stackSave, stackRestore: anyModule.stackRestore,
+            alloc_stack_frame,
+            invoke_method_and_handle_exception
         };
         const bound_js_function_name = "_bound_cs_" + `${namespace}_${classname}_${methodname}`.replace(/\./g, "_").replace(/\//g, "_");
         let body = `//# sourceURL=https://mono-wasm.invalid/${bound_js_function_name} \n`;
@@ -75,45 +72,26 @@ export function mono_wasm_bind_cs_function(fully_qualified_name: MonoStringRef,
         const { converters: res_converters, call_body: res_call_body, marshaler_type: res_marshaler_type } = generate_arg_marshal_to_js(get_sig(signature, 1), 1, JavaScriptMarshalerArgSize, JSMarshalerTypeSize + JSMarshalerSignatureHeaderSize, "js_result", closure);
         converter_names += res_converters;
 
-        body += `const { method, get_arg, signature, stackSave, stackAlloc, stackRestore, mono_wasm_new_root, conv_string, init_void, init_result, init_argument, marshal_exception_to_js, is_args_exception, mono_wasm_invoke_method_bound ${converter_names} } = closure;\n`;
+        body += `const { method, signature, stackSave, stackRestore,  alloc_stack_frame, invoke_method_and_handle_exception ${converter_names} } = closure;\n`;
         // TODO named arguments instead of arguments keyword
         body += `return function ${bound_js_function_name} () {\n`;
-        if (res_marshaler_type === MarshalerType.String) {
-            body += "let root = null;\n";
-        }
         body += "const sp = stackSave();\n";
         body += "try {\n";
-        body += `  const args = stackAlloc(${(args_count + 2) * JavaScriptMarshalerArgSize});\n`;
-        if (res_marshaler_type !== MarshalerType.Void && res_marshaler_type !== MarshalerType.Discard) {
-            if (res_marshaler_type === MarshalerType.String) {
-                body += "  root = mono_wasm_new_root(0);\n";
-                body += "  init_result(args);\n";
-            }
-            else {
-                body += "  init_result(args);\n";
-            }
-        } else {
-            body += "  init_void(args);\n";
-        }
+        body += `  const args = alloc_stack_frame(${(args_count + 2)});\n`;
 
         body += bodyToCs;
 
-        body += "  const fail = mono_wasm_invoke_method_bound(method, args);\n";
-        body += "  if (fail) throw new Error(\"ERR22: Unexpected error: \" + conv_string(fail));\n";
-        body += "  if (is_args_exception(args)) throw marshal_exception_to_js(get_arg(args, 0));\n";
+        body += "  invoke_method_and_handle_exception(method, args);\n";
         if (res_marshaler_type !== MarshalerType.Void && res_marshaler_type !== MarshalerType.Discard) {
             body += res_call_body;
         }
 
         if (res_marshaler_type !== MarshalerType.Void && res_marshaler_type !== MarshalerType.Discard) {
-            body += "return js_result;\n";
+            body += "  return js_result;\n";
         }
 
         body += "} finally {\n";
         body += "  stackRestore(sp);\n";
-        if (res_marshaler_type === MarshalerType.String) {
-            body += "  if(root) root.release()\n";
-        }
         body += "}}";
         const factory = new Function("closure", body);
         const bound_fn = factory(closure);
@@ -131,22 +109,13 @@ export function mono_wasm_bind_cs_function(fully_qualified_name: MonoStringRef,
     }
 }
 
-function init_void(args: JSMarshalerArguments) {
-    mono_assert(args && (<any>args) % 8 == 0, "Arg alignment");
-    const exc = get_arg(args, 0);
-    set_arg_type(exc, MarshalerType.None);
-
-    const res = get_arg(args, 1);
-    set_arg_type(res, MarshalerType.None);
-}
-
-function init_result(args: JSMarshalerArguments) {
-    mono_assert(args && (<any>args) % 8 == 0, "Arg alignment");
-    const exc = get_arg(args, 0);
-    set_arg_type(exc, MarshalerType.None);
-
-    const res = get_arg(args, 1);
-    set_arg_type(res, MarshalerType.None);
+export function invoke_method_and_handle_exception(method: MonoMethod, args: JSMarshalerArguments): void {
+    const fail = cwraps.mono_wasm_invoke_method_bound(method, args);
+    if (fail) throw new Error("ERR24: Unexpected error: " + conv_string(fail));
+    if (is_args_exception(args)) {
+        const exc = get_arg(args, 0);
+        throw marshal_exception_to_js(exc);
+    }
 }
 
 export const exportsByAssembly: Map<string, any> = new Map();
@@ -202,10 +171,38 @@ function _walk_exports_to_set_function(assembly: string, namespace: string, clas
 
 export async function mono_wasm_get_assembly_exports(assembly: string): Promise<any> {
     mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
-    const asm = assembly_load(assembly);
-    if (!asm)
-        throw new Error("Could not find assembly: " + assembly);
-    cwraps.mono_wasm_runtime_run_module_cctor(asm);
+    const result = exportsByAssembly.get(assembly);
+    if (!result) {
+        const asm = assembly_load(assembly);
+        if (!asm)
+            throw new Error("Could not find assembly: " + assembly);
+        cwraps.mono_wasm_runtime_run_module_cctor(asm);
+    }
 
     return exportsByAssembly.get(assembly) || {};
+}
+
+export function parseFQN(fqn: string)
+    : { assembly: string, namespace: string, classname: string, methodname: string } {
+    const assembly = fqn.substring(fqn.indexOf("[") + 1, fqn.indexOf("]")).trim();
+    fqn = fqn.substring(fqn.indexOf("]") + 1).trim();
+
+    const methodname = fqn.substring(fqn.indexOf(":") + 1);
+    fqn = fqn.substring(0, fqn.indexOf(":")).trim();
+
+    let namespace = "";
+    let classname = fqn;
+    if (fqn.indexOf(".") != -1) {
+        const idx = fqn.lastIndexOf(".");
+        namespace = fqn.substring(0, idx);
+        classname = fqn.substring(idx + 1);
+    }
+
+    if (!assembly.trim())
+        throw new Error("No assembly name specified " + fqn);
+    if (!classname.trim())
+        throw new Error("No class name specified " + fqn);
+    if (!methodname.trim())
+        throw new Error("No method name specified " + fqn);
+    return { assembly, namespace, classname, methodname };
 }
\ No newline at end of file
index 1eae1e8..21c5bfa 100644 (file)
@@ -5,13 +5,13 @@ import { mono_wasm_get_jsobj_from_js_handle, mono_wasm_get_js_handle } from "./g
 import { marshal_exception_to_cs, generate_arg_marshal_to_cs } from "./marshal-to-cs";
 import { get_signature_argument_count, JSMarshalerArguments as JSMarshalerArguments, JavaScriptMarshalerArgSize, JSFunctionSignature as JSFunctionSignature, bound_js_function_symbol, JSMarshalerTypeSize, get_sig, JSMarshalerSignatureHeaderSize, get_signature_version, MarshalerType, get_signature_type } from "./marshal";
 import { setI32 } from "./memory";
-import { wrap_error_root } from "./method-calls";
-import { conv_string_root } from "./strings";
+import { conv_string_root, js_string_to_mono_string_root } from "./strings";
 import { mono_assert, JSHandle, MonoObject, MonoObjectRef, MonoString, MonoStringRef } from "./types";
 import { Int32Ptr } from "./types/emscripten";
-import { IMPORTS, INTERNAL, runtimeHelpers } from "./imports";
+import { IMPORTS, INTERNAL, Module, runtimeHelpers } from "./imports";
 import { generate_arg_marshal_to_js } from "./marshal-to-js";
-import { mono_wasm_new_external_root } from "./roots";
+import { mono_wasm_new_external_root, WasmRoot } from "./roots";
+import { mono_wasm_symbolicate_string } from "./debug";
 
 export function mono_wasm_bind_js_function(function_name: MonoStringRef, module_name: MonoStringRef, signature: JSFunctionSignature, function_js_handle: Int32Ptr, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
     const function_name_root = mono_wasm_new_external_root<MonoString>(function_name),
@@ -189,3 +189,31 @@ export async function dynamic_import(module_name: string, module_url: string): P
 }
 
 
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+function _wrap_error_flag(is_exception: Int32Ptr | null, ex: any): string {
+    let res = "unknown exception";
+    if (ex) {
+        res = ex.toString();
+        const stack = ex.stack;
+        if (stack) {
+            // Some JS runtimes insert the error message at the top of the stack, some don't,
+            //  so normalize it by using the stack as the result if it already contains the error
+            if (stack.startsWith(res))
+                res = stack;
+            else
+                res += "\n" + stack;
+        }
+
+        res = mono_wasm_symbolicate_string(res);
+    }
+    if (is_exception) {
+        Module.setValue(is_exception, 1, "i32");
+    }
+    return res;
+}
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export function wrap_error_root(is_exception: Int32Ptr | null, ex: any, result: WasmRoot<MonoObject>): void {
+    const res = _wrap_error_flag(is_exception, ex);
+    js_string_to_mono_string_root(res, <any>result);
+}
diff --git a/src/mono/wasm/runtime/managed-exports.ts b/src/mono/wasm/runtime/managed-exports.ts
new file mode 100644 (file)
index 0000000..7b6e21f
--- /dev/null
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+import { GCHandle, MonoMethod, mono_assert } from "./types";
+import cwraps from "./cwraps";
+import { Module, runtimeHelpers } from "./imports";
+import { alloc_stack_frame, get_arg, get_arg_gc_handle, MarshalerToCs, MarshalerToJs, MarshalerType, set_arg_type, set_gc_handle } from "./marshal";
+import { invoke_method_and_handle_exception } from "./invoke-cs";
+import { marshal_exception_to_cs } from "./marshal-to-cs";
+
+// in all the exported internals methods, we use the same data structures for stack frame as normal full blow interop
+// see src\libraries\System.Runtime.InteropServices.JavaScript\src\System\Runtime\InteropServices\JavaScript\Interop\JavaScriptExports.cs
+export interface JavaScriptExports {
+    // the marshaled signature is: void ReleaseJSOwnedObjectByGCHandle(GCHandle gcHandle)
+    _release_js_owned_object_by_gc_handle(gc_handle: GCHandle): void;
+    // the marshaled signature is: GCHandle CreateTaskCallback()
+    _create_task_callback(): GCHandle;
+    // the marshaled signature is: void CompleteTask<T>(GCHandle holder, Exception? exceptionResult, T? result)
+    _complete_task(holder_gc_handle: GCHandle, error?: any, data?: any, res_converter?: MarshalerToCs): void;
+    // the marshaled signature is: TRes? CallDelegate<T1,T2,T3TRes>(GCHandle callback, T1? arg1, T2? arg2, T3? arg3)
+    _call_delegate(callback_gc_handle: GCHandle, arg1_js: any, arg2_js: any, arg3_js: any,
+        res_converter?: MarshalerToJs, arg1_converter?: MarshalerToCs, arg2_converter?: MarshalerToCs, arg3_converter?: MarshalerToCs): any;
+}
+
+export function init_managed_exports(): void {
+    const anyModule = Module as any;
+    const exports_fqn_asm = "System.Runtime.InteropServices.JavaScript";
+    runtimeHelpers.runtime_interop_module = cwraps.mono_wasm_assembly_load(exports_fqn_asm);
+    if (!runtimeHelpers.runtime_interop_module)
+        throw "Can't find bindings module assembly: " + exports_fqn_asm;
+
+    runtimeHelpers.runtime_interop_namespace = "System.Runtime.InteropServices.JavaScript";
+    runtimeHelpers.runtime_interop_exports_classname = "JavaScriptExports";
+    runtimeHelpers.runtime_interop_exports_class = cwraps.mono_wasm_assembly_find_class(runtimeHelpers.runtime_interop_module, runtimeHelpers.runtime_interop_namespace, runtimeHelpers.runtime_interop_exports_classname);
+    if (!runtimeHelpers.runtime_interop_exports_class)
+        throw "Can't find " + runtimeHelpers.runtime_interop_namespace + "." + runtimeHelpers.runtime_interop_exports_classname + " class";
+
+
+    const release_js_owned_object_by_gc_handle_method = get_method("ReleaseJSOwnedObjectByGCHandle");
+    mono_assert(release_js_owned_object_by_gc_handle_method, "Can't find ReleaseJSOwnedObjectByGCHandle method");
+    const create_task_callback_method = get_method("CreateTaskCallback");
+    mono_assert(create_task_callback_method, "Can't find CreateTaskCallback method");
+    const complete_task_method = get_method("CompleteTask");
+    mono_assert(complete_task_method, "Can't find CompleteTask method");
+    const call_delegate_method = get_method("CallDelegate");
+    mono_assert(call_delegate_method, "Can't find CallDelegate method");
+
+    runtimeHelpers.javaScriptExports._release_js_owned_object_by_gc_handle = (gc_handle: GCHandle) => {
+        if (!gc_handle) {
+            Module.printErr("Must be valid gc_handle");
+        }
+        mono_assert(gc_handle, "Must be valid gc_handle");
+        const sp = anyModule.stackSave();
+        try {
+            const args = alloc_stack_frame(3);
+            const arg1 = get_arg(args, 2);
+            set_gc_handle(arg1, gc_handle);
+            invoke_method_and_handle_exception(release_js_owned_object_by_gc_handle_method, args);
+        } finally {
+            anyModule.stackRestore(sp);
+        }
+    };
+    runtimeHelpers.javaScriptExports._create_task_callback = () => {
+        const sp = anyModule.stackSave();
+        try {
+            const args = alloc_stack_frame(2);
+            invoke_method_and_handle_exception(create_task_callback_method, args);
+            const res = get_arg(args, 1);
+            return get_arg_gc_handle(res);
+        } finally {
+            anyModule.stackRestore(sp);
+        }
+    };
+    runtimeHelpers.javaScriptExports._complete_task = (holder_gc_handle: GCHandle, error?: any, data?: any, res_converter?: MarshalerToCs) => {
+        const sp = anyModule.stackSave();
+        try {
+            const args = alloc_stack_frame(5);
+            const arg1 = get_arg(args, 2);
+            set_gc_handle(arg1, holder_gc_handle);
+            const arg2 = get_arg(args, 3);
+            if (error) {
+                marshal_exception_to_cs(arg2, error);
+            } else {
+                set_arg_type(arg2, MarshalerType.None);
+                const arg3 = get_arg(args, 4);
+                mono_assert(res_converter, "res_converter missing");
+                res_converter(arg3, data);
+            }
+            invoke_method_and_handle_exception(complete_task_method, args);
+        } finally {
+            anyModule.stackRestore(sp);
+        }
+    };
+    runtimeHelpers.javaScriptExports._call_delegate = (callback_gc_handle: GCHandle, arg1_js: any, arg2_js: any, arg3_js: any, res_converter?: MarshalerToJs, arg1_converter?: MarshalerToCs, arg2_converter?: MarshalerToCs, arg3_converter?: MarshalerToCs) => {
+        const sp = anyModule.stackSave();
+        try {
+            const args = alloc_stack_frame(6);
+
+            const arg1 = get_arg(args, 2);
+            set_gc_handle(arg1, callback_gc_handle);
+            // payload arg numbers are shifted by one, the real first is a gc handle of the callback
+
+            if (arg1_converter) {
+                const arg2 = get_arg(args, 3);
+                arg1_converter(arg2, arg1_js);
+            }
+            if (arg2_converter) {
+                const arg3 = get_arg(args, 4);
+                arg2_converter(arg3, arg2_js);
+            }
+            if (arg3_converter) {
+                const arg4 = get_arg(args, 5);
+                arg3_converter(arg4, arg3_js);
+            }
+
+            invoke_method_and_handle_exception(call_delegate_method, args);
+
+            if (res_converter) {
+                const res = get_arg(args, 1);
+                return res_converter(res);
+            }
+        } finally {
+            anyModule.stackRestore(sp);
+        }
+    };
+}
+
+export function get_method(method_name: string): MonoMethod {
+    const res = cwraps.mono_wasm_assembly_find_method(runtimeHelpers.runtime_interop_exports_class, method_name, -1);
+    if (!res)
+        throw "Can't find method " + runtimeHelpers.runtime_interop_namespace + "." + runtimeHelpers.runtime_interop_exports_classname + "." + method_name;
+    return res;
+}
\ No newline at end of file
index a9fff71..ae2019f 100644 (file)
@@ -2,19 +2,19 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import { isThenable } from "./cancelable-promise";
-import wrapped_cs_functions from "./corebindings";
 import cwraps from "./cwraps";
 import { assert_not_disposed, cs_owned_js_handle_symbol, js_owned_gc_handle_symbol, mono_wasm_get_js_handle, setup_managed_proxy, teardown_managed_proxy } from "./gc-handles";
 import { Module, runtimeHelpers } from "./imports";
 import {
     JSMarshalerArgument, ManagedError,
     set_gc_handle, set_js_handle, set_arg_type, set_arg_i32, set_arg_f64, set_arg_i52, set_arg_f32, set_arg_i16, set_arg_u8, set_arg_b8, set_arg_date,
-    set_arg_length, get_arg, is_args_exception, JavaScriptMarshalerArgSize, get_signature_type, get_signature_arg1_type, get_signature_arg2_type, cs_to_js_marshalers, js_to_cs_marshalers,
-    MarshalerToCs, MarshalerToJs, get_signature_res_type, JSMarshalerArguments, bound_js_function_symbol, set_arg_u16, JSMarshalerType, array_element_size, get_string_root, Span, ArraySegment, MemoryViewType, get_signature_arg3_type, MarshalerType, set_arg_i64_big, set_arg_intptr, IDisposable, set_arg_element_type, ManagedObject
+    set_arg_length, get_arg, get_signature_type, get_signature_arg1_type, get_signature_arg2_type, cs_to_js_marshalers, js_to_cs_marshalers,
+    MarshalerToCs, MarshalerToJs, get_signature_res_type, JSMarshalerArguments, bound_js_function_symbol, set_arg_u16, JSMarshalerType, array_element_size,
+    get_string_root, Span, ArraySegment, MemoryViewType, get_signature_arg3_type, MarshalerType, set_arg_i64_big, set_arg_intptr, IDisposable,
+    set_arg_element_type, ManagedObject
 } from "./marshal";
-import { marshal_exception_to_js } from "./marshal-to-js";
 import { _zero_region } from "./memory";
-import { conv_string, js_string_to_mono_string_root } from "./strings";
+import { js_string_to_mono_string_root } from "./strings";
 import { mono_assert, GCHandle, GCHandleNull } from "./types";
 import { TypedArray } from "./types/emscripten";
 
@@ -362,53 +362,17 @@ function _marshal_task_to_cs(arg: JSMarshalerArgument, value: Promise<any>, _?:
     }
     mono_assert(isThenable(value), "Value is not a Promise");
 
-    const anyModule = Module as any;
-    const gc_handle: GCHandle = wrapped_cs_functions._create_task_callback();
+    const gc_handle: GCHandle = runtimeHelpers.javaScriptExports._create_task_callback();
     set_gc_handle(arg, gc_handle);
     set_arg_type(arg, MarshalerType.Task);
     const holder = new TaskCallbackHolder(value);
     setup_managed_proxy(holder, gc_handle);
 
     value.then(data => {
-        const sp = anyModule.stackSave();
-        try {
-            const args = anyModule.stackAlloc(JavaScriptMarshalerArgSize * 3);
-            const exc = get_arg(args, 0);
-            set_arg_type(exc, MarshalerType.None);
-            const res = get_arg(args, 1);
-            set_arg_type(res, MarshalerType.None);
-            set_gc_handle(res, <any>gc_handle);
-            const arg1 = get_arg(args, 2);
-            if (!res_converter) {
-                _marshal_cs_object_to_cs(arg1, data);
-            } else {
-                res_converter(arg1, data);
-            }
-            const fail = cwraps.mono_wasm_invoke_method_bound(runtimeHelpers.complete_task_method, args);
-            if (fail) throw new Error("ERR22: Unexpected error: " + conv_string(fail));
-            if (is_args_exception(args)) throw marshal_exception_to_js(exc);
-        } finally {
-            anyModule.stackRestore(sp);
-        }
+        runtimeHelpers.javaScriptExports._complete_task(gc_handle, null, data, res_converter || _marshal_cs_object_to_cs);
         teardown_managed_proxy(holder, gc_handle); // this holds holder alive for finalizer, until the promise is freed, (holding promise instead would not work)
     }).catch(reason => {
-        const sp = anyModule.stackSave();
-        try {
-            const args = anyModule.stackAlloc(JavaScriptMarshalerArgSize * 3);
-            const res = get_arg(args, 1);
-            set_arg_type(res, MarshalerType.None);
-            set_gc_handle(res, gc_handle);
-            const exc = get_arg(args, 0);
-            if (typeof reason === "string" || reason === null || reason === undefined) {
-                reason = new Error(reason || "");
-            }
-            marshal_exception_to_cs(exc, reason);
-            const fail = cwraps.mono_wasm_invoke_method_bound(runtimeHelpers.complete_task_method, args);
-            if (fail) throw new Error("ERR24: Unexpected error: " + conv_string(fail));
-            if (is_args_exception(args)) throw marshal_exception_to_js(exc);
-        } finally {
-            anyModule.stackRestore(sp);
-        }
+        runtimeHelpers.javaScriptExports._complete_task(gc_handle, reason, null, undefined);
         teardown_managed_proxy(holder, gc_handle); // this holds holder alive for finalizer, until the promise is freed
     });
 }
index 1cf0b43..7555fdb 100644 (file)
@@ -10,9 +10,10 @@ import {
     get_arg_gc_handle, get_arg_js_handle, get_arg_type, get_arg_i32, get_arg_f64, get_arg_i52, get_arg_i16, get_arg_u8, get_arg_f32,
     get_arg_b8, get_arg_date, get_arg_length, set_js_handle, get_arg, set_arg_type,
     get_signature_arg2_type, get_signature_arg1_type, get_signature_type, cs_to_js_marshalers, js_to_cs_marshalers,
-    get_signature_res_type, JavaScriptMarshalerArgSize, set_gc_handle, is_args_exception, get_arg_u16, array_element_size, get_string_root, ArraySegment, Span, MemoryViewType, get_signature_arg3_type, MarshalerType, get_arg_i64_big, get_arg_intptr, get_arg_element_type
+    get_signature_res_type, get_arg_u16, array_element_size, get_string_root,
+    ArraySegment, Span, MemoryViewType, get_signature_arg3_type, MarshalerType, get_arg_i64_big, get_arg_intptr, get_arg_element_type
 } from "./marshal";
-import { conv_string, conv_string_root } from "./strings";
+import { conv_string_root } from "./strings";
 import { mono_assert, JSHandleNull, GCHandleNull } from "./types";
 import { TypedArray } from "./types/emscripten";
 
@@ -239,48 +240,14 @@ function _marshal_delegate_to_js(arg: JSMarshalerArgument, _?: JSMarshalerType,
         return null;
     }
 
-    const anyModule = Module as any;
     const gc_handle = get_arg_gc_handle(arg);
     let result = _lookup_js_owned_object(gc_handle);
     if (result === null || result === undefined) {
         // this will create new Function for the C# delegate
-        result = (arg1_js: any, arg2_js: any, arg3_js: any) => {
-
-            const sp = anyModule.stackSave();
-            try {
-                const args = anyModule.stackAlloc(JavaScriptMarshalerArgSize * 5);
-                const exc = get_arg(args, 0);
-                set_arg_type(exc, MarshalerType.None);
-                const res = get_arg(args, 1);
-                set_arg_type(res, MarshalerType.None);
-                set_gc_handle(res, <any>gc_handle);
-                const arg1 = get_arg(args, 2);
-                const arg2 = get_arg(args, 3);
-                const arg3 = get_arg(args, 4);
-
-                if (arg1_converter) {
-                    arg1_converter(arg1, arg1_js);
-                }
-                if (arg2_converter) {
-                    arg2_converter(arg2, arg2_js);
-                }
-                if (arg3_converter) {
-                    arg3_converter(arg3, arg3_js);
-                }
-
-                const fail = cwraps.mono_wasm_invoke_method_bound(runtimeHelpers.call_delegate, args);
-                if (fail) throw new Error("ERR23: Unexpected error: " + conv_string(fail));
-                if (is_args_exception(args)) throw marshal_exception_to_js(exc);
-
-                if (res_converter) {
-                    return res_converter(res);
-                }
-
-            } finally {
-                anyModule.stackRestore(sp);
-            }
+        result = (arg1_js: any, arg2_js: any, arg3_js: any): any => {
+            // arg numbers are shifted by one, the real first is a gc handle of the callback
+            return runtimeHelpers.javaScriptExports._call_delegate(gc_handle, arg1_js, arg2_js, arg3_js, res_converter, arg1_converter, arg2_converter, arg3_converter);
         };
-
         setup_managed_proxy(result, gc_handle);
     }
 
index 7df0c23..f62415e 100644 (file)
@@ -55,6 +55,17 @@ export interface JSMarshalerArgument extends NativePointer {
     __brand: "JSMarshalerArgument"
 }
 
+export function alloc_stack_frame(size: number): JSMarshalerArguments {
+    const anyModule = Module as any;
+    const args = anyModule.stackAlloc(JavaScriptMarshalerArgSize * size);
+    mono_assert(args && (<any>args) % 8 == 0, "Arg alignment");
+    const exc = get_arg(args, 0);
+    set_arg_type(exc, MarshalerType.None);
+    const res = get_arg(args, 1);
+    set_arg_type(res, MarshalerType.None);
+    return args;
+}
+
 export function get_arg(args: JSMarshalerArguments, index: number): JSMarshalerArgument {
     mono_assert(args, "Null args");
     return <any>args + (index * JavaScriptMarshalerArgSize);
index ecc4275..1653b94 100644 (file)
@@ -256,6 +256,15 @@ export function withStackAlloc<T1, T2, T3, TResult>(bytesWanted: number, f: (ptr
     }
 }
 
+// @bytes must be a typed array. space is allocated for it in the native heap
+//  and it is copied to that location. returns the address of the allocation.
+export function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr {
+    const memoryOffset = Module._malloc(bytes.length);
+    const heapBytes = new Uint8Array(Module.HEAPU8.buffer, <any>memoryOffset, bytes.length);
+    heapBytes.set(bytes);
+    return memoryOffset;
+}
+
 const BuiltinAtomics = globalThis.Atomics;
 
 export const Atomics = monoWasmThreads ? {
@@ -269,4 +278,4 @@ export const Atomics = monoWasmThreads ? {
 } : {
     storeI32: setI32,
     notifyI32: () => { /*empty*/ }
-};
+};
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/net6-legacy/buffers.ts b/src/mono/wasm/runtime/net6-legacy/buffers.ts
new file mode 100644 (file)
index 0000000..e09b9ab
--- /dev/null
@@ -0,0 +1,110 @@
+import { Module } from "../imports";
+import { wrap_error_root } from "../invoke-js";
+import { mono_wasm_new_external_root } from "../roots";
+import { MonoArray, MonoObjectRef, MonoObject } from "../types";
+import { Int32Ptr, TypedArray } from "../types/emscripten";
+import { js_to_mono_obj_root } from "./js-to-cs";
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export function mono_wasm_typed_array_from_ref(pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number, type: number, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
+    const resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
+    try {
+        const res = typed_array_from(pinned_array, begin, end, bytes_per_element, type);
+        // returns JS typed array like Int8Array, to be wraped with JSObject proxy
+        js_to_mono_obj_root(res, resultRoot, true);
+    } catch (exc) {
+        wrap_error_root(is_exception, String(exc), resultRoot);
+    } finally {
+        resultRoot.release();
+    }
+}
+
+// Creates a new typed array from pinned array address from pinned_array allocated on the heap to the typed array.
+//      address of managed pinned array -> copy from heap -> typed array memory
+function typed_array_from(pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number, type: number) {
+
+    // typed array
+    let newTypedArray: TypedArray | null = null;
+
+    switch (type) {
+        case 5:
+            newTypedArray = new Int8Array(end - begin);
+            break;
+        case 6:
+            newTypedArray = new Uint8Array(end - begin);
+            break;
+        case 7:
+            newTypedArray = new Int16Array(end - begin);
+            break;
+        case 8:
+            newTypedArray = new Uint16Array(end - begin);
+            break;
+        case 9:
+            newTypedArray = new Int32Array(end - begin);
+            break;
+        case 10:
+            newTypedArray = new Uint32Array(end - begin);
+            break;
+        case 13:
+            newTypedArray = new Float32Array(end - begin);
+            break;
+        case 14:
+            newTypedArray = new Float64Array(end - begin);
+            break;
+        case 15:  // This is a special case because the typed array is also byte[]
+            newTypedArray = new Uint8ClampedArray(end - begin);
+            break;
+        default:
+            throw new Error("Unknown array type " + type);
+    }
+
+    typedarray_copy_from(newTypedArray, pinned_array, begin, end, bytes_per_element);
+    return newTypedArray;
+}
+
+// Copy the pinned array address from pinned_array allocated on the heap to the typed array.
+//      address of managed pinned array -> copy from heap -> typed array memory
+function typedarray_copy_from(typed_array: TypedArray, pinned_array: MonoArray, begin: number, end: number, bytes_per_element: number) {
+
+    // JavaScript typed arrays are array-like objects and provide a mechanism for accessing
+    // raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays
+    // split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
+    //  is an object representing a chunk of data; it has no format to speak of, and offers no
+    // mechanism for accessing its contents. In order to access the memory contained in a buffer,
+    // you need to use a view. A view provides a context - that is, a data type, starting offset,
+    // and number of elements - that turns the data into an actual typed array.
+    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
+    if (has_backing_array_buffer(typed_array) && typed_array.BYTES_PER_ELEMENT) {
+        // Some sanity checks of what is being asked of us
+        // lets play it safe and throw an error here instead of assuming to much.
+        // Better safe than sorry later
+        if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT)
+            throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'");
+
+        // how much space we have to work with
+        let num_of_bytes = (end - begin) * bytes_per_element;
+        // how much typed buffer space are we talking about
+        const view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT;
+        // only use what is needed.
+        if (num_of_bytes > view_bytes)
+            num_of_bytes = view_bytes;
+
+        // Create a new view for mapping
+        const typedarrayBytes = new Uint8Array(typed_array.buffer, 0, num_of_bytes);
+        // offset index into the view
+        const offset = begin * bytes_per_element;
+        // Set view bytes to value from HEAPU8
+        typedarrayBytes.set(Module.HEAPU8.subarray(<any>pinned_array + offset, <any>pinned_array + offset + num_of_bytes));
+        return num_of_bytes;
+    }
+    else {
+        throw new Error("Object '" + typed_array + "' is not a typed array");
+    }
+}
+
+
+export function has_backing_array_buffer(js_obj: TypedArray): boolean {
+    return typeof SharedArrayBuffer !== "undefined"
+        ? js_obj.buffer instanceof ArrayBuffer || js_obj.buffer instanceof SharedArrayBuffer
+        : js_obj.buffer instanceof ArrayBuffer;
+}
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/net6-legacy/corebindings.ts b/src/mono/wasm/runtime/net6-legacy/corebindings.ts
new file mode 100644 (file)
index 0000000..4ac7b5b
--- /dev/null
@@ -0,0 +1,97 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+import { JSHandle, GCHandle, MonoObjectRef, MonoMethod, MonoObject } from "../types";
+import { mono_bind_method, _create_primitive_converters } from "./method-binding";
+import { WasmRoot } from "../roots";
+import { runtimeHelpers } from "../imports";
+import cwraps from "../cwraps";
+import { PromiseController } from "../promise-controller";
+type SigLine = [lazy: boolean, jsname: string, csname: string, signature: string/*ArgsMarshalString*/];
+const fn_signatures: SigLine[] = [
+    [true, "_get_cs_owned_object_by_js_handle_ref", "GetCSOwnedObjectByJSHandleRef", "iim"],
+    [true, "_get_cs_owned_object_js_handle_ref", "GetCSOwnedObjectJSHandleRef", "mi"],
+    [true, "_try_get_cs_owned_object_js_handle_ref", "TryGetCSOwnedObjectJSHandleRef", "mi"],
+    [false, "_create_cs_owned_proxy_ref", "CreateCSOwnedProxyRef", "iiim"],
+
+    [false, "_get_js_owned_object_by_gc_handle_ref", "GetJSOwnedObjectByGCHandleRef", "im"],
+    [true, "_get_js_owned_object_gc_handle_ref", "GetJSOwnedObjectGCHandleRef", "m"],
+
+    [true, "_create_tcs", "CreateTaskSource", ""],
+    [true, "_set_tcs_result_ref", "SetTaskSourceResultRef", "iR"],
+    [true, "_set_tcs_failure", "SetTaskSourceFailure", "is"],
+    [true, "_get_tcs_task_ref", "GetTaskSourceTaskRef", "im"],
+    [true, "_setup_js_cont_ref", "SetupJSContinuationRef", "mo"],
+
+    [true, "_object_to_string_ref", "ObjectToStringRef", "m"],
+    [true, "_get_date_value_ref", "GetDateValueRef", "m"],
+    [true, "_create_date_time_ref", "CreateDateTimeRef", "dm"],
+    [true, "_create_uri_ref", "CreateUriRef", "sm"],
+    [true, "_is_simple_array_ref", "IsSimpleArrayRef", "m"],
+    [false, "_get_call_sig_ref", "GetCallSignatureRef", "im"],
+];
+
+export interface LegacyExports {
+    // see src\libraries\System.Runtime.InteropServices.JavaScript\src\System\Runtime\InteropServices\JavaScript\Interop\LegacyExports.cs
+    _get_cs_owned_object_by_js_handle_ref(jsHandle: JSHandle, shouldAddInflight: 0 | 1, result: MonoObjectRef): void;
+    _get_cs_owned_object_js_handle_ref(obj: MonoObjectRef, shouldAddInflight: 0 | 1): JSHandle;
+    _try_get_cs_owned_object_js_handle_ref(obj: MonoObjectRef, shouldAddInflight: 0 | 1): JSHandle;
+    _create_cs_owned_proxy_ref(jsHandle: JSHandle, mappedType: number, shouldAddInflight: 0 | 1, result: MonoObjectRef): void;
+
+    _get_js_owned_object_by_gc_handle_ref(gcHandle: GCHandle, result: MonoObjectRef): void;
+    _get_js_owned_object_gc_handle_ref(obj: MonoObjectRef): GCHandle
+
+    _create_tcs(): GCHandle;
+    _set_tcs_result_ref(gcHandle: GCHandle, result: any): void
+    _set_tcs_failure(gcHandle: GCHandle, result: string): void
+    _get_tcs_task_ref(gcHandle: GCHandle, result: MonoObjectRef): void;
+    _setup_js_cont_ref(task: MonoObjectRef, continuation: PromiseController): void;
+
+    _object_to_string_ref(obj: MonoObjectRef): string;
+    _get_date_value_ref(obj: MonoObjectRef): number;
+    _create_date_time_ref(ticks: number, result: MonoObjectRef): void;
+    _create_uri_ref(uri: string, result: MonoObjectRef): void;
+    _is_simple_array_ref(obj: MonoObjectRef): boolean;
+    _get_call_sig_ref(method: MonoMethod, obj: WasmRoot<MonoObject>): string;
+}
+
+export const legacyManagedExports: LegacyExports = <any>{};
+
+
+export function bind_runtime_method(method_name: string, signature: string): Function {
+    const method = get_method(method_name);
+    return mono_bind_method(method, signature, false, "BINDINGS_" + method_name);
+}
+
+export function init_legacy_exports(): void {
+    _create_primitive_converters();
+
+    runtimeHelpers.runtime_legacy_exports_classname = "LegacyExports";
+    runtimeHelpers.runtime_legacy_exports_class = cwraps.mono_wasm_assembly_find_class(runtimeHelpers.runtime_interop_module, runtimeHelpers.runtime_interop_namespace, runtimeHelpers.runtime_legacy_exports_classname);
+    if (!runtimeHelpers.runtime_legacy_exports_class)
+        throw "Can't find " + runtimeHelpers.runtime_interop_namespace + "." + runtimeHelpers.runtime_interop_exports_classname + " class";
+
+    for (const sig of fn_signatures) {
+        const wf: any = legacyManagedExports;
+        const [lazy, jsname, csname, signature] = sig;
+        if (lazy) {
+            // lazy init on first run
+            wf[jsname] = function (...args: any[]) {
+                const fce = bind_runtime_method(csname, signature);
+                wf[jsname] = fce;
+                return fce(...args);
+            };
+        }
+        else {
+            const fce = bind_runtime_method(csname, signature);
+            wf[jsname] = fce;
+        }
+    }
+}
+
+export function get_method(method_name: string): MonoMethod {
+    const res = cwraps.mono_wasm_assembly_find_method(runtimeHelpers.runtime_legacy_exports_class, method_name, -1);
+    if (!res)
+        throw "Can't find method " + runtimeHelpers.runtime_interop_namespace + "." + runtimeHelpers.runtime_legacy_exports_classname + "." + method_name;
+    return res;
+}
\ No newline at end of file
similarity index 77%
rename from src/mono/wasm/runtime/cs-to-js.ts
rename to src/mono/wasm/runtime/net6-legacy/cs-to-js.ts
index 84f0985..51fc454 100644 (file)
@@ -1,27 +1,20 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-import { mono_wasm_new_root, WasmRoot, mono_wasm_new_external_root } from "./roots";
-import {
-    GCHandle, JSHandleDisposed, MarshalError, MarshalType, MonoArray,
-    MonoArrayNull, MonoObject, MonoObjectNull, MonoString,
-    MonoType, MonoTypeNull, MonoObjectRef, MonoStringRef, is_nullish
-} from "./types";
-import { runtimeHelpers } from "./imports";
-import { conv_string_root } from "./strings";
-import corebindings from "./corebindings";
-import cwraps from "./cwraps";
-import { get_js_owned_object_by_gc_handle_ref, js_owned_gc_handle_symbol, mono_wasm_get_jsobj_from_js_handle, mono_wasm_get_js_handle, setup_managed_proxy, teardown_managed_proxy, _lookup_js_owned_object } from "./gc-handles";
-import { mono_method_get_call_signature_ref, call_method_ref, wrap_error_root } from "./method-calls";
+import { _are_promises_supported } from "../cancelable-promise";
+import cwraps from "../cwraps";
+import { mono_wasm_get_jsobj_from_js_handle, _lookup_js_owned_object, setup_managed_proxy, mono_wasm_get_js_handle, teardown_managed_proxy, assert_not_disposed } from "../gc-handles";
+import { runtimeHelpers } from "../imports";
+import { wrap_error_root } from "../invoke-js";
+import { ManagedObject } from "../marshal";
+import { getU32, getI32, getF32, getF64, setI32_unchecked } from "../memory";
+import { createPromiseController } from "../promise-controller";
+import { WasmRoot, mono_wasm_new_root, mono_wasm_new_external_root } from "../roots";
+import { conv_string_root } from "../strings";
+import { MarshalType, MonoType, MarshalError, MonoTypeNull, MonoArray, MonoArrayNull, MonoObject, MonoObjectNull, GCHandle, MonoStringRef, MonoObjectRef, MonoString, JSHandleDisposed, is_nullish } from "../types";
+import { Int32Ptr, VoidPtr } from "../types/emscripten";
+import { legacyManagedExports } from "./corebindings";
 import { js_to_mono_obj_root } from "./js-to-cs";
-import { _are_promises_supported } from "./cancelable-promise";
-import { getU32, getI32, getF32, getF64 } from "./memory";
-import { Int32Ptr, VoidPtr } from "./types/emscripten";
-import { ManagedObject } from "./marshal";
-import { createPromiseController } from "./promise-controller";
+import { mono_bind_method, mono_method_get_call_signature_ref } from "./method-binding";
 
 const delegate_invoke_symbol = Symbol.for("wasm delegate_invoke");
-const delegate_invoke_signature_symbol = Symbol.for("wasm delegate_invoke_signature");
 
 // this is only used from Blazor
 export function unbox_mono_obj(mono_obj: MonoObject): any {
@@ -38,7 +31,7 @@ export function unbox_mono_obj(mono_obj: MonoObject): any {
 
 function _unbox_cs_owned_root_as_js_object(root: WasmRoot<any>) {
     // we don't need in-flight reference as we already have it rooted here
-    const js_handle = corebindings._get_cs_owned_object_js_handle_ref(root.address, 0);
+    const js_handle = legacyManagedExports._get_cs_owned_object_js_handle_ref(root.address, 0);
     const js_obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
     return js_obj;
 }
@@ -75,11 +68,11 @@ function _unbox_mono_obj_root_with_known_nonprimitive_type_impl(root: WasmRoot<a
         case MarshalType.ARRAY_DOUBLE:
             throw new Error("Marshaling of primitive arrays are not supported.");
         case <MarshalType>20: // clr .NET DateTime
-            return new Date(corebindings._get_date_value_ref(root.address));
+            return new Date(legacyManagedExports._get_date_value_ref(root.address));
         case <MarshalType>21: // clr .NET DateTimeOffset
-            return corebindings._object_to_string_ref(root.address);
+            return legacyManagedExports._object_to_string_ref(root.address);
         case MarshalType.URI:
-            return corebindings._object_to_string_ref(root.address);
+            return legacyManagedExports._object_to_string_ref(root.address);
         case MarshalType.SAFEHANDLE:
             return _unbox_cs_owned_root_as_js_object(root);
         case MarshalType.VOID:
@@ -147,7 +140,7 @@ export function mono_array_to_js_array(mono_array: MonoArray): any[] | null {
 }
 
 function is_nested_array_ref(ele: WasmRoot<MonoObject>) {
-    return corebindings._is_simple_array_ref(ele.address);
+    return legacyManagedExports._is_simple_array_ref(ele.address);
 }
 
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
@@ -182,30 +175,23 @@ export function _wrap_delegate_root_as_function(root: WasmRoot<MonoObject>): Fun
         return null;
 
     // get strong reference to the Delegate
-    const gc_handle = corebindings._get_js_owned_object_gc_handle_ref(root.address);
+    const gc_handle = legacyManagedExports._get_js_owned_object_gc_handle_ref(root.address);
     return _wrap_delegate_gc_handle_as_function(gc_handle);
 }
 
-export function _wrap_delegate_gc_handle_as_function(gc_handle: GCHandle, after_listener_callback?: () => void): Function {
+export function _wrap_delegate_gc_handle_as_function(gc_handle: GCHandle): Function {
     // see if we have js owned instance for this gc_handle already
     let result = _lookup_js_owned_object(gc_handle);
 
+
     // If the function for this gc_handle was already collected (or was never created)
     if (!result) {
+
         // note that we do not implement function/delegate roundtrip
         result = function (...args: any[]) {
-            const delegateRoot = mono_wasm_new_root<MonoObject>();
-            get_js_owned_object_by_gc_handle_ref(gc_handle, delegateRoot.address);
-            try {
-                // FIXME: Pass delegateRoot by-ref
-                const res = call_method_ref(result[delegate_invoke_symbol], delegateRoot, result[delegate_invoke_signature_symbol], args);
-                if (after_listener_callback) {
-                    after_listener_callback();
-                }
-                return res;
-            } finally {
-                delegateRoot.release();
-            }
+            assert_not_disposed(result);
+            const boundMethod = result[delegate_invoke_symbol];
+            return boundMethod(...args);
         };
 
         // bind the method
@@ -213,20 +199,21 @@ export function _wrap_delegate_gc_handle_as_function(gc_handle: GCHandle, after_
         get_js_owned_object_by_gc_handle_ref(gc_handle, delegateRoot.address);
         try {
             if (typeof result[delegate_invoke_symbol] === "undefined") {
-                result[delegate_invoke_symbol] = cwraps.mono_wasm_get_delegate_invoke_ref(delegateRoot.address);
+                const method = cwraps.mono_wasm_get_delegate_invoke_ref(delegateRoot.address);
+                const signature = mono_method_get_call_signature_ref(method, delegateRoot);
+                const js_method = mono_bind_method(method, signature, true);
+                result[delegate_invoke_symbol] = js_method.bind({ this_arg_gc_handle: gc_handle });
                 if (!result[delegate_invoke_symbol]) {
                     throw new Error("System.Delegate Invoke method can not be resolved.");
                 }
             }
-
-            if (typeof result[delegate_invoke_signature_symbol] === "undefined") {
-                result[delegate_invoke_signature_symbol] = mono_method_get_call_signature_ref(result[delegate_invoke_symbol], delegateRoot);
-            }
         } finally {
             delegateRoot.release();
         }
 
         setup_managed_proxy(result, gc_handle);
+    } else {
+        assert_not_disposed(result);
     }
 
     return result;
@@ -289,7 +276,7 @@ function _unbox_task_root_as_promise(root: WasmRoot<MonoObject>) {
         throw new Error("Promises are not supported thus 'System.Threading.Tasks.Task' can not work in this context.");
 
     // get strong reference to Task
-    const gc_handle = corebindings._get_js_owned_object_gc_handle_ref(root.address);
+    const gc_handle = legacyManagedExports._get_js_owned_object_gc_handle_ref(root.address);
 
     // see if we have js owned instance for this gc_handle already
     let result = _lookup_js_owned_object(gc_handle);
@@ -305,7 +292,7 @@ function _unbox_task_root_as_promise(root: WasmRoot<MonoObject>) {
         result = promise;
 
         // register C# side of the continuation
-        corebindings._setup_js_cont_ref(root.address, promise_control);
+        legacyManagedExports._setup_js_cont_ref(root.address, promise_control);
 
         setup_managed_proxy(result, gc_handle);
     }
@@ -320,7 +307,7 @@ export function _unbox_ref_type_root_as_js_object(root: WasmRoot<MonoObject>): a
 
     // this could be JSObject proxy of a js native object
     // we don't need in-flight reference as we already have it rooted here
-    const js_handle = corebindings._try_get_cs_owned_object_js_handle_ref(root.address, 0);
+    const js_handle = legacyManagedExports._try_get_cs_owned_object_js_handle_ref(root.address, 0);
     if (js_handle) {
         if (js_handle === JSHandleDisposed) {
             throw new Error("Cannot access a disposed JSObject at " + root.value);
@@ -330,7 +317,7 @@ export function _unbox_ref_type_root_as_js_object(root: WasmRoot<MonoObject>): a
     // otherwise this is C# only object
 
     // get strong reference to Object
-    const gc_handle = corebindings._get_js_owned_object_gc_handle_ref(root.address);
+    const gc_handle = legacyManagedExports._get_js_owned_object_gc_handle_ref(root.address);
 
     // see if we have js owned instance for this gc_handle already
     let result = _lookup_js_owned_object(gc_handle);
@@ -339,11 +326,17 @@ export function _unbox_ref_type_root_as_js_object(root: WasmRoot<MonoObject>): a
     if (is_nullish(result)) {
         result = new ManagedObject();
 
-        // keep the gc_handle so that we could easily convert it back to original C# object for roundtrip
-        result[js_owned_gc_handle_symbol] = gc_handle;
-
         setup_managed_proxy(result, gc_handle);
     }
 
     return result;
 }
+
+export function get_js_owned_object_by_gc_handle_ref(gc_handle: GCHandle, result: MonoObjectRef): void {
+    if (!gc_handle) {
+        setI32_unchecked(result, 0);
+        return;
+    }
+    // this is always strong gc_handle
+    legacyManagedExports._get_js_owned_object_by_gc_handle_ref(gc_handle, result);
+}
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts b/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts
new file mode 100644 (file)
index 0000000..93b26e6
--- /dev/null
@@ -0,0 +1,207 @@
+import cwraps from "../cwraps";
+import { mono_wasm_runtime_ready } from "../debug";
+import diagnostics, { Diagnostics } from "../diagnostics";
+import { mono_wasm_load_icu_data } from "../icu";
+import { runtimeHelpers } from "../imports";
+import { mono_wasm_get_assembly_exports } from "../invoke-cs";
+import { mono_wasm_load_bytes_into_heap, setB32, setI8, setI16, setI32, setI52, setU52, setI64Big, setU8, setU16, setU32, setF32, setF64, getB32, getI8, getI16, getI32, getI52, getU52, getI64Big, getU8, getU16, getU32, getF32, getF64 } from "../memory";
+import { mono_wasm_new_root_buffer, mono_wasm_new_root, mono_wasm_new_external_root, mono_wasm_release_roots } from "../roots";
+import { mono_run_main, mono_run_main_and_exit } from "../run";
+import { mono_wasm_setenv, mono_wasm_load_data_archive, mono_wasm_load_config, mono_load_runtime_and_bcl_args } from "../startup";
+import { js_string_to_mono_string, conv_string, js_string_to_mono_string_root, conv_string_root } from "../strings";
+import { MonoArray, MonoConfig, MonoConfigError, MonoObject, MonoObjectRef } from "../types";
+import { VoidPtr } from "../types/emscripten";
+import { mono_array_to_js_array, unbox_mono_obj, unbox_mono_obj_root, mono_array_root_to_js_array } from "./cs-to-js";
+import { js_typed_array_to_array, js_to_mono_obj, js_typed_array_to_array_root, js_to_mono_obj_root } from "./js-to-cs";
+import { mono_bind_static_method, mono_call_assembly_entry_point } from "./method-calls";
+import { mono_wasm_load_runtime } from "../startup";
+
+export function export_mono_api(): MONOType {
+    return {
+        // current "public" MONO API
+        mono_wasm_setenv,
+        mono_wasm_load_bytes_into_heap,
+        mono_wasm_load_icu_data,
+        mono_wasm_runtime_ready,
+        mono_wasm_load_data_archive,
+        mono_wasm_load_config,
+        mono_load_runtime_and_bcl_args,
+        mono_wasm_new_root_buffer,
+        mono_wasm_new_root,
+        mono_wasm_new_external_root,
+        mono_wasm_release_roots,
+        mono_run_main,
+        mono_run_main_and_exit,
+        mono_wasm_get_assembly_exports,
+
+        // for Blazor's future!
+        mono_wasm_add_assembly: <any>null,
+        mono_wasm_load_runtime,
+
+        config: <MonoConfig | MonoConfigError>runtimeHelpers.config,
+        loaded_files: <string[]>[],
+
+        // memory accessors
+        setB32,
+        setI8,
+        setI16,
+        setI32,
+        setI52,
+        setU52,
+        setI64Big,
+        setU8,
+        setU16,
+        setU32,
+        setF32,
+        setF64,
+        getB32,
+        getI8,
+        getI16,
+        getI32,
+        getI52,
+        getU52,
+        getI64Big,
+        getU8,
+        getU16,
+        getU32,
+        getF32,
+        getF64,
+
+        // Diagnostics
+        diagnostics
+    };
+}
+
+export function cwraps_mono_api(mono: MONOType): void {
+    Object.assign(mono, {
+        mono_wasm_add_assembly: cwraps.mono_wasm_add_assembly,
+    });
+}
+
+export function export_binding_api(): BINDINGType {
+    return {
+        //current "public" BINDING API
+        bind_static_method: mono_bind_static_method,
+        call_assembly_entry_point: mono_call_assembly_entry_point,
+        mono_obj_array_new: <any>null,
+        mono_obj_array_set: <any>null,
+        js_string_to_mono_string,
+        js_typed_array_to_array,
+        mono_array_to_js_array,
+        js_to_mono_obj,
+        conv_string,
+        unbox_mono_obj,
+
+        mono_obj_array_new_ref: <any>null,
+        mono_obj_array_set_ref: <any>null,
+        js_string_to_mono_string_root,
+        js_typed_array_to_array_root,
+        js_to_mono_obj_root,
+        conv_string_root,
+        unbox_mono_obj_root,
+        mono_array_root_to_js_array,
+    };
+}
+
+export function cwraps_binding_api(binding: BINDINGType): void {
+    Object.assign(binding, {
+        mono_obj_array_new: cwraps.mono_wasm_obj_array_new,
+        mono_obj_array_set: cwraps.mono_wasm_obj_array_set,
+        mono_obj_array_new_ref: cwraps.mono_wasm_obj_array_new_ref,
+        mono_obj_array_set_ref: cwraps.mono_wasm_obj_array_set_ref,
+    });
+}
+
+export type BINDINGType = {
+    bind_static_method: typeof mono_bind_static_method;
+    call_assembly_entry_point: typeof mono_call_assembly_entry_point;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    mono_obj_array_new: (size: number) => MonoArray;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    mono_obj_array_set: (array: MonoArray, idx: number, obj: MonoObject) => void;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    js_string_to_mono_string: typeof js_string_to_mono_string;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    js_typed_array_to_array: typeof js_typed_array_to_array;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    mono_array_to_js_array: typeof mono_array_to_js_array;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    js_to_mono_obj: typeof js_to_mono_obj;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    conv_string: typeof conv_string;
+    /**
+     * @deprecated Not GC or thread safe
+     */
+    unbox_mono_obj: typeof unbox_mono_obj;
+
+    // do we really want to advertize add these below ?
+    mono_obj_array_new_ref: (size: number, result: MonoObjectRef) => void;
+    mono_obj_array_set_ref: (array: MonoObjectRef, idx: number, obj: MonoObjectRef) => void;
+    js_string_to_mono_string_root: typeof js_string_to_mono_string_root;
+    js_typed_array_to_array_root: typeof js_typed_array_to_array_root;
+    js_to_mono_obj_root: typeof js_to_mono_obj_root;
+    conv_string_root: typeof conv_string_root;
+    unbox_mono_obj_root: typeof unbox_mono_obj_root;
+    mono_array_root_to_js_array: typeof mono_array_root_to_js_array;
+}
+
+export type MONOType = {
+    mono_wasm_setenv: typeof mono_wasm_setenv;
+    mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap;
+    mono_wasm_load_icu_data: typeof mono_wasm_load_icu_data;
+    mono_wasm_runtime_ready: typeof mono_wasm_runtime_ready;
+    mono_wasm_load_data_archive: typeof mono_wasm_load_data_archive;
+    mono_wasm_load_config: typeof mono_wasm_load_config;
+    mono_load_runtime_and_bcl_args: typeof mono_load_runtime_and_bcl_args;
+    mono_wasm_new_root_buffer: typeof mono_wasm_new_root_buffer;
+    mono_wasm_new_root: typeof mono_wasm_new_root;
+    mono_wasm_new_external_root: typeof mono_wasm_new_external_root;
+    mono_wasm_release_roots: typeof mono_wasm_release_roots;
+    mono_run_main: typeof mono_run_main;
+    mono_run_main_and_exit: typeof mono_run_main_and_exit;
+    mono_wasm_get_assembly_exports: typeof mono_wasm_get_assembly_exports;
+    mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number;
+    mono_wasm_load_runtime: (unused: string, debug_level: number) => void;
+    config: MonoConfig | MonoConfigError;
+    loaded_files: string[];
+    setB32: typeof setB32;
+    setI8: typeof setI8;
+    setI16: typeof setI16;
+    setI32: typeof setI32;
+    setI52: typeof setI52;
+    setU52: typeof setU52;
+    setI64Big: typeof setI64Big;
+    setU8: typeof setU8;
+    setU16: typeof setU16;
+    setU32: typeof setU32;
+    setF32: typeof setF32;
+    setF64: typeof setF64;
+    getB32: typeof getB32;
+    getI8: typeof getI8;
+    getI16: typeof getI16;
+    getI32: typeof getI32;
+    getI52: typeof getI52;
+    getU52: typeof getU52;
+    getI64Big: typeof getI64Big;
+    getU8: typeof getU8;
+    getU16: typeof getU16;
+    getU32: typeof getU32;
+    getF32: typeof getF32;
+    getF64: typeof getF64;
+    diagnostics: Diagnostics;
+
+}
\ No newline at end of file
similarity index 80%
rename from src/mono/wasm/runtime/js-to-cs.ts
rename to src/mono/wasm/runtime/net6-legacy/js-to-cs.ts
index 890febf..438afba 100644 (file)
@@ -1,24 +1,16 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-import { Module, runtimeHelpers } from "./imports";
-import {
-    assert_not_disposed,
-    cs_owned_js_handle_symbol, get_cs_owned_object_by_js_handle_ref,
-    get_js_owned_object_by_gc_handle_ref, js_owned_gc_handle_symbol,
-    mono_wasm_get_jsobj_from_js_handle, mono_wasm_get_js_handle,
-    mono_wasm_release_cs_owned_object, setup_managed_proxy, teardown_managed_proxy
-} from "./gc-handles";
-import corebindings from "./corebindings";
-import cwraps from "./cwraps";
-import { mono_wasm_new_root, mono_wasm_release_roots, WasmRoot, mono_wasm_new_external_root } from "./roots";
-import { wrap_error_root } from "./method-calls";
-import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root } from "./strings";
-import { isThenable } from "./cancelable-promise";
+import { isThenable } from "../cancelable-promise";
+import cwraps from "../cwraps";
+import { js_owned_gc_handle_symbol, assert_not_disposed, cs_owned_js_handle_symbol, mono_wasm_get_js_handle, setup_managed_proxy, mono_wasm_release_cs_owned_object, teardown_managed_proxy, mono_wasm_get_jsobj_from_js_handle } from "../gc-handles";
+import { runtimeHelpers, Module } from "../imports";
+import { wrap_error_root } from "../invoke-js";
+import { setI32_unchecked, setU32_unchecked, setF64, setB32 } from "../memory";
+import { WasmRoot, mono_wasm_new_root, mono_wasm_release_roots, mono_wasm_new_external_root } from "../roots";
+import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root } from "../strings";
+import { MonoObject, is_nullish, MonoClass, wasm_type_symbol, MonoArray, MonoMethod, MonoObjectNull, JSHandle, MonoObjectRef, JSHandleNull, JSHandleDisposed } from "../types";
+import { TypedArray, Int32Ptr } from "../types/emscripten";
 import { has_backing_array_buffer } from "./buffers";
-import { JSHandle, MonoArray, MonoMethod, MonoObject, MonoObjectNull, wasm_type_symbol, MonoClass, MonoObjectRef, is_nullish } from "./types";
-import { setF64, setI32_unchecked, setU32_unchecked, setB32 } from "./memory";
-import { Int32Ptr, TypedArray } from "./types/emscripten";
+import { legacyManagedExports } from "./corebindings";
+import { get_js_owned_object_by_gc_handle_ref } from "./cs-to-js";
 
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 export function _js_to_mono_uri_root(should_add_in_flight: boolean, js_obj: any, result: WasmRoot<MonoObject>): void {
@@ -29,7 +21,7 @@ export function _js_to_mono_uri_root(should_add_in_flight: boolean, js_obj: any,
             return;
         case typeof js_obj === "symbol":
         case typeof js_obj === "string":
-            corebindings._create_uri_ref(js_obj, result.address);
+            legacyManagedExports._create_uri_ref(js_obj, result.address);
             return;
         default:
             _extract_mono_obj_root(should_add_in_flight, js_obj, result);
@@ -108,7 +100,7 @@ export function js_to_mono_obj_root(js_obj: any, result: WasmRoot<MonoObject>, s
         }
         case js_obj.constructor.name === "Date":
             // getTime() is always UTC
-            corebindings._create_date_time_ref(js_obj.getTime(), result.address);
+            legacyManagedExports._create_date_time_ref(js_obj.getTime(), result.address);
             return;
         default:
             _extract_mono_obj_root(should_add_in_flight, js_obj, result);
@@ -125,8 +117,8 @@ function _extract_mono_obj_root(should_add_in_flight: boolean, js_obj: any, resu
     if (js_obj[js_owned_gc_handle_symbol] !== undefined) {
         // for js_owned_gc_handle we don't want to create new proxy
         // since this is strong gc_handle we don't need to in-flight reference
-        assert_not_disposed(js_obj);
-        get_js_owned_object_by_gc_handle_ref(js_obj[js_owned_gc_handle_symbol], result.address);
+        const gc_handle = assert_not_disposed(js_obj);
+        get_js_owned_object_by_gc_handle_ref(gc_handle, result.address);
         return;
     }
     if (js_obj[cs_owned_js_handle_symbol]) {
@@ -148,7 +140,7 @@ function _extract_mono_obj_root(should_add_in_flight: boolean, js_obj: any, resu
 
         const js_handle = mono_wasm_get_js_handle(js_obj);
 
-        corebindings._create_cs_owned_proxy_ref(js_handle, wasm_type_id, should_add_in_flight ? 1 : 0, result.address);
+        legacyManagedExports._create_cs_owned_proxy_ref(js_handle, wasm_type_id, should_add_in_flight ? 1 : 0, result.address);
     }
 }
 
@@ -245,13 +237,13 @@ export function _wrap_js_thenable_as_task_root(thenable: Promise<any>, resultRoo
     // Note that we do not implement promise/task roundtrip.
     // With more complexity we could recover original instance when this Task is marshaled back to JS.
     // TODO optimization: return the tcs.Task on this same call instead of _get_tcs_task
-    const tcs_gc_handle = corebindings._create_tcs();
+    const tcs_gc_handle = legacyManagedExports._create_tcs();
     const holder: any = { tcs_gc_handle };
     setup_managed_proxy(holder, tcs_gc_handle);
     thenable.then((result) => {
-        corebindings._set_tcs_result_ref(tcs_gc_handle, result);
+        legacyManagedExports._set_tcs_result_ref(tcs_gc_handle, result);
     }, (reason) => {
-        corebindings._set_tcs_failure(tcs_gc_handle, reason ? reason.toString() : "");
+        legacyManagedExports._set_tcs_failure(tcs_gc_handle, reason ? reason.toString() : "");
     }).finally(() => {
         // let go of the thenable reference
         mono_wasm_release_cs_owned_object(thenable_js_handle);
@@ -259,7 +251,7 @@ export function _wrap_js_thenable_as_task_root(thenable: Promise<any>, resultRoo
     });
 
 
-    corebindings._get_tcs_task_ref(tcs_gc_handle, resultRoot.address);
+    legacyManagedExports._get_tcs_task_ref(tcs_gc_handle, resultRoot.address);
 
     // returns raw pointer to tcs.Task
     return {
@@ -284,3 +276,14 @@ export function mono_wasm_typed_array_to_array_ref(js_handle: JSHandle, is_excep
         resultRoot.release();
     }
 }
+
+// when should_add_in_flight === true, the JSObject would be temporarily hold by Normal gc_handle, so that it would not get collected during transition to the managed stack.
+// its InFlight gc_handle would be freed when the instance arrives to managed side via Interop.Runtime.ReleaseInFlight
+export function get_cs_owned_object_by_js_handle_ref(js_handle: JSHandle, should_add_in_flight: boolean, result: MonoObjectRef): void {
+    if (js_handle === JSHandleNull || js_handle === JSHandleDisposed) {
+        setI32_unchecked(result, 0);
+        return;
+    }
+    legacyManagedExports._get_cs_owned_object_by_js_handle_ref(js_handle, should_add_in_flight ? 1 : 0, result);
+}
+
@@ -1,27 +1,24 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-import { WasmRoot, WasmRootBuffer, mono_wasm_new_root, mono_wasm_new_external_root } from "./roots";
-import { MonoClass, MonoMethod, MonoObject, VoidPtrNull, MonoType, MarshalType, mono_assert } from "./types";
-import { BINDING, Module, runtimeHelpers } from "./imports";
-import { js_to_mono_enum, js_to_mono_obj_root, _js_to_mono_uri_root } from "./js-to-cs";
-import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root } from "./strings";
-import { _unbox_mono_obj_root_with_known_nonprimitive_type } from "./cs-to-js";
-import {
-    _create_temp_frame, _zero_region,
-    getI32, getU32, getF32, getF64,
-    setI32, setU32, setF32, setF64, setI52, setU52,
-    setB32, getB32, setI32_unchecked, setU32_unchecked
-} from "./memory";
-import {
-    _handle_exception_for_call, _teardown_after_call
-} from "./method-calls";
-import cwraps, { wrap_c_function } from "./cwraps";
-import { VoidPtr } from "./types/emscripten";
-
+import cwraps from "../cwraps";
+import { runtimeHelpers, BINDING, Module } from "../imports";
+import { parseFQN } from "../invoke-cs";
+import { setI32, setU32, setF32, setF64, setU52, setI52, setB32, setI32_unchecked, setU32_unchecked, _zero_region, _create_temp_frame, getB32, getI32, getU32, getF32, getF64 } from "../memory";
+import { WasmRoot, mono_wasm_new_external_root, mono_wasm_new_root, WasmRootBuffer } from "../roots";
+import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root, conv_string_root } from "../strings";
+import { MonoMethod, MonoObject, MonoType, MonoClass, mono_assert, VoidPtrNull, MarshalType, MonoString, MonoObjectNull } from "../types";
+import { VoidPtr } from "../types/emscripten";
+import { legacyManagedExports } from "./corebindings";
+import { get_js_owned_object_by_gc_handle_ref, _unbox_mono_obj_root_with_known_nonprimitive_type } from "./cs-to-js";
+import { js_to_mono_obj_root, _js_to_mono_uri_root, js_to_mono_enum } from "./js-to-cs";
+import { _teardown_after_call } from "./method-calls";
+
+
+const escapeRE = /[^A-Za-z0-9_$]/g;
 const primitiveConverters = new Map<string, Converter>();
 const _signature_converters = new Map<string, Converter>();
-
+const boundMethodsByMethod: Map<string, Function> = new Map();
 
 export function _get_type_name(typePtr: MonoType): string {
     if (!typePtr)
@@ -41,23 +38,6 @@ export function _get_class_name(classPtr: MonoClass): string {
     return cwraps.mono_wasm_get_type_name(cwraps.mono_wasm_class_get_type(classPtr));
 }
 
-export function find_method(klass: MonoClass, name: string, n: number): MonoMethod {
-    return cwraps.mono_wasm_assembly_find_method(klass, name, n);
-}
-
-export function get_method(method_name: string): MonoMethod {
-    const res = find_method(runtimeHelpers.runtime_interop_exports_class, method_name, -1);
-    if (!res)
-        throw "Can't find method " + runtimeHelpers.runtime_interop_namespace + "." + runtimeHelpers.runtime_interop_exports_classname + ":" + method_name;
-    return res;
-}
-
-export function bind_runtime_method(method_name: string, signature: string): Function {
-    const method = get_method(method_name);
-    return mono_bind_method(method, null, signature, "BINDINGS_" + method_name);
-}
-
-
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 export function _create_named_function(name: string, argumentNames: string[], body: string, closure: any): Function {
     let result = null;
@@ -399,10 +379,20 @@ export function _decide_if_result_is_marshaled(converter: Converter, argc: numbe
     }
 }
 
-export function mono_bind_method(method: MonoMethod, this_arg: null, args_marshal: string/*ArgsMarshalString*/, friendly_name: string): Function {
+
+export function mono_bind_method(method: MonoMethod, args_marshal: string/*ArgsMarshalString*/, has_this_arg: boolean, friendly_name?: string): Function {
     if (typeof (args_marshal) !== "string")
         throw new Error("args_marshal argument invalid, expected string");
 
+    const key = `managed_${method}_${args_marshal}`;
+    let result = boundMethodsByMethod.get(key);
+    if (result) {
+        return result;
+    }
+    if (!friendly_name) {
+        friendly_name = key;
+    }
+
     let converter: Converter | null = null;
     if (typeof (args_marshal) === "string") {
         converter = _compile_converter_for_marshal_string(args_marshal);
@@ -413,23 +403,24 @@ export function mono_bind_method(method: MonoMethod, this_arg: null, args_marsha
     const unbox_buffer = Module._malloc(unbox_buffer_size);
 
     const token: BoundMethodToken = {
-        friendlyName: friendly_name,
         method,
         converter,
         scratchRootBuffer: null,
         scratchBuffer: VoidPtrNull,
         scratchResultRoot: mono_wasm_new_root(),
-        scratchExceptionRoot: mono_wasm_new_root()
+        scratchExceptionRoot: mono_wasm_new_root(),
+        scratchThisArgRoot: mono_wasm_new_root()
     };
     const closure: any = {
         Module,
         mono_wasm_new_root,
+        get_js_owned_object_by_gc_handle_ref,
         _create_temp_frame,
         _handle_exception_for_call,
         _teardown_after_call,
-        mono_wasm_try_unbox_primitive_and_get_type_ref: wrap_c_function("mono_wasm_try_unbox_primitive_and_get_type_ref"),
+        mono_wasm_try_unbox_primitive_and_get_type_ref: cwraps.mono_wasm_try_unbox_primitive_and_get_type_ref,
         _unbox_mono_obj_root_with_known_nonprimitive_type,
-        invoke_method_ref: wrap_c_function("mono_wasm_invoke_method_ref"),
+        invoke_method_ref: cwraps.mono_wasm_invoke_method_ref,
         method,
         token,
         unbox_buffer,
@@ -449,13 +440,16 @@ export function mono_bind_method(method: MonoMethod, this_arg: null, args_marsha
     const argumentNames = [];
     const body = [
         "_create_temp_frame();",
-        "let resultRoot = token.scratchResultRoot, exceptionRoot = token.scratchExceptionRoot, sp = stackSave();",
+        "let resultRoot = token.scratchResultRoot, exceptionRoot = token.scratchExceptionRoot, thisArgRoot = token.scratchThisArgRoot , sp = stackSave();",
         "token.scratchResultRoot = null;",
         "token.scratchExceptionRoot = null;",
+        "token.scratchThisArgRoot = null;",
         "if (resultRoot === null)",
         "      resultRoot = mono_wasm_new_root ();",
         "if (exceptionRoot === null)",
         "      exceptionRoot = mono_wasm_new_root ();",
+        "if (thisArgRoot === null)",
+        "      thisArgRoot = mono_wasm_new_root ();",
         ""
     ];
 
@@ -503,8 +497,18 @@ export function mono_bind_method(method: MonoMethod, this_arg: null, args_marsha
     // The end result is that bound method invocations don't always allocate, so no more nursery GCs. Yay! -kg
     body.push(
         "",
-        "invoke_method_ref (method, 0, buffer, exceptionRoot.address, resultRoot.address);",
-        `_handle_exception_for_call (${converterKey}, token, buffer, resultRoot, exceptionRoot, sp);`,
+        "",
+        "",
+    );
+    if (has_this_arg) {
+        body.push("get_js_owned_object_by_gc_handle_ref(this.this_arg_gc_handle, thisArgRoot.address);");
+        body.push("invoke_method_ref (method, thisArgRoot.address, buffer, exceptionRoot.address, resultRoot.address);");
+    } else {
+        body.push("invoke_method_ref (method, 0, buffer, exceptionRoot.address, resultRoot.address);");
+    }
+
+    body.push(
+        `_handle_exception_for_call (${converterKey}, token, buffer, resultRoot, exceptionRoot, thisArgRoot, sp);`,
         "",
         "let resultPtr = resultRoot.value, result = undefined;"
     );
@@ -549,24 +553,20 @@ export function mono_bind_method(method: MonoMethod, this_arg: null, args_marsha
         throw new Error("No converter");
     }
 
-    if (friendly_name) {
-        const escapeRE = /[^A-Za-z0-9_$]/g;
-        friendly_name = friendly_name.replace(escapeRE, "_");
-    }
-
-    let displayName = friendly_name || ("clr_" + method);
+    let displayName = friendly_name.replace(escapeRE, "_");
 
-    if (this_arg)
-        displayName += "_this" + this_arg;
+    if (has_this_arg)
+        displayName += "_this";
 
     body.push(
-        `_teardown_after_call (${converterKey}, token, buffer, resultRoot, exceptionRoot, sp);`,
+        `_teardown_after_call (${converterKey}, token, buffer, resultRoot, exceptionRoot, thisArgRoot, sp);`,
         "return result;"
     );
 
     const bodyJs = body.join("\r\n");
 
-    const result = _create_named_function(displayName, argumentNames, bodyJs, closure);
+    result = _create_named_function(displayName, argumentNames, bodyJs, closure);
+    boundMethodsByMethod.set(key, result);
 
     return result;
 }
@@ -632,11 +632,57 @@ export type Converter = {
 }
 
 export type BoundMethodToken = {
-    friendlyName: string;
     method: MonoMethod;
     converter: Converter | null;
     scratchRootBuffer: WasmRootBuffer | null;
     scratchBuffer: VoidPtr;
     scratchResultRoot: WasmRoot<MonoObject>;
     scratchExceptionRoot: WasmRoot<MonoObject>;
-}
\ No newline at end of file
+    scratchThisArgRoot: WasmRoot<MonoObject>;
+}
+
+function _handle_exception_for_call(
+    converter: Converter | undefined, token: BoundMethodToken | null,
+    buffer: VoidPtr, resultRoot: WasmRoot<MonoString>,
+    exceptionRoot: WasmRoot<MonoObject>,
+    thisArgRoot: WasmRoot<MonoObject>,
+    sp: VoidPtr
+): void {
+    const exc = _convert_exception_for_method_call(resultRoot, exceptionRoot);
+    if (!exc)
+        return;
+
+    _teardown_after_call(converter, token, buffer, resultRoot, exceptionRoot, thisArgRoot, sp);
+    throw exc;
+}
+
+function _convert_exception_for_method_call(result: WasmRoot<MonoString>, exception: WasmRoot<MonoObject>) {
+    if (exception.value === MonoObjectNull)
+        return null;
+
+    const msg = conv_string_root(result);
+    const err = new Error(msg!); //the convention is that invoke_method ToString () any outgoing exception
+    // console.warn (`error ${msg} at location ${err.stack});
+    return err;
+}
+
+export function mono_method_resolve(fqn: string): MonoMethod {
+    const { assembly, namespace, classname, methodname } = parseFQN(fqn);
+
+    const asm = cwraps.mono_wasm_assembly_load(assembly);
+    if (!asm)
+        throw new Error("Could not find assembly: " + assembly);
+
+    const klass = cwraps.mono_wasm_assembly_find_class(asm, namespace, classname);
+    if (!klass)
+        throw new Error("Could not find class: " + namespace + ":" + classname + " in assembly " + assembly);
+
+    const method = cwraps.mono_wasm_assembly_find_method(klass, methodname, -1);
+    if (!method)
+        throw new Error("Could not find method: " + methodname);
+    return method;
+}
+
+export function mono_method_get_call_signature_ref(method: MonoMethod, mono_obj?: WasmRoot<MonoObject>): string/*ArgsMarshalString*/ {
+    return legacyManagedExports._get_call_sig_ref(method, mono_obj ? mono_obj.address : runtimeHelpers._null_root.address);
+}
similarity index 52%
rename from src/mono/wasm/runtime/method-calls.ts
rename to src/mono/wasm/runtime/net6-legacy/method-calls.ts
index 3f0301f..af7c17b 100644 (file)
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-import { mono_wasm_new_root, WasmRoot, mono_wasm_new_external_root } from "./roots";
-import {
-    JSHandle, MonoArray, MonoMethod, MonoObject,
-    MonoObjectNull, MonoString, coerceNull as coerceNull,
-    VoidPtrNull, MonoObjectRef,
-    MonoStringRef, is_nullish, mono_assert
-} from "./types";
-import { INTERNAL, Module, runtimeHelpers } from "./imports";
+import { assembly_load } from "../class-loader";
+import cwraps from "../cwraps";
+import { get_js_obj, mono_wasm_get_jsobj_from_js_handle } from "../gc-handles";
+import { Module, runtimeHelpers, INTERNAL } from "../imports";
+import { wrap_error_root } from "../invoke-js";
+import { _release_temp_frame } from "../memory";
+import { WasmRoot, mono_wasm_new_external_root, mono_wasm_new_root } from "../roots";
+import { conv_string_root, js_string_to_mono_string_root } from "../strings";
+import { JSHandle, MonoStringRef, MonoObjectRef, MonoArray, MonoString, MonoObject, is_nullish, mono_assert } from "../types";
+import { Int32Ptr, VoidPtr } from "../types/emscripten";
 import { mono_array_root_to_js_array, unbox_mono_obj_root } from "./cs-to-js";
-import { get_js_obj, mono_wasm_get_jsobj_from_js_handle } from "./gc-handles";
-// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-ignore used by unsafe export
 import { js_array_to_mono_array, js_to_mono_obj_root } from "./js-to-cs";
-import {
-    mono_bind_method,
-    Converter, _compile_converter_for_marshal_string,
-    _decide_if_result_is_marshaled, find_method,
-    BoundMethodToken
-} from "./method-binding";
-import { conv_string_root, js_string_to_mono_string, js_string_to_mono_string_root } from "./strings";
-import cwraps from "./cwraps";
-import { _create_temp_frame, _release_temp_frame } from "./memory";
-import { VoidPtr, Int32Ptr } from "./types/emscripten";
-import { assembly_load } from "./class-loader";
-
-function _verify_args_for_method_call(args_marshal: string/*ArgsMarshalString*/, args: any) {
-    const has_args = args && (typeof args === "object") && args.length > 0;
-    const has_args_marshal = typeof args_marshal === "string";
-
-    if (has_args) {
-        if (!has_args_marshal)
-            throw new Error("No signature provided for method call.");
-        else if (args.length > args_marshal.length)
-            throw new Error("Too many parameter values. Expected at most " + args_marshal.length + " value(s) for signature " + args_marshal);
-    }
-
-    return has_args_marshal && has_args;
-}
-
-function _convert_exception_for_method_call(result: WasmRoot<MonoString>, exception: WasmRoot<MonoObject>) {
-    if (exception.value === MonoObjectNull)
-        return null;
-
-    const msg = conv_string_root(result);
-    const err = new Error(msg!); //the convention is that invoke_method ToString () any outgoing exception
-    // console.warn (`error ${msg} at location ${err.stack});
-    return err;
-}
-
-/*
-args_marshal is a string with one character per parameter that tells how to marshal it, here are the valid values:
-
-i: int32
-j: int32 - Enum with underlying type of int32
-l: int64
-k: int64 - Enum with underlying type of int64
-f: float
-d: double
-s: string
-S: interned string
-o: js object will be converted to a C# object (this will box numbers/bool/promises)
-m: raw mono object. Don't use it unless you know what you're doing
-
-to suppress marshaling of the return value, place '!' at the end of args_marshal, i.e. 'ii!' instead of 'ii'
-*/
-export function call_method_ref(method: MonoMethod, this_arg: WasmRoot<MonoObject> | MonoObjectRef | undefined, args_marshal: string/*ArgsMarshalString*/, args: ArrayLike<any>): any {
-    // HACK: Sometimes callers pass null or undefined, coerce it to 0 since that's what wasm expects
-    let this_arg_ref: MonoObjectRef | undefined = undefined;
-    if (typeof (this_arg) === "number")
-        this_arg_ref = this_arg;
-    else if (typeof (this_arg) === "object")
-        this_arg_ref = (<any>this_arg).address;
-    else
-        this_arg_ref = <any>coerceNull(this_arg);
-
-    // Detect someone accidentally passing the wrong type of value to method
-    if (typeof method !== "number")
-        throw new Error(`method must be an address in the native heap, but was '${method}'`);
-    if (!method)
-        throw new Error("no method specified");
-    if (typeof (this_arg_ref) !== "number")
-        throw new Error(`this_arg must be a root instance, the address of a root, or undefined, but was ${this_arg}`);
-
-    const needs_converter = _verify_args_for_method_call(args_marshal, args);
-
-    let buffer = VoidPtrNull, converter = undefined;
-    const sp = Module.stackSave();
-    let is_result_marshaled = true;
-
-    // TODO: Only do this if the signature needs marshaling
-    _create_temp_frame();
-
-    // check if the method signature needs argument mashalling
-    if (needs_converter) {
-        converter = _compile_converter_for_marshal_string(args_marshal);
-
-        is_result_marshaled = _decide_if_result_is_marshaled(converter, args.length);
-
-        buffer = converter.compiled_variadic_function!(method, args);
-    }
-
-    return _call_method_with_converted_args(method, <any>this_arg_ref, converter, null, buffer, is_result_marshaled, sp);
-}
-
+import { Converter, BoundMethodToken, mono_method_resolve, mono_method_get_call_signature_ref, mono_bind_method } from "./method-binding";
 
-export function _handle_exception_for_call(
-    converter: Converter | undefined, token: BoundMethodToken | null,
-    buffer: VoidPtr, resultRoot: WasmRoot<MonoString>,
-    exceptionRoot: WasmRoot<MonoObject>, sp: VoidPtr
-): void {
-    const exc = _convert_exception_for_method_call(resultRoot, exceptionRoot);
-    if (!exc)
-        return;
-
-    _teardown_after_call(converter, token, buffer, resultRoot, exceptionRoot, sp);
-    throw exc;
-}
-
-function _handle_exception_and_produce_result_for_call(
-    converter: Converter | undefined, token: BoundMethodToken | null,
-    buffer: VoidPtr, resultRoot: WasmRoot<MonoString>,
-    exceptionRoot: WasmRoot<MonoObject>, sp: VoidPtr,
-    is_result_marshaled: boolean
-): any {
-    _handle_exception_for_call(converter, token, buffer, resultRoot, exceptionRoot, sp);
-
-    let result: any;
-
-    if (is_result_marshaled)
-        result = unbox_mono_obj_root(resultRoot);
-    else
-        result = resultRoot.value;
-
-    _teardown_after_call(converter, token, buffer, resultRoot, exceptionRoot, sp);
-    return result;
-}
+const boundMethodsByFqn: Map<string, Function> = new Map();
 
 export function _teardown_after_call(
     converter: Converter | undefined, token: BoundMethodToken | null,
-    buffer: VoidPtr, resultRoot: WasmRoot<any>,
-    exceptionRoot: WasmRoot<any>, sp: VoidPtr
+    buffer: VoidPtr,
+    resultRoot: WasmRoot<any>,
+    exceptionRoot: WasmRoot<any>,
+    thisArgRoot: WasmRoot<MonoObject>,
+    sp: VoidPtr
 ): void {
     _release_temp_frame();
     Module.stackRestore(sp);
@@ -160,36 +42,30 @@ export function _teardown_after_call(
         else
             exceptionRoot.release();
     }
-}
-
-function _call_method_with_converted_args(
-    method: MonoMethod, this_arg_ref: MonoObjectRef, converter: Converter | undefined,
-    token: BoundMethodToken | null, buffer: VoidPtr,
-    is_result_marshaled: boolean, sp: VoidPtr
-): any {
-    const resultRoot = mono_wasm_new_root<MonoString>(), exceptionRoot = mono_wasm_new_root<MonoObject>();
-    cwraps.mono_wasm_invoke_method_ref(method, this_arg_ref, buffer, exceptionRoot.address, resultRoot.address);
-    return _handle_exception_and_produce_result_for_call(converter, token, buffer, resultRoot, exceptionRoot, sp, is_result_marshaled);
-}
-
-export function call_static_method(fqn: string, args: any[], signature: string/*ArgsMarshalString*/): any {
-    mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
-    const method = mono_method_resolve(fqn);
-
-    if (typeof signature === "undefined")
-        signature = mono_method_get_call_signature_ref(method, undefined);
-
-    return call_method_ref(method, undefined, signature, args);
+    if (typeof (thisArgRoot) === "object") {
+        thisArgRoot.clear();
+        if ((token !== null) && (token.scratchThisArgRoot === null))
+            token.scratchThisArgRoot = thisArgRoot;
+        else
+            thisArgRoot.release();
+    }
 }
 
 export function mono_bind_static_method(fqn: string, signature?: string/*ArgsMarshalString*/): Function {
     mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
-    const method = mono_method_resolve(fqn);
 
-    if (typeof signature === "undefined")
-        signature = mono_method_get_call_signature_ref(method, undefined);
+    const key = `${fqn}-${signature}`;
+    let js_method = boundMethodsByFqn.get(key);
+    if (js_method === undefined) {
+        const method = mono_method_resolve(fqn);
 
-    return mono_bind_method(method, null, signature!, fqn);
+        if (typeof signature === "undefined")
+            signature = mono_method_get_call_signature_ref(method, undefined);
+
+        js_method = mono_bind_method(method, signature!, false, fqn);
+        boundMethodsByFqn.set(key, js_method);
+    }
+    return js_method;
 }
 
 export function mono_bind_assembly_entry_point(assembly: string, signature?: string/*ArgsMarshalString*/): Function {
@@ -209,10 +85,12 @@ export function mono_bind_assembly_entry_point(assembly: string, signature?: str
     if (typeof (signature) !== "string")
         signature = mono_method_get_call_signature_ref(method, undefined);
 
+    const js_method = mono_bind_method(method, signature!, false, "_" + assembly + "__entrypoint");
+
     return async function (...args: any[]) {
         if (args.length > 0 && Array.isArray(args[0]))
             args[0] = js_array_to_mono_array(args[0], true, false);
-        return call_method_ref(method, undefined, signature!, args);
+        return js_method(...args);
     };
 }
 
@@ -416,93 +294,6 @@ export function mono_wasm_get_global_object_ref(global_name: MonoStringRef, is_e
     }
 }
 
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-function _wrap_error_flag(is_exception: Int32Ptr | null, ex: any): string {
-    let res = "unknown exception";
-    if (ex) {
-        res = ex.toString();
-        const stack = ex.stack;
-        if (stack) {
-            // Some JS runtimes insert the error message at the top of the stack, some don't,
-            //  so normalize it by using the stack as the result if it already contains the error
-            if (stack.startsWith(res))
-                res = stack;
-            else
-                res += "\n" + stack;
-        }
-
-        res = INTERNAL.mono_wasm_symbolicate_string(res);
-    }
-    if (is_exception) {
-        Module.setValue(is_exception, 1, "i32");
-    }
-    return res;
-}
-
-/**
- * @deprecated Not GC or thread safe
- */
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-export function wrap_error(is_exception: Int32Ptr | null, ex: any): MonoString {
-    const res = _wrap_error_flag(is_exception, ex);
-    return js_string_to_mono_string(res)!;
-}
-
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-export function wrap_error_root(is_exception: Int32Ptr | null, ex: any, result: WasmRoot<MonoObject>): void {
-    const res = _wrap_error_flag(is_exception, ex);
-    js_string_to_mono_string_root(res, <any>result);
-}
-
-export function mono_method_get_call_signature_ref(method: MonoMethod, mono_obj?: WasmRoot<MonoObject>): string/*ArgsMarshalString*/ {
-    return call_method_ref(
-        runtimeHelpers.get_call_sig_ref, undefined, "im",
-        [method, mono_obj ? mono_obj.address : runtimeHelpers._null_root.address]
-    );
-}
-
-export function parseFQN(fqn: string)
-    : { assembly: string, namespace: string, classname: string, methodname: string } {
-    const assembly = fqn.substring(fqn.indexOf("[") + 1, fqn.indexOf("]")).trim();
-    fqn = fqn.substring(fqn.indexOf("]") + 1).trim();
-
-    const methodname = fqn.substring(fqn.indexOf(":") + 1);
-    fqn = fqn.substring(0, fqn.indexOf(":")).trim();
-
-    let namespace = "";
-    let classname = fqn;
-    if (fqn.indexOf(".") != -1) {
-        const idx = fqn.lastIndexOf(".");
-        namespace = fqn.substring(0, idx);
-        classname = fqn.substring(idx + 1);
-    }
-
-    if (!assembly.trim())
-        throw new Error("No assembly name specified " + fqn);
-    if (!classname.trim())
-        throw new Error("No class name specified " + fqn);
-    if (!methodname.trim())
-        throw new Error("No method name specified " + fqn);
-    return { assembly, namespace, classname, methodname };
-}
-
-export function mono_method_resolve(fqn: string): MonoMethod {
-    const { assembly, namespace, classname, methodname } = parseFQN(fqn);
-
-    const asm = cwraps.mono_wasm_assembly_load(assembly);
-    if (!asm)
-        throw new Error("Could not find assembly: " + assembly);
-
-    const klass = cwraps.mono_wasm_assembly_find_class(asm, namespace, classname);
-    if (!klass)
-        throw new Error("Could not find class: " + namespace + ":" + classname + " in assembly " + assembly);
-
-    const method = find_method(klass, methodname, -1);
-    if (!method)
-        throw new Error("Could not find method: " + methodname);
-    return method;
-}
-
 // Blazor specific custom routine
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 export function mono_wasm_invoke_js_blazor(exceptionMessage: Int32Ptr, callInfo: any, arg0: any, arg1: any, arg2: any): void | number {
index c7a2f02..fcf1c78 100644 (file)
@@ -1,5 +1,5 @@
 import { INTERNAL, Module, runtimeHelpers } from "./imports";
-import { mono_call_assembly_entry_point } from "./method-calls";
+import { mono_call_assembly_entry_point } from "./net6-legacy/method-calls";
 import { mono_wasm_wait_for_debugger } from "./debug";
 import { abort_startup, mono_wasm_set_main_args } from "./startup";
 
index 137c12a..f95c432 100644 (file)
@@ -2,18 +2,15 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import MonoWasmThreads from "consts:monoWasmThreads";
-import { mono_assert, CharPtrNull, DotnetModule, MonoConfig, wasm_type_symbol, MonoObject, MonoConfigError, LoadingResource, AssetEntry, ResourceRequest } from "./types";
-import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_SHELL, INTERNAL, Module, MONO, runtimeHelpers } from "./imports";
-import cwraps from "./cwraps";
+import { mono_assert, CharPtrNull, DotnetModule, MonoConfig, wasm_type_symbol, MonoObject, MonoConfigError, LoadingResource, AssetEntry, ResourceRequest, DotnetPublicAPI } from "./types";
+import { BINDING, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_SHELL, INTERNAL, Module, MONO, runtimeHelpers } from "./imports";
+import cwraps, { init_c_exports } from "./cwraps";
 import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug";
 import { mono_wasm_globalization_init, mono_wasm_load_icu_data } from "./icu";
 import { toBase64StringImpl } from "./base64";
 import { mono_wasm_init_aot_profiler, mono_wasm_init_coverage_profiler } from "./profiler";
-import { mono_wasm_load_bytes_into_heap } from "./buffers";
-import { bind_runtime_method, get_method, _create_primitive_converters } from "./method-binding";
 import { find_corlib_class } from "./class-loader";
 import { VoidPtr, CharPtr } from "./types/emscripten";
-import { DotnetPublicAPI } from "./exports";
 import { mono_on_abort, set_exit_code } from "./run";
 import { initialize_marshalers_to_cs } from "./marshal-to-cs";
 import { initialize_marshalers_to_js } from "./marshal-to-js";
@@ -24,9 +21,14 @@ import * as pthreads_worker from "./pthreads/worker";
 import { createPromiseController } from "./promise-controller";
 import { string_decoder } from "./strings";
 import { mono_wasm_init_diagnostics } from "./diagnostics/index";
+import { init_managed_exports } from "./managed-exports";
+import { init_legacy_exports } from "./net6-legacy/corebindings";
+import { mono_wasm_load_bytes_into_heap } from "./memory";
+import { cwraps_internal } from "./exports-internal";
+import { cwraps_binding_api, cwraps_mono_api } from "./net6-legacy/exports-legacy";
 
 let all_assets_loaded_in_memory: Promise<void> | null = null;
-const loaded_files: { url?: string, file: string }[] = [];
+const loaded_files: { url: string, file: string }[] = [];
 const loaded_assets: { [id: string]: [VoidPtr, number] } = Object.create(null);
 let instantiated_assets_count = 0;
 let downloded_assets_count = 0;
@@ -248,6 +250,10 @@ function mono_wasm_pre_init_essential(): void {
 
     // init_polyfills() is already called from export.ts
     init_crypto();
+    init_c_exports();
+    cwraps_internal(INTERNAL);
+    cwraps_mono_api(MONO);
+    cwraps_binding_api(BINDING);
 
     Module.removeRunDependency("mono_wasm_pre_init_essential");
 }
@@ -594,50 +600,12 @@ export function bindings_init(): void {
         runtimeHelpers._class_uint32 = find_corlib_class("System", "UInt32");
         runtimeHelpers._class_double = find_corlib_class("System", "Double");
         runtimeHelpers._class_boolean = find_corlib_class("System", "Boolean");
-        runtimeHelpers.bind_runtime_method = bind_runtime_method;
-
-        const bindingAssembly = INTERNAL.BINDING_ASM;
-        const binding_fqn_asm = bindingAssembly.substring(bindingAssembly.indexOf("[") + 1, bindingAssembly.indexOf("]")).trim();
-        const binding_fqn_class = bindingAssembly.substring(bindingAssembly.indexOf("]") + 1).trim();
-
-        const binding_module = cwraps.mono_wasm_assembly_load(binding_fqn_asm);
-        if (!binding_module)
-            throw "Can't find bindings module assembly: " + binding_fqn_asm;
-
-        if (binding_fqn_class && binding_fqn_class.length) {
-            runtimeHelpers.runtime_interop_exports_classname = binding_fqn_class;
-            if (binding_fqn_class.indexOf(".") != -1) {
-                const idx = binding_fqn_class.lastIndexOf(".");
-                runtimeHelpers.runtime_interop_namespace = binding_fqn_class.substring(0, idx);
-                runtimeHelpers.runtime_interop_exports_classname = binding_fqn_class.substring(idx + 1);
-            }
-        }
-
-        runtimeHelpers.runtime_interop_exports_class = cwraps.mono_wasm_assembly_find_class(binding_module, runtimeHelpers.runtime_interop_namespace, runtimeHelpers.runtime_interop_exports_classname);
-        if (!runtimeHelpers.runtime_interop_exports_class)
-            throw "Can't find " + binding_fqn_class + " class";
-
-        runtimeHelpers.get_call_sig_ref = get_method("GetCallSignatureRef");
-        if (!runtimeHelpers.get_call_sig_ref)
-            throw "Can't find GetCallSignatureRef method";
-
-        runtimeHelpers.complete_task_method = get_method("CompleteTask");
-        if (!runtimeHelpers.complete_task_method)
-            throw "Can't find CompleteTask method";
-
-        runtimeHelpers.create_task_method = get_method("CreateTaskCallback");
-        if (!runtimeHelpers.create_task_method)
-            throw "Can't find CreateTaskCallback method";
-
-        runtimeHelpers.call_delegate = get_method("CallDelegate");
-        if (!runtimeHelpers.call_delegate)
-            throw "Can't find CallDelegate method";
 
+        init_managed_exports();
+        init_legacy_exports();
         initialize_marshalers_to_js();
         initialize_marshalers_to_cs();
 
-        _create_primitive_converters();
-
         runtimeHelpers._box_root = mono_wasm_new_root<MonoObject>();
         runtimeHelpers._null_root = mono_wasm_new_root<MonoObject>();
     } catch (err) {
index b909569..494db15 100644 (file)
@@ -2,7 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import "node/buffer"; // we use the Buffer type to type some of Emscripten's APIs
-import { bind_runtime_method } from "./method-binding";
+import { JavaScriptExports } from "./managed-exports";
+import { BINDINGType, MONOType } from "./net6-legacy/exports-legacy";
 import { CharPtr, EmscriptenModule, ManagedPointer, NativePointer, VoidPtr, Int32Ptr } from "./types/emscripten";
 
 export type GCHandle = {
@@ -128,10 +129,12 @@ export type RuntimeHelpers = {
     complete_task_method: MonoMethod;
     create_task_method: MonoMethod;
     call_delegate: MonoMethod;
+    runtime_interop_module: MonoAssembly;
     runtime_interop_namespace: string;
     runtime_interop_exports_classname: string;
     runtime_interop_exports_class: MonoClass;
-    bind_runtime_method: typeof bind_runtime_method;
+    runtime_legacy_exports_classname: string;
+    runtime_legacy_exports_class: MonoClass;
 
     _box_buffer_size: number;
     _unbox_buffer_size: number;
@@ -161,6 +164,7 @@ export type RuntimeHelpers = {
     ExitStatus: ExitStatusError;
     quit: Function,
     locateFile: (path: string, prefix?: string) => string,
+    javaScriptExports: JavaScriptExports,
 }
 
 export const wasm_type_symbol = Symbol.for("wasm type");
@@ -362,3 +366,19 @@ export function notThenable<T>(x: T | PromiseLike<T>): x is T {
 /// An identifier for an EventPipe session. The id is unique during the lifetime of the runtime.
 /// Primarily intended for debugging purposes.
 export type EventPipeSessionID = bigint;
+
+// this represents visibility in the javascript
+// like https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web.JS/src/Platform/Mono/MonoTypes.ts
+export interface DotnetPublicAPI {
+    MONO: MONOType,
+    BINDING: BINDINGType,
+    INTERNAL: any,
+    EXPORTS: any,
+    IMPORTS: any,
+    Module: EmscriptenModule,
+    RuntimeId: number,
+    RuntimeBuildInfo: {
+        ProductVersion: string,
+        Configuration: string,
+    }
+}
\ No newline at end of file
index 2eb29cb..d327e81 100644 (file)
@@ -490,7 +490,8 @@ const App = {
 
         const fqn = "[System.Private.Runtime.InteropServices.JavaScript.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:" + method_name;
         try {
-            return App.INTERNAL.call_static_method(fqn, args || [], signature);
+            const method = App.BINDING.bind_static_method(fqn, signature);
+            return method.apply(null, args || []);
         } catch (exc) {
             console.error("exception thrown in", fqn);
             throw exc;