1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-10 18:11:04 +09:00

[browser] remove legacy js interop (#96841)

This commit is contained in:
Pavel Savara 2024-01-19 16:23:05 +01:00 committed by GitHub
parent aca77bdbef
commit 8c3ee305d7
Signed by: github
GPG key ID: B5690EEEBB952194
81 changed files with 65 additions and 7530 deletions

1
.gitattributes vendored
View file

@ -78,4 +78,3 @@ src/tests/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp-
src/tests/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/knucleotide-input.txt text eol=lf
src/tests/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/knucleotide-input-big.txt text eol=lf
src/mono/wasm/runtime/dotnet.d.ts text eol=lf
src/mono/wasm/runtime/dotnet-legacy.d.ts text eol=lf

View file

@ -204,7 +204,6 @@
$(LibrariesNativeArtifactsPath)dotnet.runtime.js;
$(LibrariesNativeArtifactsPath)dotnet.runtime.js.map;
$(LibrariesNativeArtifactsPath)dotnet.d.ts;
$(LibrariesNativeArtifactsPath)dotnet-legacy.d.ts;
$(LibrariesNativeArtifactsPath)package.json;
$(LibrariesNativeArtifactsPath)dotnet.native.wasm;
$(LibrariesNativeArtifactsPath)dotnet.native.js.symbols;

View file

@ -33,7 +33,6 @@
>true</InstallV8ForTests>
<_BundleAOTTestWasmAppForHelixDependsOn>$(_BundleAOTTestWasmAppForHelixDependsOn);PrepareForWasmBuildApp;_PrepareForAOTOnHelix</_BundleAOTTestWasmAppForHelixDependsOn>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<UseSystemResourceKeys Condition="'$(UseSystemResourceKeys)' == ''">false</UseSystemResourceKeys>
<EventSourceSupport Condition="'$(EventSourceSupport)' == ''">true</EventSourceSupport>
<NullabilityInfoContextSupport Condition="'$(NullabilityInfoContextSupport)' == ''">true</NullabilityInfoContextSupport>
@ -47,21 +46,6 @@
<WasmIncludeFullIcuData>true</WasmIncludeFullIcuData>
</PropertyGroup>
<PropertyGroup Condition="'$(BuildAOTTestsOn)' == 'local'">
<!--
When building for BuildAOTTestsOnHelix=true, the BrowserWasmApp.targets are *not* imported, because
they get instead used by the AOT proxy project on helix.
On the build machine only the regular part of the build is run, which includes trimming. But if
BrowserWasmApp.targets modify any trimming arguments, then those will not get picked up by this build.
For example - linker substitution files used with simd builds.
So, set those parameters explicitly here.
-->
<_ExtraTrimmerArgs Condition="'$(WasmEnableLegacyJsInterop)' == 'false'">$(_ExtraTrimmerArgs) --substitutions "$(BrowserProjectRoot)build\ILLink.Substitutions.LegacyJsInterop.xml"</_ExtraTrimmerArgs>
</PropertyGroup>
<!-- On CI this is installed as part of pretest, but it should still be installed
for WBT, and debugger tests -->
<Import Project="$(MSBuildThisFileDirectory)wasm-provisioning.targets"

View file

@ -231,7 +231,6 @@
<PlatformManifestFileEntry Include="dotnet.native.worker.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.native.js.symbols" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.d.ts" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet-legacy.d.ts" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.native.wasm" IsNative="true" />
<PlatformManifestFileEntry Include="icudt.dat" IsNative="true" />
<PlatformManifestFileEntry Include="icudt_no_CJK.dat" IsNative="true" />

View file

@ -11,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JSImportGenerator.Unit.Tests", "tests\JSImportGenerator.UnitTest\JSImportGenerator.Unit.Tests.csproj", "{BFED925C-18F2-4C98-833E-66F205234598}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices.JavaScript.Legacy.Tests", "tests\System.Runtime.InteropServices.JavaScript.Legacy.UnitTests\System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj", "{ABA5A92B-CAD8-47E8-A7CE-D28A67FB69C0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.InteropServices.JavaScript.Tests", "tests\System.Runtime.InteropServices.JavaScript.UnitTests\System.Runtime.InteropServices.JavaScript.Tests.csproj", "{765B4AA5-723A-44FF-BC4E-EB0F03103F6D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComInterfaceGenerator", "..\System.Runtime.InteropServices\gen\ComInterfaceGenerator\ComInterfaceGenerator.csproj", "{FB12C247-AFEF-4772-BB0C-983969B6CF32}"

View file

@ -1,42 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.Array</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.ArrayBuffer</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.DataView</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.Function</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.Runtime</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.Uint8Array</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.SynchronizationContextExtension</Target>

View file

@ -14,9 +14,7 @@
<FeatureWasmThreads Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(MonoWasmBuildVariant)' == 'multithread'">true</FeatureWasmThreads>
<WasmEnableJsInteropByValue Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableJsInteropByValue)' == '' and '$(FeatureWasmThreads)' == 'true'">true</WasmEnableJsInteropByValue>
<WasmEnableJsInteropByValue Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableJsInteropByValue)' == ''">false</WasmEnableJsInteropByValue>
<WasmEnableLegacyJsInterop Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<DefineConstants Condition="'$(FeatureWasmThreads)' == 'true'">$(DefineConstants);FEATURE_WASM_THREADS</DefineConstants>
<DefineConstants Condition="'$(WasmEnableLegacyJsInterop)' == 'false'">$(DefineConstants);DISABLE_LEGACY_JS_INTEROP</DefineConstants>
<DefineConstants Condition="'$(WasmEnableJsInteropByValue)' == 'true'">$(DefineConstants);ENABLE_JS_INTEROP_BY_VALUE</DefineConstants>
<EmitCompilerGeneratedFiles Condition="'$(Configuration)' == 'Debug' and '$(TargetPlatformIdentifier)' == 'browser'">true</EmitCompilerGeneratedFiles>
</PropertyGroup>
@ -29,7 +27,6 @@
<Compile Include="$(CommonPath)Interop\Browser\Interop.Runtime.cs" Link="System\Runtime\InteropServices\JavaScript\Interop\Interop.Runtime.cs" />
<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\JSHost.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\JSMarshalerType.cs" />
@ -68,18 +65,6 @@
<Compile Include="System\Runtime\InteropServices\JavaScript\Marshaling\JSMarshalerArgument.Exception.cs" />
</ItemGroup>
<!-- only include legacy interop when WasmEnableLegacyJsInterop is enabled -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(WasmEnableLegacyJsInterop)' != 'false'">
<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" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\ArrayBuffer.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\DataView.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Function.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\Uint8Array.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Legacy\LegacyHostImplementation.cs" />
</ItemGroup>
<!-- only include threads support when FeatureWasmThreads is enabled -->
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(FeatureWasmThreads)' == 'true'">
<Compile Include="System\Runtime\InteropServices\JavaScript\JSWebWorker.cs" />

View file

@ -1,37 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
namespace System.Runtime.InteropServices.JavaScript
{
internal static unsafe partial class JavaScriptImports
{
#if !DISABLE_LEGACY_JS_INTEROP
#region legacy
public static object GetGlobalObject(string? str = null)
{
int exception;
Interop.Runtime.GetGlobalObjectRef(str, out exception, out object jsObj);
if (exception != 0)
throw new JSException(SR.Format(SR.ErrorResolvingFromGlobalThis, str));
LegacyHostImplementation.ReleaseInFlight(jsObj);
return jsObj;
}
public static IntPtr CreateCSOwnedObject(string typeName, object[] parms)
{
Interop.Runtime.CreateCSOwnedObjectRef(typeName, parms, out int exception, out object res);
if (exception != 0)
throw new JSException((string)res);
return (IntPtr)(int)res;
}
#endregion
#endif
}
}

View file

@ -1,247 +0,0 @@
// 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.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace System.Runtime.InteropServices.JavaScript
{
internal static unsafe partial class LegacyExportsTrimmingRoot
{
// the public methods are used from JavaScript, but the trimmer doesn't know about it.
// It's protected by DynamicDependencyAttribute on JSFunctionBinding.BindJSFunction.
public static void TrimWhenNotWasmEnableLegacyJsInterop()
{
// if MSBuild property WasmEnableLegacyJsInterop==false this call would be substituted away and LegacyExports would be trimmed.
LegacyExports.PreventTrimming();
}
}
internal static unsafe partial class LegacyExports
{
// the public methods of this class are used from JavaScript, but the trimmer doesn't know about it.
// They are protected by LegacyExportsTrimmingRoot.PreventTrimming and JSFunctionBinding.BindJSFunction.
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(LegacyExports))]
internal static void PreventTrimming()
{
}
public static void GetCSOwnedObjectByJSHandleRef(nint jsHandle, int shouldAddInflight, out JSObject? result)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
result = JSProxyContext.MainThreadContext.GetCSOwnedObjectByJSHandle(jsHandle, shouldAddInflight);
}
public static IntPtr GetCSOwnedObjectJSHandleRef(in JSObject jsObject, int shouldAddInflight)
{
jsObject.AssertNotDisposed();
if (shouldAddInflight != 0)
{
jsObject.AddInFlight();
}
return jsObject.JSHandle;
}
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;
}
public static void CreateCSOwnedProxyRef(nint jsHandle, LegacyHostImplementation.MappedType mappedType, int shouldAddInflight, out JSObject jsObject)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
jsObject = JSProxyContext.MainThreadContext.CreateCSOwnedProxy(jsHandle, mappedType, shouldAddInflight);
}
public static void GetJSOwnedObjectByGCHandleRef(int gcHandle, out object result)
{
GCHandle h = (GCHandle)(IntPtr)gcHandle;
result = h.Target!;
}
public static IntPtr GetJSOwnedObjectGCHandleRef(in object obj)
{
return JSProxyContext.MainThreadContext.GetJSOwnedObjectGCHandle(obj, GCHandleType.Normal);
}
public static IntPtr CreateTaskSource()
{
var tcs = new TaskCompletionSource<object>();
return GetJSOwnedObjectGCHandleRef(tcs);
}
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);
}
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));
}
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;
}
public static void SetupJSContinuationRef(in Task _task, JSObject continuationObj)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
// 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();
}
}
}
public static string ObjectToStringRef(ref object o)
{
return o.ToString() ?? string.Empty;
}
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.
public static void CreateDateTimeRef(double ticks, out object result)
{
DateTimeOffset unixTime = DateTimeOffset.FromUnixTimeMilliseconds((long)ticks);
result = unixTime.DateTime;
}
// we do this via reflection to allow trimming tools to trim dependency on Uri class and it's assembly
// if the user code has methods with Uri signature, they probably also have the Uri constructor
// if they don't have it, they could configure ILLing to protect it after they enabled trimming
// We believe that this code path is probably not even used in the wild
// System.Private.Uri is ~80KB large assembly so it's worth trimming
private static Type? uriType;
[Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2077", Justification = "Done on purpose, see comment above.")]
[Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2057", Justification = "Done on purpose, see comment above.")]
public static void CreateUriRef(string uri, out object? result)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
if (uriType == null)
{
// StringBuilder to confuse ILLink, which is too smart otherwise
StringBuilder sb = new StringBuilder("System.Uri, System.Private.Uri");
uriType = Type.GetType(sb.ToString());
}
// See: https://devblogs.microsoft.com/dotnet/customizing-trimming-in-net-core-5/
if (uriType == null) throw new InvalidOperationException(SR.UriTypeMissing);
try
{
result = Activator.CreateInstance(uriType, uri);
}
catch (MissingMethodException ex)
{
throw new MissingMethodException(SR.UriConstructorMissing, ex);
}
}
public static bool IsSimpleArrayRef(ref object a)
{
return a is System.Array arr && arr.Rank == 1 && arr.GetLowerBound(0) == 0;
}
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 = LegacyHostImplementation.GetMarshalTypeFromType(t);
result[i] = LegacyHostImplementation.GetCallSignatureCharacterForMarshalType(mt, null);
}
return new string(result);
}
}
}

View file

@ -170,8 +170,6 @@ namespace System.Runtime.InteropServices.JavaScript
/// <exception cref="PlatformNotSupportedException">The method is executed on an architecture other than WebAssembly.</exception>
// 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")]
// Same for legacy, but the type could be explicitly trimmed by setting WasmEnableLegacyJsInterop=false which would use ILLink.Descriptors.LegacyJsInterop.xml
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.LegacyExportsTrimmingRoot", "System.Runtime.InteropServices.JavaScript")]
public static JSFunctionBinding BindJSFunction(string functionName, string moduleName, ReadOnlySpan<JSMarshalerType> signatures)
{
if (RuntimeInformation.OSArchitecture != Architecture.Wasm)

View file

@ -25,10 +25,6 @@ namespace System.Runtime.InteropServices.JavaScript
}
}
#if !DISABLE_LEGACY_JS_INTEROP
internal GCHandle? InFlight;
internal int InFlightCounter;
#endif
internal bool _isDisposed;
internal JSObject(IntPtr jsHandle, JSProxyContext ctx)
@ -37,41 +33,6 @@ namespace System.Runtime.InteropServices.JavaScript
JSHandle = jsHandle;
}
#if !DISABLE_LEGACY_JS_INTEROP
internal void AddInFlight()
{
AssertNotDisposed();
lock (ProxyContext)
{
InFlightCounter++;
if (InFlightCounter == 1)
{
Debug.Assert(InFlight == null, "InFlight == null");
InFlight = GCHandle.Alloc(this, GCHandleType.Normal);
}
}
}
// Note that we could not use SafeHandle.DangerousAddRef() and DangerousRelease()
// because we could get to zero InFlightCounter multiple times across lifetime of the JSObject
// we only want JSObject to be disposed (from GC finalizer) once there is no in-flight reference and also no natural C# reference
internal void ReleaseInFlight()
{
lock (ProxyContext)
{
Debug.Assert(InFlightCounter != 0, "InFlightCounter != 0");
InFlightCounter--;
if (InFlightCounter == 0)
{
Debug.Assert(InFlight.HasValue, "InFlight.HasValue");
InFlight.Value.Free();
InFlight = null;
}
}
}
#endif
/// <inheritdoc />
public override bool Equals([NotNullWhen(true)] object? obj) => obj is JSObject other && JSHandle == other.JSHandle;

View file

@ -469,69 +469,6 @@ namespace System.Runtime.InteropServices.JavaScript
#endregion
#region Legacy
// legacy
public void RegisterCSOwnedObject(JSObject proxy)
{
lock (this)
{
ThreadCsOwnedObjects[(int)proxy.JSHandle] = new WeakReference<JSObject>(proxy, trackResurrection: true);
}
}
// legacy
public JSObject? GetCSOwnedObjectByJSHandle(nint jsHandle, int shouldAddInflight)
{
lock (this)
{
if (ThreadCsOwnedObjects.TryGetValue(jsHandle, out WeakReference<JSObject>? reference))
{
reference.TryGetTarget(out JSObject? jsObject);
if (shouldAddInflight != 0)
{
jsObject?.AddInFlight();
}
return jsObject;
}
}
return null;
}
// legacy
public JSObject CreateCSOwnedProxy(nint jsHandle, LegacyHostImplementation.MappedType mappedType, int shouldAddInflight)
{
lock (this)
{
JSObject? res = null;
if (!ThreadCsOwnedObjects.TryGetValue(jsHandle, out WeakReference<JSObject>? reference) ||
!reference.TryGetTarget(out res) ||
res.IsDisposed)
{
#pragma warning disable CS0612 // Type or member is obsolete
res = mappedType switch
{
LegacyHostImplementation.MappedType.JSObject => new JSObject(jsHandle, JSProxyContext.MainThreadContext),
LegacyHostImplementation.MappedType.Array => new Array(jsHandle),
LegacyHostImplementation.MappedType.ArrayBuffer => new ArrayBuffer(jsHandle),
LegacyHostImplementation.MappedType.DataView => new DataView(jsHandle),
LegacyHostImplementation.MappedType.Function => new Function(jsHandle),
LegacyHostImplementation.MappedType.Uint8Array => new Uint8Array(jsHandle),
_ => throw new ArgumentOutOfRangeException(nameof(mappedType))
};
#pragma warning restore CS0612 // Type or member is obsolete
ThreadCsOwnedObjects[jsHandle] = new WeakReference<JSObject>(res, trackResurrection: true);
}
if (shouldAddInflight != 0)
{
res.AddInFlight();
}
return res;
}
}
#endregion
#region Dispose
private void Dispose(bool disposing)

View file

@ -1,122 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
namespace System.Runtime.InteropServices.JavaScript
{
/// <summary>
/// Initializes a new instance of JavaScript Core Array class.
/// </summary>
[Obsolete]
public class Array : JSObject
{
/// <summary>
/// Initializes a new instance of the Array class.
/// </summary>
/// <param name="_params">Parameters.</param>
public Array(params object[] _params)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(Array), _params), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
/// <summary>
/// Initializes a new instance of the Array/> class.
/// </summary>
/// <param name="jsHandle">Js handle.</param>
internal Array(IntPtr jsHandle) : base(jsHandle, JSProxyContext.MainThreadContext)
{ }
/// <summary>
/// Push the specified elements.
/// </summary>
/// <returns>The new length of the Array push was called on.</returns>
/// <param name="elements">Elements.</param>
public int Push(params object[] elements) => (int)this.Invoke("push", elements);
/// <summary>
/// Pop this instance.
/// </summary>
/// <returns>The element removed from the array or null if the array was empty.</returns>
public object Pop() => (object)this.Invoke("pop");
/// <summary>
/// Remove the first element of the Array and return that element
/// </summary>
/// <returns>The removed element.</returns>
public object Shift() => this.Invoke("shift");
/// <summary>
/// Add <paramref name="elements"/> to the array starting at index <c>0</c>
/// </summary>
/// <returns>The length after shift.</returns>
/// <param name="elements">Elements.</param>
public int UnShift(params object[] elements) => (int)this.Invoke("unshift", elements);
/// <summary>
/// Index of the search element.
/// </summary>
/// <returns>The index of first occurrence of searchElement in the Array or -1 if not Found.</returns>
/// <param name="searchElement">Search element.</param>
/// <param name="fromIndex">The index to start the search from.</param>
public int IndexOf(object searchElement, int fromIndex = 0) => (int)this.Invoke("indexOf", searchElement, fromIndex);
/// <summary>
/// Finds the index of the last occurrence of<paramref name="searchElement" />
/// </summary>
/// <returns>The index of the last occurrence.</returns>
/// <param name="searchElement">Search element.</param>
public int LastIndexOf(object searchElement) => (int)this.Invoke("lastIndexOf", searchElement);
/// <summary>
/// Finds the index of the last occurrence of<paramref name="searchElement" /> between 0 and <paramref name="endIndex" />.
/// </summary>
/// <returns>The index of the last occurrence.</returns>
/// <param name="searchElement">Search element.</param>
/// <param name="endIndex">End index.</param>
public int LastIndexOf(object searchElement, int endIndex) => (int)this.Invoke("lastIndexOf", searchElement, endIndex);
/// <summary>
/// Gets or sets the Array with the index specified by <paramref name="i" />.
/// </summary>
/// <param name="i">The index.</param>
public object this[int i]
{
get
{
this.AssertNotDisposed();
Interop.Runtime.GetByIndexRef(JSHandle, i, out int exception, out object indexValue);
if (exception != 0)
throw new JSException((string)indexValue);
LegacyHostImplementation.ReleaseInFlight(indexValue);
return indexValue;
}
set
{
this.AssertNotDisposed();
Interop.Runtime.SetByIndexRef(JSHandle, i, value, out int exception, out object res);
if (exception != 0)
throw new JSException((string)res);
}
}
/// <summary>
/// Gets or sets the length.
/// </summary>
/// <value>The length.</value>
public int Length
{
get => Convert.ToInt32(this.GetObjectProperty("length"));
set => this.SetObjectProperty("length", value, false);
}
}
}

View file

@ -1,56 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.InteropServices.JavaScript
{
[Obsolete]
public class ArrayBuffer : JSObject
{
/// <summary>
/// Initializes a new instance of the JavaScript Core ArrayBuffer class.
/// </summary>
/// <param name="length">Length.</param>
public ArrayBuffer(int length)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(ArrayBuffer), new object[] { length }), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
/// <summary>
/// Initializes a new instance of the JavaScript Core ArrayBuffer class.
/// </summary>
/// <param name="jsHandle">Js handle.</param>
internal ArrayBuffer(IntPtr jsHandle) : base(jsHandle, JSProxyContext.MainThreadContext)
{ }
/// <summary>
/// The length of an ArrayBuffer in bytes.
/// </summary>
/// <value>The length of the underlying ArrayBuffer in bytes.</value>
public int ByteLength => (int)this.GetObjectProperty("byteLength");
/// <summary>
/// Gets a value indicating whether this ArrayBuffer is view.
/// </summary>
/// <value><see langword="true"/> if is view; otherwise, <see langword="false"/>.</value>
public bool IsView => (bool)this.GetObjectProperty("isView");
/// <summary>
/// Slice the specified begin.
/// </summary>
/// <returns>The slice.</returns>
/// <param name="begin">Begin.</param>
public ArrayBuffer Slice(int begin) => (ArrayBuffer)this.Invoke("slice", begin);
/// <summary>
/// Slice the specified begin and end.
/// </summary>
/// <returns>The slice.</returns>
/// <param name="begin">Begin.</param>
/// <param name="end">End.</param>
public ArrayBuffer Slice(int begin, int end) => (ArrayBuffer)this.Invoke("slice", begin, end);
}
}

View file

@ -1,233 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.InteropServices.JavaScript
{
/// <summary>
/// The DataView view provides a low-level interface for reading and writing multiple number types in a
/// binary ArrayBuffer, without having to care about the platform's endianness.
/// </summary>
[Obsolete]
public class DataView : JSObject
{
/// <summary>
/// Initializes a new instance of the DataView class.
/// </summary>
/// <param name="buffer">ArrayBuffer to use as the storage backing the new DataView object.</param>
public DataView(ArrayBuffer buffer)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(DataView), new object[] { buffer }), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
/// <summary>
/// Initializes a new instance of the DataView class.
/// </summary>
/// <param name="buffer">ArrayBuffer to use as the storage backing the new DataView object.</param>
/// <param name="byteOffset">The offset, in bytes, to the first byte in the above buffer for the new view to reference. If unspecified, the buffer view starts with the first byte.</param>
public DataView(ArrayBuffer buffer, int byteOffset)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(DataView), new object[] { buffer, byteOffset }), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
/// <summary>
/// Initializes a new instance of the DataView class.
/// </summary>
/// <param name="buffer">ArrayBuffer to use as the storage backing the new DataView object.</param>
/// <param name="byteOffset">The offset, in bytes, to the first byte in the above buffer for the new view to reference. If unspecified, the buffer view starts with the first byte.</param>
/// <param name="byteLength">The number of elements in the byte array. If unspecified, the view's length will match the buffer's length.</param>
public DataView(ArrayBuffer buffer, int byteOffset, int byteLength)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(DataView), new object[] { buffer, byteOffset, byteLength }), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
/// <summary>
/// Initializes a new instance of the DataView class.
/// </summary>
/// <param name="jsHandle">Js handle.</param>
internal DataView(IntPtr jsHandle) : base(jsHandle, JSProxyContext.MainThreadContext)
{ }
/// <summary>
/// Gets the length (in bytes) of this view from the start of its ArrayBuffer. Fixed at construction time and thus read only.
/// </summary>
/// <value>The length (in bytes) of this view.</value>
public int ByteLength => (int)this.GetObjectProperty("byteLength");
/// <summary>
/// Gets the offset (in bytes) of this view from the start of its ArrayBuffer. Fixed at construction time and thus read only.
/// </summary>
/// <value>The offset (in bytes) of this view.</value>
public int ByteOffset => (int)this.GetObjectProperty("byteOffset");
/// <summary>
/// Gets the ArrayBuffer referenced by this view. Fixed at construction time and thus read only.
/// </summary>
/// <value>The ArrayBuffer.</value>
public ArrayBuffer Buffer => (ArrayBuffer)this.GetObjectProperty("buffer");
/// <summary>
/// Gets the signed 32-bit float (float) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A signed 32-bit float number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the 32-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public float GetFloat32(int byteOffset, bool littleEndian = false) => UnBoxValue<float>(this.Invoke("getFloat32", byteOffset, littleEndian));
/// <summary>
/// Gets the signed 64-bit double (double) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A signed 64-bit coulbe number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the 64-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public double GetFloat64(int byteOffset, bool littleEndian = false) => UnBoxValue<double>(this.Invoke("getFloat64", byteOffset, littleEndian));
/// <summary>
/// Gets the signed 16-bit integer (short) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A signed 16-bit ineger (short) number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the 16-bit integer (short) is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public short GetInt16(int byteOffset, bool littleEndian = false) => UnBoxValue<short>(this.Invoke("getInt16", byteOffset, littleEndian));
/// <summary>
/// Gets the signed 32-bit integer (int) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A signed 32-bit ineger (int) number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the 32-bit integer (int) is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public int GetInt32(int byteOffset, bool littleEndian = false) => UnBoxValue<int>(this.Invoke("getInt32", byteOffset, littleEndian));
/// <summary>
/// Gets the signed 8-bit byte (sbyte) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A signed 8-bit byte (sbyte) number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the 8-bit byte is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
[CLSCompliant(false)]
public sbyte GetInt8(int byteOffset, bool littleEndian = false) => UnBoxValue<sbyte>(this.Invoke("getInt8", byteOffset, littleEndian));
/// <summary>
/// Gets the unsigned 16-bit integer (short) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A unsigned 16-bit integer (ushort) number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the unsigned 16-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
[CLSCompliant(false)]
public ushort GetUint16(int byteOffset, bool littleEndian = false) => UnBoxValue<ushort>(this.Invoke("getUint16", byteOffset, littleEndian));
/// <summary>
/// Gets the usigned 32-bit integer (uint) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A usigned 32-bit ineger (uint) number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the 32-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
[CLSCompliant(false)]
public uint GetUint32(int byteOffset, bool littleEndian = false) => UnBoxValue<uint>(this.Invoke("getUint32", byteOffset, littleEndian));
/// <summary>
/// Gets the unsigned 8-bit byte (byte) at the specified byte offset from the start of the DataView.
/// </summary>
/// <returns>A unsigned 8-bit byte (byte) number.</returns>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="littleEndian">Indicates whether the 32-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public byte GetUint8(int byteOffset, bool littleEndian = false) => UnBoxValue<byte>(this.Invoke("getUint8", byteOffset, littleEndian));
/// <summary>
/// Sets the signed 32-bit float (float) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">float value.</param>
/// <param name="littleEndian">Indicates whether the 32-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public void SetFloat32(int byteOffset, float value, bool littleEndian = false) => this.Invoke("setFloat32", byteOffset, value, littleEndian);
/// <summary>
/// Sets the signed 64-bit double (double) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">double value.</param>
/// <param name="littleEndian">Indicates whether the 64-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public void SetFloat64(int byteOffset, double value, bool littleEndian = false) => this.Invoke("setFloat64", byteOffset, value, littleEndian);
/// <summary>
/// Sets the signed 16-bit integer (short) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">short value.</param>
/// <param name="littleEndian">Indicates whether the 16-bit integer (short) is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public void SetInt16(int byteOffset, short value, bool littleEndian = false) => this.Invoke("setInt16", byteOffset, value, littleEndian);
/// <summary>
/// Sets the signed 32-bit integer (int) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">int value.</param>
/// <param name="littleEndian">Indicates whether the 32-bit integer (int) is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public void SetInt32(int byteOffset, int value, bool littleEndian = false) => this.Invoke("setInt32", byteOffset, value, littleEndian);
/// <summary>
/// Sets the signed 8-bit byte (sbyte) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">sbyte value.</param>
/// <param name="littleEndian">Indicates whether the 8-bit byte is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
[CLSCompliant(false)]
public void SetInt8(int byteOffset, sbyte value, bool littleEndian = false) => this.Invoke("setInt8", byteOffset, value, littleEndian);
/// <summary>
/// Sets the unsigned 16-bit integer (short) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">ushort value.</param>
/// <param name="littleEndian">Indicates whether the unsigned 16-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
[CLSCompliant(false)]
public void SetUint16(int byteOffset, ushort value, bool littleEndian = false) => this.Invoke("setUint16", byteOffset, value, littleEndian);
/// <summary>
/// Sets the usigned 32-bit integer (uint) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">uint value.</param>
/// <param name="littleEndian">Indicates whether the 32-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
[CLSCompliant(false)]
public void SetUint32(int byteOffset, uint value, bool littleEndian = false) => this.Invoke("setUint32", byteOffset, value, littleEndian);
/// <summary>
/// Sets the unsigned 8-bit byte (sbyte) at the specified byte offset from the start of the DataView.
/// </summary>
/// <param name="byteOffset">Byte offset.</param>
/// <param name="value">byte value.</param>
/// <param name="littleEndian">Indicates whether the 32-bit float is stored in little- or big-endian format. If <c>false</c>, a big-endian value is read.</param>
public void SetUint8(int byteOffset, byte value, bool littleEndian = false) => this.Invoke("setUint8", byteOffset, value, littleEndian);
private static U UnBoxValue<U>(object jsValue) where U : struct
{
if (jsValue == null)
{
throw new InvalidCastException(SR.Format(SR.UnableCastNullToType, typeof(U)));
}
var type = jsValue.GetType();
if (type.IsPrimitive)
{
return (U)Convert.ChangeType(jsValue, typeof(U));
}
else
{
throw new InvalidCastException(SR.Format(SR.UnableCastObjectToType, type, typeof(U)));
}
}
}
}

View file

@ -1,66 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.InteropServices.JavaScript
{
/// <summary>
/// The Function constructor creates a new Function object.
/// </summary>
/// <remarks>
/// Calling the constructor directly can create functions dynamically, but suffers from security and similar
/// (but far less significant) performance issues similar to eval. However, unlike eval, the Function constructor
/// allows executing code in the global scope, prompting better programming habits and allowing for more efficient
/// code minification.
/// </remarks>
[Obsolete]
public class Function : JSObject
{
public Function(params object[] args)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(Function), args), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
internal Function(IntPtr jsHandle) : base(jsHandle, JSProxyContext.MainThreadContext)
{ }
/// <summary>
/// The Apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).
/// </summary>
/// <returns>The apply.</returns>
/// <param name="thisArg">This argument.</param>
/// <param name="argsArray">Arguments.</param>
public object Apply(object? thisArg, object[]? argsArray = null) => this.Invoke("apply", thisArg, argsArray);
/// <summary>
/// Creates a new Function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
/// </summary>
/// <returns>The bind.</returns>
/// <param name="thisArg">This argument.</param>
/// <param name="argsArray">Arguments.</param>
public Function Bind(object? thisArg, object[]? argsArray = null) => (Function)this.Invoke("bind", thisArg, argsArray);
/// <summary>
/// Calls a function with a given `this` value and arguments provided individually.
/// </summary>
/// <returns>The result of calling the function with the specified `this` value and arguments.</returns>
/// <param name="thisArg">Optional (null value). The value of this provided for the call to a function. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode, null and undefined will be replaced with the global object and primitive values will be converted to objects.</param>
/// <param name="argsArray">Optional. Arguments for the function.</param>
public object Call(object? thisArg, params object[] argsArray)
{
object?[] argsList = new object[argsArray.Length + 1];
argsList[0] = thisArg;
System.Array.Copy(argsArray, 0, argsList, 1, argsArray.Length);
return this.Invoke("call", argsList);
}
/// <summary>
/// Calls a function with a null `this` value.
/// </summary>
/// <returns>The result of calling the function.</returns>
public object Call() => Call(null);
}
}

View file

@ -1,226 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
namespace System.Runtime.InteropServices.JavaScript
{
[SupportedOSPlatform("browser")]
internal static class LegacyHostImplementation
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReleaseInFlight(object obj)
{
JSObject? jsObj = obj as JSObject;
jsObj?.ReleaseInFlight();
}
public static MarshalType GetMarshalTypeFromType(Type type)
{
if (type is null)
return MarshalType.VOID;
var typeCode = Type.GetTypeCode(type);
if (type.IsEnum)
{
switch (typeCode)
{
case TypeCode.Int32:
case TypeCode.UInt32:
return MarshalType.ENUM;
case TypeCode.Int64:
case TypeCode.UInt64:
return MarshalType.ENUM64;
default:
throw new ArgumentException(SR.Format(SR.UnsupportedEnumType, type.FullName), nameof(type));
}
}
switch (typeCode)
{
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
return MarshalType.INT;
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
return MarshalType.UINT32;
case TypeCode.Boolean:
return MarshalType.BOOL;
case TypeCode.Int64:
return MarshalType.INT64;
case TypeCode.UInt64:
return MarshalType.UINT64;
case TypeCode.Single:
return MarshalType.FP32;
case TypeCode.Double:
return MarshalType.FP64;
case TypeCode.String:
return MarshalType.STRING;
case TypeCode.Char:
return MarshalType.CHAR;
}
if (type.IsArray)
{
if (!type.IsSZArray)
throw new ArgumentException(SR.Format(SR.UnsupportedArrayType, type.FullName), nameof(type));
var elementType = type.GetElementType();
switch (Type.GetTypeCode(elementType))
{
case TypeCode.Byte:
return MarshalType.ARRAY_UBYTE;
case TypeCode.SByte:
return MarshalType.ARRAY_BYTE;
case TypeCode.Int16:
return MarshalType.ARRAY_SHORT;
case TypeCode.UInt16:
return MarshalType.ARRAY_USHORT;
case TypeCode.Int32:
return MarshalType.ARRAY_INT;
case TypeCode.UInt32:
return MarshalType.ARRAY_UINT;
case TypeCode.Single:
return MarshalType.ARRAY_FLOAT;
case TypeCode.Double:
return MarshalType.ARRAY_DOUBLE;
default:
throw new ArgumentException(SR.Format(SR.UnsupportedElementType, elementType), nameof(type));
}
}
else if (type == typeof(IntPtr))
return MarshalType.POINTER;
else if (type == typeof(UIntPtr))
return MarshalType.POINTER;
else if (type == typeof(SafeHandle))
return MarshalType.SAFEHANDLE;
else if (typeof(Delegate).IsAssignableFrom(type))
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;
if (type.IsValueType)
return MarshalType.VT;
else
return MarshalType.OBJECT;
}
public static char GetCallSignatureCharacterForMarshalType(MarshalType type, char? defaultValue)
{
switch (type)
{
case MarshalType.BOOL:
return 'b';
case MarshalType.UINT32:
case MarshalType.POINTER:
return 'I';
case MarshalType.INT:
return 'i';
case MarshalType.UINT64:
return 'L';
case MarshalType.INT64:
return 'l';
case MarshalType.FP32:
return 'f';
case MarshalType.FP64:
return 'd';
case MarshalType.STRING:
return 's';
case MarshalType.URI:
return 'u';
case MarshalType.SAFEHANDLE:
return 'h';
case MarshalType.ENUM:
return 'j'; // this is wrong for uint enums
case MarshalType.ENUM64:
return 'k'; // this is wrong for ulong enums
case MarshalType.TASK:
case MarshalType.DELEGATE:
case MarshalType.OBJECT:
return 'o';
case MarshalType.VT:
return 'a';
default:
if (defaultValue.HasValue)
return defaultValue.Value;
else
throw new ArgumentException(SR.Format(SR.UnsupportedLegacyMarshlerType, type), nameof(type));
}
}
// see src/mono/wasm/driver.c MARSHAL_TYPE_xxx
public enum MarshalType : int
{
NULL = 0,
INT = 1,
FP64 = 2,
STRING = 3,
VT = 4,
DELEGATE = 5,
TASK = 6,
OBJECT = 7,
BOOL = 8,
ENUM = 9,
URI = 22,
SAFEHANDLE = 23,
ARRAY_BYTE = 10,
ARRAY_UBYTE = 11,
ARRAY_UBYTE_C = 12,
ARRAY_SHORT = 13,
ARRAY_USHORT = 14,
ARRAY_INT = 15,
ARRAY_UINT = 16,
ARRAY_FLOAT = 17,
ARRAY_DOUBLE = 18,
FP32 = 24,
UINT32 = 25,
INT64 = 26,
UINT64 = 27,
CHAR = 28,
STRING_INTERNED = 29,
VOID = 30,
ENUM64 = 31,
POINTER = 32
}
// see src/mono/wasm/driver.c MARSHAL_ERROR_xxx
public enum MarshalError : int
{
BUFFER_TOO_SMALL = 512,
NULL_CLASS_POINTER = 513,
NULL_TYPE_POINTER = 514,
UNSUPPORTED_TYPE = 515,
FIRST = BUFFER_TOO_SMALL
}
// please keep BINDING wasm_type_symbol in sync
public enum MappedType
{
JSObject = 0,
Array = 1,
ArrayBuffer = 2,
DataView = 3,
Function = 4,
Uint8Array = 11,
}
#if FEATURE_WASM_THREADS
public static void ThrowIfLegacyWorkerThread()
{
if (Environment.CurrentManagedThreadId != 1)
{
throw new PlatformNotSupportedException("Legacy interop is not supported with WebAssembly threads.");
}
}
#endif
}
}

View file

@ -1,117 +0,0 @@
// 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.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace System.Runtime.InteropServices.JavaScript
{
[Obsolete]
public static class Runtime
{
public static object GetGlobalObject(string str)
=> JavaScriptImports.GetGlobalObject(str);
/// <summary>
/// Invoke a named method of the object, or throws a JSException on error.
/// </summary>
/// <param name="self">thisArg</param>
/// <param name="method">The name of the method to invoke.</param>
/// <param name="args">The argument list to pass to the invoke command.</param>
/// <returns>
/// <para>
/// The return value can either be a primitive (string, int, double), a JSObject for JavaScript objects, a
/// System.Threading.Tasks.Task(object) for JavaScript promises, an array of
/// a byte, int or double (for Javascript objects typed as ArrayBuffer) or a
/// System.Func to represent JavaScript functions. The specific version of
/// the Func that will be returned depends on the parameters of the Javascript function
/// and return value.
/// </para>
/// <para>
/// The value of a returned promise (The Task(object) return) can in turn be any of the above
/// valuews.
/// </para>
/// </returns>
public static object Invoke(this JSObject self, string method, params object?[] args)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
ArgumentNullException.ThrowIfNull(self);
self.AssertNotDisposed();
Interop.Runtime.InvokeJSWithArgsRef(self.JSHandle, method, args, out int exception, out object res);
if (exception != 0)
throw new JSException((string)res);
LegacyHostImplementation.ReleaseInFlight(res);
return res;
}
/// <summary>
/// Returns the named property from the object, or throws a JSException on error.
/// </summary>
/// <param name="self">thisArg</param>
/// <param name="name">The name of the property to lookup.</param>
/// <remarks>
/// This method can raise a JSException if fetching the property in Javascript raises an exception.
/// </remarks>
/// <returns>
/// <para>
/// The return value can either be a primitive (string, int, double), a
/// JSObject for JavaScript objects, a
/// System.Threading.Tasks.Task (object) for JavaScript promises, an array of
/// a byte, int or double (for Javascript objects typed as ArrayBuffer) or a
/// System.Func to represent JavaScript functions. The specific version of
/// the Func that will be returned depends on the parameters of the Javascript function
/// and return value.
/// </para>
/// <para>
/// The value of a returned promise (The Task(object) return) can in turn be any of the above
/// valuews.
/// </para>
/// </returns>
public static object GetObjectProperty(this JSObject self, string name)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
ArgumentNullException.ThrowIfNull(self);
self.AssertNotDisposed();
Interop.Runtime.GetObjectPropertyRef(self.JSHandle, name, out int exception, out object propertyValue);
if (exception != 0)
throw new JSException((string)propertyValue);
LegacyHostImplementation.ReleaseInFlight(propertyValue);
return propertyValue;
}
/// <summary>
/// Sets the named property to the provided value.
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="self">thisArg</param>
/// <param name="name">The name of the property to lookup.</param>
/// <param name="value">The value can be a primitive type (int, double, string, bool), an
/// array that will be surfaced as a typed ArrayBuffer (byte[], sbyte[], short[], ushort[],
/// float[], double[]) </param>
/// <param name="createIfNotExists">Defaults to <see langword="true"/> and creates the property on the javascript object if not found, if set to <see langword="false"/> it will not create the property if it does not exist. If the property exists, the value is updated with the provided value.</param>
/// <param name="hasOwnProperty"></param>
public static void SetObjectProperty(this JSObject self, string name, object? value, bool createIfNotExists = true, bool hasOwnProperty = false)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
ArgumentNullException.ThrowIfNull(self);
self.AssertNotDisposed();
Interop.Runtime.SetObjectPropertyRef(self.JSHandle, name, in value, createIfNotExists, hasOwnProperty, out int exception, out object res);
if (exception != 0)
throw new JSException(SR.Format(SR.ErrorLegacySettingProperty, name, self.JSHandle, res));
}
public static void AssertInFlight(this JSObject self, int expectedInFlightCount)
{
if (self.InFlightCounter != expectedInFlightCount) throw new InvalidOperationException(SR.Format(SR.UnsupportedLegacyMarshlerType, self.JSHandle, expectedInFlightCount, self.InFlightCounter));
}
}
}

View file

@ -1,84 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
namespace System.Runtime.InteropServices.JavaScript
{
[Obsolete]
public sealed class Uint8Array : JSObject
{
public Uint8Array(int length)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(Uint8Array), new object[] { length }), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
public Uint8Array(ArrayBuffer buffer)
: base(JavaScriptImports.CreateCSOwnedObject(nameof(Uint8Array), new object[] { buffer }), JSProxyContext.MainThreadContext)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
JSProxyContext.MainThreadContext.RegisterCSOwnedObject(this);
}
internal Uint8Array(IntPtr jsHandle) : base(jsHandle, JSProxyContext.MainThreadContext)
{ }
public int Length
{
get => Convert.ToInt32(this.GetObjectProperty("length"));
set => this.SetObjectProperty("length", value, false);
}
/// <summary>
/// Defines an implicit conversion of JavaScript Core Uint8Array class to a Span&lt;byte&gt;
/// </summary>
public static implicit operator Span<byte>(Uint8Array typedarray) => typedarray.ToArray();
public static implicit operator Uint8Array(Span<byte> span) => From(span);
public byte[] ToArray()
{
this.AssertNotDisposed();
Interop.Runtime.TypedArrayToArrayRef(JSHandle, out int exception, out object res);
if (exception != 0)
throw new JSException((string)res);
return (byte[])res;
}
public static unsafe Uint8Array From(ReadOnlySpan<byte> span)
{
#if FEATURE_WASM_THREADS
LegacyHostImplementation.ThrowIfLegacyWorkerThread();
#endif
// source has to be instantiated.
if (span == null)
{
throw new System.ArgumentException(SR.Format(SR.ArgumentCannotBeNull, nameof(span)), nameof(span));
}
ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(span);
fixed (byte* ptr = bytes)
{
Interop.Runtime.TypedArrayFromRef((int)ptr, 0, span.Length, sizeof(byte), (int)TypedArrayTypeCode.Uint8Array, out int exception, out object res);
if (exception != 0)
throw new JSException((string)res);
var r = (Uint8Array)res;
r.ReleaseInFlight();
return r;
}
}
public enum TypedArrayTypeCode
{
Uint8Array = 6,
}
}
}

View file

@ -1,38 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFramework>$(NetCoreAppCurrent)-browser</TargetFramework>
<TestRuntime>true</TestRuntime>
<WasmXHarnessArgs>$(WasmXHarnessArgs) --engine-arg=--expose-gc --web-server-use-cop</WasmXHarnessArgs>
<NoWarn>0612</NoWarn>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<DefineConstants Condition="'$(WasmEnableLegacyJsInterop)' == 'false'">$(DefineConstants);DISABLE_LEGACY_JS_INTEROP</DefineConstants>
<Scenario>WasmTestOnBrowser</Scenario>
<!-- this unit test depends on legacy JavaScript interop and and is only supported in UI thread. -->
<_XUnitBackgroundExec>false</_XUnitBackgroundExec>
</PropertyGroup>
<ItemGroup Condition="'$(WasmEnableLegacyJsInterop)' != 'false'">
<Compile Include="System\Runtime\InteropServices\JavaScript\JavaScriptTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\DataViewTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\MemoryTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\TypedArrayTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\ArrayTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\MarshalTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\DelegateTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\HelperMarshal.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Http\HttpRequestMessageTest.cs" />
<Compile Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\tests\System.Runtime.InteropServices.JavaScript.UnitTests\System\Runtime\InteropServices\JavaScript\Utils.cs" Link="System\Runtime\InteropServices\JavaScript\Utils.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="System\Runtime\InteropServices\JavaScript\ParallelTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\TimerTests.cs" />
</ItemGroup>
<ItemGroup>
<WasmExtraFilesToDeploy Include="timers.mjs" />
<None Include="timers.mjs" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\src\System.Runtime.InteropServices.JavaScript.csproj" SkipUseReferenceAssembly="true"/>
</ItemGroup>
</Project>

View file

@ -1,173 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using Xunit;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class ArrayTests
{
[Fact]
public static void ArrayLength()
{
Array d = new Array();
Assert.Equal(0, d.Length);
}
[Fact]
public static void ArrayLength1()
{
Array d = new Array(50);
Assert.Equal(50, d.Length);
}
[Fact]
public static void Array_GetSetItem()
{
var jsArray = new Array(7, 8, 9, 10, 11, 12, 13);
IList<int> iList = new int[] { 7, 8, 9, 10, 11, 12, 13 };
Assert.Equal(jsArray.Length, iList.Count);
for (int i = 0; i < iList.Count; i++)
{
Assert.Equal(jsArray[i], iList[i]);
iList[i] = 99;
jsArray[i] = 99;
Assert.Equal(99, iList[i]);
Assert.Equal(99, jsArray[i]);
}
}
[Fact]
public static void Array_GetSetItemInvalid()
{
var jsArray = new Array(7, 8, 9, 10, 11, 12, 13);
Assert.Null(jsArray[-1]);
Assert.Null(jsArray[jsArray.Length]);
Assert.Equal(0, jsArray[-1] = 0);
Assert.Equal(0, jsArray[jsArray.Length] = 0);
}
[Fact]
public static void Array_GetItemIndex()
{
var jsArray = new Array(7, 8, 9, 10, 11, 12, 13);
Assert.Equal(7, jsArray[0]);
Assert.Equal(8, jsArray[1]);
Assert.Equal(9, jsArray[2]);
Assert.Equal(10, jsArray[3]);
Assert.Equal(11, jsArray[4]);
Assert.Equal(12, jsArray[5]);
Assert.Equal(13, jsArray[6]);
}
[Fact]
public static void Array_GetSetItemIndex()
{
var jsArray = new Array(7, 8, 9, 10, 11, 12, 13);
for (int d = 0; d < jsArray.Length; d++)
{
jsArray[d] = (int)jsArray[d] + 1;
}
Assert.Equal(8, jsArray[0]);
Assert.Equal(9, jsArray[1]);
Assert.Equal(10, jsArray[2]);
Assert.Equal(11, jsArray[3]);
Assert.Equal(12, jsArray[4]);
Assert.Equal(13, jsArray[5]);
Assert.Equal(14, jsArray[6]);
}
[Fact]
public static void Array_Pop()
{
var jsArray = new Array(7, 8, 9, 10, 11, 12, 13);
Assert.Equal(13, jsArray.Pop());
Assert.Equal(12, jsArray.Pop());
Assert.Equal(11, jsArray.Pop());
Assert.Equal(10, jsArray.Pop());
Assert.Equal(9, jsArray.Pop());
Assert.Equal(8, jsArray.Pop());
Assert.Equal(7, jsArray.Pop());
Assert.Equal(0, jsArray.Length);
}
[Fact]
public static void Array_PushPop()
{
var objArray = new object[] { "test7", "test8", "test9", "test10", "test11", "test12", "test13" };
var jsArray = new Array();
for (int d = 0; d < objArray.Length; d++)
{
jsArray.Push(objArray[d]);
}
Assert.Equal("test13", jsArray.Pop());
Assert.Equal("test12", jsArray.Pop());
Assert.Equal("test11", jsArray.Pop());
Assert.Equal("test10", jsArray.Pop());
Assert.Equal("test9", jsArray.Pop());
Assert.Equal("test8", jsArray.Pop());
Assert.Equal("test7", jsArray.Pop());
Assert.Equal(0, jsArray.Length);
}
[Fact]
public static void Array_PushShift()
{
var objArray = new object[] { "test7", "test8", "test9", "test10", "test11", "test12", "test13" };
var jsArray = new Array();
for (int d = 0; d < objArray.Length; d++)
{
jsArray.Push(objArray[d]);
}
Assert.Equal("test7", jsArray.Shift());
Assert.Equal("test8", jsArray.Shift());
Assert.Equal("test9", jsArray.Shift());
Assert.Equal("test10", jsArray.Shift());
Assert.Equal("test11", jsArray.Shift());
Assert.Equal("test12", jsArray.Shift());
Assert.Equal("test13", jsArray.Shift());
Assert.Equal(0, jsArray.Length);
}
[Fact]
public static void Array_UnShiftShift()
{
var objArray = new object[] { "test7", "test8", "test9", "test10", "test11", "test12", "test13" };
var jsArray = new Array();
for (int d = 0; d < objArray.Length; d++)
{
Assert.Equal(d + 1, jsArray.UnShift(objArray[d]));
}
Assert.Equal("test13", jsArray.Shift());
Assert.Equal("test12", jsArray.Shift());
Assert.Equal("test11", jsArray.Shift());
Assert.Equal("test10", jsArray.Shift());
Assert.Equal("test9", jsArray.Shift());
Assert.Equal("test8", jsArray.Shift());
Assert.Equal("test7", jsArray.Shift());
Assert.Equal(0, jsArray.Length);
}
[Fact]
public static void Array_IndexOf()
{
var beasts = new Array("ant", "bison", "camel", "duck", "bison");
Assert.Equal(1, beasts.IndexOf("bison"));
Assert.Equal(4, beasts.IndexOf("bison", 2));
Assert.Equal(-1, beasts.IndexOf("giraffe"));
}
[Fact]
public static void Array_LastIndexOf()
{
var beasts = new Array("Dodo", "Tiger", "Penguin", "Dodo");
Assert.Equal(3, beasts.LastIndexOf("Dodo"));
Assert.Equal(1, beasts.LastIndexOf("Tiger"));
Assert.Equal(0, beasts.LastIndexOf("Dodo", 2)); // The array is searched backwards
Assert.Equal(-1, beasts.LastIndexOf("giraffe"));
}
}
}

View file

@ -1,134 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using Xunit;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class DataViewTests
{
[Fact]
public static void DataViewConstructor()
{
// create an ArrayBuffer with a size in bytes
var buffer = new ArrayBuffer(16);
// Create a couple of views
var view1 = new DataView(buffer);
var view2 = new DataView(buffer, 12, 4); //from byte 12 for the next 4 bytes
view1.SetInt8(12, 42); // put 42 in slot 12
Assert.Equal(42, view2.GetInt8(0));
}
public static IEnumerable<object[]> ArrayBuffer_Test_Data()
{
yield return new object[] { new ArrayBuffer(12) };
}
[Theory]
[MemberData(nameof(ArrayBuffer_Test_Data))]
public static void DataViewArrayBuffer(ArrayBuffer buffer)
{
var x = new DataView(buffer);
Assert.True(buffer == x.Buffer);
}
[Theory]
[MemberData(nameof(ArrayBuffer_Test_Data))]
public static void DataViewByteLength(ArrayBuffer buffer)
{
var x = new DataView(buffer, 4, 2);
Assert.Equal(2, x.ByteLength);
}
[Theory]
[MemberData(nameof(ArrayBuffer_Test_Data))]
public static void DataViewByteOffset(ArrayBuffer buffer)
{
var x = new DataView(buffer, 4, 2);
Assert.Equal(4, x.ByteOffset);
}
public static IEnumerable<object[]> DataView_Test_Data()
{
yield return new object[] { new DataView(new ArrayBuffer(12), 0) };
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetFloat32(DataView view)
{
view.SetFloat32(1, (float)Math.PI);
Assert.Equal((float)Math.Round(Math.PI, 5), (float)Math.Round(view.GetFloat32(1), 5));
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetFloat64(DataView view)
{
view.SetFloat64(1, (float)Math.PI);
Assert.Equal(Math.Round(Math.PI, 5), Math.Round(view.GetFloat64(1), 5));
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetInt16(DataView view)
{
view.SetInt16(1, 1234);
Assert.Equal(1234, view.GetInt16(1));
view.SetInt16(1, -1234);
Assert.Equal(-1234, view.GetInt16(1));
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetInt32(DataView view)
{
view.SetInt32(1, 1234);
Assert.Equal(1234, view.GetInt32(1));
view.SetInt32(1, -1234);
Assert.Equal(-1234, view.GetInt32(1));
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetInt8(DataView view)
{
view.SetInt8(1, 123);
Assert.Equal(123, view.GetInt8(1));
view.SetInt8(1, -123);
Assert.Equal(-123, view.GetInt8(1));
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetUint16(DataView view)
{
view.SetUint16(1, 1234);
Assert.Equal(1234, view.GetUint16(1));
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetUint32(DataView view)
{
view.SetUint32(1, 1234);
Assert.Equal(1234u, view.GetUint32(1));
}
[Theory]
[MemberData(nameof(DataView_Test_Data))]
public static void DataViewGetUint8(DataView view)
{
view.SetUint8(1, 123);
Assert.Equal(123u, view.GetUint8(1));
}
}
}

View file

@ -1,449 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
using System.Runtime.InteropServices.JavaScript;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class DelegateTests
{
private static Function _objectPrototype;
[Fact]
public static void InvokeFunction()
{
HelperMarshal._functionResultValue = 0;
HelperMarshal._i32Value = 0;
Utils.InvokeJS(@"
var funcDelegate = App.call_test_method (""CreateFunctionDelegate"", [ ]);
var res = funcDelegate (10, 20);
App.call_test_method (""InvokeI32"", [ res, res ]);
");
Assert.Equal(30, HelperMarshal._functionResultValue);
Assert.Equal(60, HelperMarshal._i32Value);
}
[Fact]
public static void InvokeFunctionInLoopUsingConstanceValues()
{
HelperMarshal._functionResultValue = 0;
HelperMarshal._i32Value = 0;
Utils.InvokeJS(@"
var funcDelegate = App.call_test_method (""CreateFunctionDelegate"", [ ]);
var res = funcDelegate (10, 20);
for (let x = 0; x < 1000; x++)
{
res = funcDelegate (10, 20);
}
App.call_test_method (""InvokeI32"", [ res, res ]);
");
Assert.Equal(30, HelperMarshal._functionResultValue);
Assert.Equal(60, HelperMarshal._i32Value);
}
[Fact]
public static void InvokeFunctionInLoopUsingIncrementedValues()
{
HelperMarshal._functionResultValue = 0;
HelperMarshal._i32Value = 0;
Utils.InvokeJS(@"
var funcDelegate = App.call_test_method (""CreateFunctionDelegate"", [ ]);
var res = funcDelegate (10, 20);
for (let x = 0; x < 1000; x++)
{
res = funcDelegate (x, x);
}
App.call_test_method (""InvokeI32"", [ res, res ]);
");
Assert.Equal(1998, HelperMarshal._functionResultValue);
Assert.Equal(3996, HelperMarshal._i32Value);
}
[Fact]
public static void InvokeActionTReturnedByInvokingFuncT()
{
HelperMarshal._functionActionResultValue = 0;
HelperMarshal._functionActionResultValueOfAction = 0;
Utils.InvokeJS(@"
var funcDelegate = App.call_test_method (""CreateFunctionDelegateWithAction"", [ ]);
var actionDelegate = funcDelegate (10, 20);
actionDelegate(30,40);
");
Assert.Equal(30, HelperMarshal._functionActionResultValue);
Assert.Equal(70, HelperMarshal._functionActionResultValueOfAction);
}
[Fact]
public static void InvokeActionIntInt()
{
HelperMarshal._actionResultValue = 0;
Utils.InvokeJS(@"
var actionDelegate = App.call_test_method (""CreateActionDelegate"", [ ]);
actionDelegate(30,40);
");
Assert.Equal(70, HelperMarshal._actionResultValue);
}
[Fact]
public static void InvokeActionFloatIntToIntInt()
{
HelperMarshal._actionResultValue = 0;
var ex = Assert.Throws<JSException>(()=>Utils.InvokeJS(@"
var actionDelegate = App.call_test_method (""CreateActionDelegate"", [ ]);
actionDelegate(3.14,40);
"));
Assert.Contains("Value is not an integer: 3.14 (number)", ex.Message);
Assert.Equal(0, HelperMarshal._actionResultValue);
}
[Fact]
public static void InvokeDelegateMethod()
{
HelperMarshal._delMethodResultValue = string.Empty;
Utils.InvokeJS(@"
var del = App.call_test_method (""CreateDelegateMethod"", [ ]);
del(""Hic sunt dracones"");
");
Assert.Equal("Hic sunt dracones", HelperMarshal._delMethodResultValue);
}
[Fact]
public static void InvokeDelegateMethodReturnString()
{
HelperMarshal._delMethodStringResultValue = string.Empty;
Utils.InvokeJS(@"
var del = App.call_test_method (""CreateDelegateMethodReturnString"", [ ]);
var res = del(""Hic sunt dracones"");
App.call_test_method (""SetTestString1"", [ res ]);
");
Assert.Equal("Received: Hic sunt dracones", HelperMarshal._delMethodStringResultValue);
}
[Theory]
[InlineData("CreateCustomMultiCastDelegate_VoidString", "Moin")]
[InlineData("CreateMultiCastAction_VoidString", "MoinMoin")]
public static void InvokeMultiCastDelegate_VoidString(string creator, string testStr)
{
HelperMarshal._delegateCallResult = string.Empty;
Utils.InvokeJS($@"
var del = App.call_test_method (""{creator}"", [ ]);
del(""{testStr}"");
");
Assert.Equal($" Hello, {testStr}! GoodMorning, {testStr}!", HelperMarshal._delegateCallResult);
}
[Theory]
[InlineData("CreateDelegateFromAnonymousMethod_VoidString")]
[InlineData("CreateDelegateFromLambda_VoidString")]
[InlineData("CreateDelegateFromMethod_VoidString")]
[InlineData("CreateActionT_VoidString")]
public static void InvokeDelegate_VoidString(string creator)
{
HelperMarshal._delegateCallResult = string.Empty;
var s = Utils.InvokeJS($@"
var del = App.call_test_method (""{creator}"", [ ]);
del(""Hic sunt dracones"");
");
Assert.Equal("Notification received for: Hic sunt dracones", HelperMarshal._delegateCallResult);
}
public static IEnumerable<object[]> ArrayType_TestData()
{
_objectPrototype ??= new Function("return Object.prototype.toString;");
yield return new object[] { _objectPrototype.Call(), "Uint8Array", Uint8Array.From(new byte[10]) };
yield return new object[] { _objectPrototype.Call(), "Array", new Array(10) };
}
[Theory]
[MemberData(nameof(ArrayType_TestData))]
public static void InvokeFunctionAcceptingArrayTypes(Function objectPrototype, string creator, JSObject arrayType)
{
HelperMarshal._funcActionBufferObjectResultValue = arrayType;
Assert.Equal(10, HelperMarshal._funcActionBufferObjectResultValue.GetObjectProperty("length"));
Assert.Equal($"[object {creator}]", objectPrototype.Call(HelperMarshal._funcActionBufferObjectResultValue));
Utils.InvokeJS($@"
var buffer = new {creator}(50);
var del = App.call_test_method (""CreateFunctionAccepting{creator}"", [ ]);
var setAction = del(buffer);
setAction(buffer);
");
Assert.Equal(50, HelperMarshal._funcActionBufferObjectResultValue.GetObjectProperty("length"));
Assert.Equal(HelperMarshal._funcActionBufferObjectResultValue.GetObjectProperty("length"), HelperMarshal._funcActionBufferResultLengthValue);
Assert.Equal($"[object {creator}]", objectPrototype.Call(HelperMarshal._funcActionBufferObjectResultValue));
}
[Fact]
public static void DispatchToDelegate()
{
var factory = new Function(@"return {
callback: null,
eventFactory:function(data){
return {
data:data
};
},
fireEvent: function (evt) {
this.callback(evt);
}
};");
var dispatcher = (JSObject)factory.Call();
var temp = new bool[2];
Action<JSObject> cb = (JSObject envt) =>
{
var data = (int)envt.GetObjectProperty("data");
temp[data] = true;
};
dispatcher.SetObjectProperty("callback", cb);
var evnt0 = dispatcher.Invoke("eventFactory", 0);
var evnt1 = dispatcher.Invoke("eventFactory", 1);
dispatcher.Invoke("fireEvent", evnt0);
dispatcher.Invoke("fireEvent", evnt0);
dispatcher.Invoke("fireEvent", evnt1);
Assert.True(temp[0]);
Assert.True(temp[1]);
}
[Fact]
public static void EventsAreNotCollected()
{
const int attempts = 100; // we fire 100 events in a loop, to try that it's GC same
var factory = new Function(@"return {
callback: null,
eventFactory:function(data){
return {
data:data
};
},
fireEvent: function (evt) {
this.callback(evt);
}
};");
var dispatcher = (JSObject)factory.Call();
var temp = new bool[attempts];
Action<JSObject> cb = (JSObject envt) =>
{
ObjectDisposedException.ThrowIf(envt.IsDisposed, envt);
envt.AssertInFlight(0);
var data = (int)envt.GetObjectProperty("data");
temp[data] = true;
};
dispatcher.SetObjectProperty("callback", cb);
var evnt = dispatcher.Invoke("eventFactory", 0);
for (int i = 0; i < attempts; i++)
{
var evnti = dispatcher.Invoke("eventFactory", i);
dispatcher.Invoke("fireEvent", evnti);
dispatcher.Invoke("fireEvent", evnt);
Utils.InvokeJS("if (globalThis.gc) globalThis.gc();");// needs v8 flag --expose-gc
}
}
[Fact]
public static void NullDelegate()
{
var factory = new Function("delegate", "callback", @"
callback(delegate);
");
Delegate check = null;
Action<Delegate> callback = (Delegate data) =>
{
check = data;
};
factory.Call(null, null, callback);
Assert.Null(check);
}
[Fact]
public static async Task ResolveStringPromise()
{
var factory = new Function(@"
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo');
}, 10);
});");
var promise = (Task<object>)factory.Call();
var value = await promise;
Assert.Equal("foo", (string)value);
}
[Fact]
public static async Task ResolveJSObjectPromise()
{
for (int i = 0; i < 10; i++)
{
var factory = new Function(@"
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({foo:'bar'});
}, 10);
});");
var promise = (Task<object>)factory.Call();
var value = (JSObject)await promise;
Assert.Equal("bar", value.GetObjectProperty("foo"));
Utils.InvokeJS("if (globalThis.gc) globalThis.gc();");// needs v8 flag --expose-gc
}
}
[Fact]
public static async Task RejectPromise()
{
var factory = new Function(@"
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('fail');
}, 10);
});");
var promise = (Task<object>)factory.Call();
var ex = await Assert.ThrowsAsync<JSException>(async () => await promise);
Assert.Equal("fail", ex.Message);
}
[Fact]
public static async Task RejectPromiseError()
{
var factory = new Function(@"
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('fail'));
}, 10);
});");
var promise = (Task<object>)factory.Call();
var ex = await Assert.ThrowsAsync<JSException>(async () => await promise);
Assert.Equal("Error: fail", ex.Message);
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/56963")]
[Fact]
public static void RoundtripPromise()
{
var factory = new Function(@"
var dummy=new Promise((resolve, reject) => {});
return {
dummy:dummy,
check:(promise)=>{
return promise===dummy ? 1:0;
}
}");
var obj = (JSObject)factory.Call();
var dummy = obj.GetObjectProperty("dummy");
Assert.IsType<Task<object>>(dummy);
var check = obj.Invoke("check", dummy);
Assert.Equal(1, check);
}
[Fact]
public static async Task ResolveTask()
{
var tcs = new TaskCompletionSource<int>();
var factory = new Function("task", "callback", @"
return task.then((data)=>{
callback(data);
})
");
int check = 0;
Action<int> callback = (int data) =>
{
check = data;
};
Task<int> task = tcs.Task;
// we are testing that Task is marshaled as thenable
var promise = (Task<object>)factory.Call(null, task, callback);
tcs.SetResult(1);
// the result value is not applied until we await the promise
Assert.Equal(0, check);
await promise;
// but it's set after we do
Assert.Equal(1, check);
}
[Fact]
public static async Task RejectTask()
{
var tcs = new TaskCompletionSource<int>();
var factory = new Function("task", "callback", @"
return task.catch((reason)=>{
callback(reason);
})
");
string check = null;
Action<string> callback = (string data) =>
{
check = data;
};
var promise = (Task<object>)factory.Call(null, tcs.Task, callback);
Assert.Null(check);
tcs.SetException(new Exception("test"));
Assert.Null(check);
await promise;
Assert.Contains("System.Exception: test", check);
}
[Fact]
public static void NullTask()
{
var tcs = new TaskCompletionSource<int>();
var factory = new Function("task", "callback", @"
callback(task);
");
Task check = Task.FromResult(1);
Action<Task> callback = (Task data) =>
{
check = data;
};
factory.Call(null, null, callback);
Assert.Null(check);
}
[ActiveIssue("https://github.com/dotnet/runtime/issues/56963")]
[Fact]
public static void RoundtripTask()
{
var tcs = new TaskCompletionSource<int>();
var factory = new Function("dummy", @"
return {
dummy:dummy,
}");
var obj = (JSObject)factory.Call(null, tcs.Task);
var dummy = obj.GetObjectProperty("dummy");
Assert.IsType<Task<int>>(dummy);
}
}
}

View file

@ -1,463 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Threading.Tasks;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class HelperMarshal
{
internal const string INTEROP_CLASS = "[System.Runtime.InteropServices.JavaScript.Legacy.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:";
internal static int _i32Value;
private static void InvokeI32(int a, int b)
{
_i32Value = a + b;
}
internal static float _f32Value;
private static void InvokeFloat(float f)
{
_f32Value = f;
}
internal static double _f64Value;
private static void InvokeDouble(double d)
{
_f64Value = d;
}
internal static long _i64Value;
private static void InvokeLong(long l)
{
_i64Value = l;
}
internal static byte[] _byteBuffer;
private static void MarshalArrayBuffer(ArrayBuffer buffer)
{
using (var bytes = new Uint8Array(buffer))
_byteBuffer = bytes.ToArray();
}
private static void MarshalByteBuffer(Uint8Array buffer)
{
_byteBuffer = buffer.ToArray();
}
internal static string _stringResource;
private static void InvokeString(string s)
{
_stringResource = s;
}
internal static string _stringResource2;
private static void InvokeString2(string s)
{
_stringResource2 = s;
}
private static string StoreArgumentAndReturnLiteral(string s)
{
_stringResource = $"s: {s} length: {s?.Length}";
return "1";
}
private static string StoreAndReturnNew(string s)
{
var sb = new System.Text.StringBuilder();
sb.Append("Got:");
sb.Append(' ');
sb.Append(s);
_stringResource = sb.ToString();
return _stringResource;
}
internal static string _marshaledString;
private static string InvokeMarshalString()
{
_marshaledString = "Hic Sunt Dracones";
return _marshaledString;
}
internal static object _object1;
private static object InvokeObj1(object obj)
{
_object1 = obj;
return obj;
}
internal static object _object2;
private static object InvokeObj2(object obj)
{
_object2 = obj;
return obj;
}
internal static object _marshaledObject;
private static object InvokeMarshalObj()
{
_marshaledObject = new object();
return _marshaledObject;
}
private static object InvokeReturnMarshalObj()
{
return _marshaledObject;
}
private static int InvokeReturnInt()
{
return 42;
}
private static long InvokeReturnLong()
{
return 42L;
}
private static double InvokeReturnDouble()
{
return double.Pi;
}
internal static int _valOne, _valTwo;
private static void ManipulateObject(JSObject obj)
{
_valOne = (int)obj.Invoke("inc");
_valTwo = (int)obj.Invoke("add", 20);
}
internal static object[] _jsObjects;
private static void MinipulateObjTypes(JSObject obj)
{
_jsObjects = new object[4];
_jsObjects[0] = obj.Invoke("return_int");
_jsObjects[1] = obj.Invoke("return_double");
_jsObjects[2] = obj.Invoke("return_string");
_jsObjects[3] = obj.Invoke("return_bool");
}
internal static int _jsAddFunctionResult;
private static void UseFunction(JSObject obj)
{
_jsAddFunctionResult = (int)obj.Invoke("call", null, 10, 20);
}
internal static int _jsAddAsFunctionResult;
private static void UseAsFunction(Function func)
{
_jsAddAsFunctionResult = (int)func.Call(null, 20, 30);
}
internal static int _intValue;
private static void InvokeInt(int value)
{
_intValue = value;
}
internal static IntPtr _intPtrValue;
private static void InvokeIntPtr(IntPtr i)
{
_intPtrValue = i;
}
internal static IntPtr _marshaledIntPtrValue;
private static IntPtr InvokeMarshalIntPtr()
{
_marshaledIntPtrValue = (IntPtr)42;
return _marshaledIntPtrValue;
}
internal static object[] _jsProperties;
private static void RetrieveObjectProperties(JSObject obj)
{
_jsProperties = new object[4];
_jsProperties[0] = obj.GetObjectProperty("myInt");
_jsProperties[1] = obj.GetObjectProperty("myDouble");
_jsProperties[2] = obj.GetObjectProperty("myString");
_jsProperties[3] = obj.GetObjectProperty("myBoolean");
}
private static void PopulateObjectProperties(JSObject obj, bool createIfNotExist)
{
_jsProperties = new object[4];
obj.SetObjectProperty("myInt", 100, createIfNotExist);
obj.SetObjectProperty("myDouble", 4.5, createIfNotExist);
obj.SetObjectProperty("myString", "qwerty", createIfNotExist);
obj.SetObjectProperty("myBoolean", true, createIfNotExist);
}
private static void SetTypedArrayByte(JSObject obj)
{
var dragons = "hic sunt dracones";
byte[] buffer = System.Text.Encoding.ASCII.GetBytes(dragons);
obj.SetObjectProperty("dracones", Uint8Array.From(buffer));
}
internal static byte[] _taByte;
private static void GetTypedArrayByte(JSObject obj)
{
_taByte = ((Uint8Array)obj.GetObjectProperty("dracones")).ToArray();
}
private static Function _sumFunction;
private static void CreateFunctionSum()
{
_sumFunction = new Function("a", "b", "return a + b");
}
internal static int _sumValue = 0;
private static void CallFunctionSum()
{
if (_sumFunction == null)
throw new Exception("_sumFunction is null");
_sumValue = (int)_sumFunction.Call(null, 3, 5);
}
private static Function _mathMinFunction;
private static void CreateFunctionApply()
{
var math = (JSObject)Runtime.GetGlobalObject("Math");
if (math == null)
throw new Exception("Runtime.GetGlobalObject(Math) returned null");
_mathMinFunction = (Function)math.GetObjectProperty("min");
}
internal static int _minValue = 0;
private static void CallFunctionApply()
{
if (_mathMinFunction == null)
throw new Exception("_mathMinFunction is null");
_minValue = (int)_mathMinFunction.Apply(null, new object[] { 5, 6, 2, 3, 7 });
}
internal static Uri _blobURL;
public static void SetBlobUrl(string blobUrl)
{
_blobURL = new Uri(blobUrl);
}
internal static Uri _blobURI;
public static void SetBlobAsUri(Uri blobUri)
{
_blobURI = blobUri;
}
internal static uint _uintValue;
private static void InvokeUInt(uint value)
{
_uintValue = value;
}
internal static TestEnum _enumValue;
private static void SetEnumValue(TestEnum value)
{
_enumValue = value;
}
private static TestEnum GetEnumValue()
{
return _enumValue;
}
private static UInt64 GetUInt64()
{
return UInt64.MaxValue;
}
internal static int _functionResultValue;
private static Func<int, int, int> CreateFunctionDelegate()
{
return (a, b) =>
{
_functionResultValue = a + b;
return _functionResultValue;
};
}
internal static int _functionActionResultValue;
internal static int _functionActionResultValueOfAction;
private static Func<int, int, Action<int,int>> CreateFunctionDelegateWithAction()
{
return (a, b) =>
{
_functionActionResultValue = a + b;
return (i1, i2) =>
{
_functionActionResultValueOfAction = i1 + i2;
};
};
}
internal static int _actionResultValue;
private static Action<int,int> CreateActionDelegate()
{
return (a1, a2) =>
{
_actionResultValue = a1 + a2;
};
}
private static bool AreEqual(int a, int b)
{
return a == b;
}
private static string TestString1(string a)
{
return "Received: " + a;
}
private static void SetTestString1(string a)
{
_delMethodStringResultValue = a;
}
// Create a method for a delegate.
public static void DelegateMethod(string message)
{
_delMethodResultValue = message;
}
delegate void Del(string message);
internal static string _delMethodResultValue;
private static Del CreateDelegateMethod()
{
// Instantiate the delegate.
Del handler = DelegateMethod;
return handler;
}
delegate string Del2(string message);
internal static string _delMethodStringResultValue;
private static Del2 CreateDelegateMethodReturnString()
{
// Instantiate the delegate.
Del2 handler = TestString1;
return handler;
}
internal static string _delegateCallResult;
private static Del CreateDelegateFromAnonymousMethod_VoidString()
{
// Instantiate the delegate.
Del handler = delegate(string name) { _delegateCallResult = $"Notification received for: {name}"; };
return handler;
}
private static Del CreateDelegateFromLambda_VoidString()
{
// Instantiate the delegate.
Del handler = (string name) => { _delegateCallResult = $"Notification received for: {name}"; };
return handler;
}
public static void DelegateMethod_VoidString(string name) => _delegateCallResult = $"Notification received for: {name}";
private static Del CreateDelegateFromMethod_VoidString()
{
// Instantiate the delegate.
Del handler = DelegateMethod_VoidString;
return handler;
}
private static Action<string> CreateActionT_VoidString()
=> (string name) => _delegateCallResult = $"Notification received for: {name}";
static void Hello(string s)
{
_delegateCallResult += $" Hello, {s}!";
}
static void GoodMorning(string s)
{
_delegateCallResult += $" GoodMorning, {s}!";
}
delegate void CustomDelStr(string s);
private static CustomDelStr CreateCustomMultiCastDelegate_VoidString()
{
CustomDelStr hiDel, mornDel, multiDel;
hiDel = Hello;
mornDel = GoodMorning;
multiDel = hiDel + mornDel;
return multiDel;
}
private static Action<string> CreateMultiCastAction_VoidString()
{
Action<string> hiDel, mornDel, multiDel;
hiDel = Hello;
mornDel = GoodMorning;
multiDel = hiDel + mornDel;
return multiDel;
}
internal static JSObject _funcActionBufferObjectResultValue;
internal static int _funcActionBufferResultLengthValue;
private static Func<Uint8Array, Action<Uint8Array>> CreateFunctionAcceptingUint8Array()
{
return (buffer) =>
{
_funcActionBufferObjectResultValue = buffer;
return (i1) =>
{
_funcActionBufferResultLengthValue = i1.Length;
};
};
}
private static Func<Array, Action<Array>> CreateFunctionAcceptingArray()
{
return (buffer) =>
{
_funcActionBufferObjectResultValue = buffer;
return (i1) =>
{
_funcActionBufferResultLengthValue = i1.Length;
};
};
}
public static Task SynchronousTask()
{
return Task.CompletedTask;
}
public static async Task AsynchronousTask()
{
await Task.Yield();
}
public static Task<int> SynchronousTaskInt(int i)
{
return Task.FromResult(i);
}
public static async Task<int> AsynchronousTaskInt(int i)
{
await Task.Yield();
return i;
}
public static Task FailedSynchronousTask()
{
return Task.FromException(new Exception());
}
public static async Task FailedAsynchronousTask()
{
await Task.Yield();
throw new Exception();
}
}
public enum TestEnum : uint {
FirstValue = 1,
Zero = 0,
Five = 5,
BigValue = 0xFFFFFFFEu
}
}

View file

@ -1,215 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class JavaScriptTests
{
[Fact]
public static void CoreTypes()
{
var arr1 = new Uint8Array(50);
Assert.Equal(50, arr1.Length);
}
[Fact]
public static void FunctionSum()
{
// The Difference Between call() and apply()
// The difference is:
// The call() method takes arguments separately.
// The apply() method takes arguments as an array.
var sum = new Function("a", "b", "return a + b");
Assert.Equal(8, (int)sum.Call(null, 3, 5));
Assert.Equal(13, (int)sum.Apply(null, new object[] { 6, 7 }));
}
[Fact]
public static void FunctionMath()
{
JSObject math = (JSObject)Runtime.GetGlobalObject("Math");
Assert.True(math != null, "math != null");
Function mathMax = (Function)math.GetObjectProperty("max");
Assert.True(mathMax != null, "math.max != null");
var maxValue = (int)mathMax.Apply(null, new object[] { 5, 6, 2, 3, 7 });
Assert.Equal(7, maxValue);
maxValue = (int)mathMax.Call(null, 5, 6, 2, 3, 7);
Assert.Equal(7, maxValue);
Function mathMin = (Function)((JSObject)Runtime.GetGlobalObject("Math")).GetObjectProperty("min");
Assert.True(mathMin != null, "math.min != null");
var minValue = (int)mathMin.Apply(null, new object[] { 5, 6, 2, 3, 7 });
Assert.Equal(2, minValue);
minValue = (int)mathMin.Call(null, 5, 6, 2, 3, 7);
Assert.Equal(2, minValue);
}
[Fact]
[OuterLoop("slow")]
public static async Task BagIterator()
{
await Task.Delay(1);
var bagFn = new Function(@"
var same = {
x:1
};
return Object.entries({
a:1,
b:'two',
c:{fold:{}},
d:same,
e:same,
f:same
});
");
for (int attempt = 0; attempt < 100_000; attempt++)
{
try
{
using var bag = (JSObject)bagFn.Call(null);
using var entriesIterator = (JSObject)bag.Invoke("entries");
var cnt = entriesIterator.ToEnumerable().Count();
Assert.Equal(6, cnt);
// fill GC helps to repro
var x = new byte[100 + attempt / 100];
if (attempt % 1000 == 0)
{
Utils.InvokeJS("if (globalThis.gc) globalThis.gc();");// needs v8 flag --expose-gc
GC.Collect();
}
}
catch (Exception ex)
{
throw new Exception(ex.Message + " At attempt=" + attempt, ex);
}
}
}
[Fact]
public static async Task Iterator()
{
await Task.Delay(1);
var makeRangeIterator = new Function("start", "end", "step", @"
let nextIndex = start;
let iterationCount = 0;
const rangeIterator = {
next: function() {
let result;
if (nextIndex < end) {
result = { value: {}, done: false }
nextIndex += step;
iterationCount++;
return result;
}
return { value: {}, done: true }
}
};
return rangeIterator;
");
const int count = 500;
for (int attempt = 0; attempt < 100; attempt++)
{
int index = 0;
try
{
var entriesIterator = (JSObject)makeRangeIterator.Call(null, 0, count, 1);
Assert.NotNull(entriesIterator);
using (entriesIterator)
{
var enumerable = entriesIterator.ToEnumerable();
var enumerator = enumerable.GetEnumerator();
Assert.NotNull(enumerator);
using (enumerator)
{
while (enumerator.MoveNext())
{
Assert.NotNull(enumerator.Current);
index++;
}
}
}
Assert.Equal(count, index);
}
catch (Exception ex)
{
throw new Exception($"At attempt={attempt}, index={index}: {ex.Message}", ex);
}
await Task.Yield();
}
}
public static IEnumerable<object> ToEnumerable(this JSObject iterrator)
{
JSObject nextResult = null;
try
{
nextResult = (JSObject)iterrator.Invoke("next");
var done = (bool)nextResult.GetObjectProperty("done");
while (!done)
{
object value = nextResult.GetObjectProperty("value");
nextResult.Dispose();
yield return value;
nextResult = (JSObject)iterrator.Invoke("next");
done = (bool)nextResult.GetObjectProperty("done");
}
}
finally
{
nextResult?.Dispose();
}
}
[Fact]
public static void RoundtripCSDate()
{
var factory = new Function("dummy", @"
return {
dummy:dummy,
}");
var date = new DateTime(2021, 01, 01, 12, 34, 45);
var obj = (JSObject)factory.Call(null, date);
var dummy = (DateTime)obj.GetObjectProperty("dummy");
Assert.Equal(date, dummy);
}
[Fact]
public static void RoundtripJSDate()
{
var factory = new Function(@"
var dummy = new Date(2021, 00, 01, 12, 34, 45, 567);
return {
dummy:dummy,
check:(value) => {
return value.valueOf()==dummy.valueOf() ? 1 : 0;
},
}");
var obj = (JSObject)factory.Call();
var date = (DateTime)obj.GetObjectProperty("dummy");
var check = (int)obj.Invoke("check", date);
Assert.Equal(1, check);
}
}
}

View file

@ -1,791 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Threading.Tasks;
using Xunit;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class MarshalTests
{
[Fact]
public static void MarshalPrimitivesToCS()
{
HelperMarshal._i32Value = 0;
Utils.InvokeJS("App.call_test_method (\"InvokeI32\", [10, 20])");
Assert.Equal(30, HelperMarshal._i32Value);
HelperMarshal._f32Value = 0;
Utils.InvokeJS("App.call_test_method (\"InvokeFloat\", [1.5])");
Assert.Equal(1.5f, HelperMarshal._f32Value);
HelperMarshal._f64Value = 0;
Utils.InvokeJS("App.call_test_method (\"InvokeDouble\", [4.5])");
Assert.Equal(4.5, HelperMarshal._f64Value);
HelperMarshal._i64Value = 0;
Utils.InvokeJS("App.call_test_method (\"InvokeLong\", [99])");
Assert.Equal(99, HelperMarshal._i64Value);
}
[Fact]
public static void MarshalArrayBuffer()
{
Utils.InvokeJS(@"
var buffer = new ArrayBuffer(16);
App.call_test_method (""MarshalArrayBuffer"", [ buffer ]);
");
Assert.Equal(16, HelperMarshal._byteBuffer.Length);
}
[Fact]
public static void MarshalStringToCS()
{
HelperMarshal._stringResource = null;
Utils.InvokeJS("App.call_test_method(\"InvokeString\", [\"hello\"])");
Assert.Equal("hello", HelperMarshal._stringResource);
}
[Fact]
public static void MarshalUnicodeStringToCS()
{
HelperMarshal._stringResource = null;
Utils.InvokeJS("App.call_test_method(\"StoreAndReturnNew\", [' '+\"\u0050\u0159\u00ed\u006c\u0069\u0161\u0020\u017e\u006c\u0075\u0165\u006f\u0075\u010d\u006b\u00fd\u0020\u006b\u016f\u0148\u202f\u00fa\u0070\u011b\u006c\u0020\u010f\u00e1\u0062\u0065\u006c\u0073\u006b\u00e9\u0020\u00f3\u0064\u0079\"])");
Assert.Equal("Got: \u0050\u0159\u00ed\u006c\u0069\u0161\u0020\u017e\u006c\u0075\u0165\u006f\u0075\u010d\u006b\u00fd\u0020\u006b\u016f\u0148\u202f\u00fa\u0070\u011b\u006c\u0020\u010f\u00e1\u0062\u0065\u006c\u0073\u006b\u00e9\u0020\u00f3\u0064\u0079", HelperMarshal._stringResource);
HelperMarshal._stringResource = null;
Utils.InvokeJS("App.call_test_method(\"StoreAndReturnNew\", [' '+\"\uFEFF\u0000\uFFFE\"])");
Assert.Equal("Got: \uFEFF\0\uFFFE", HelperMarshal._stringResource);
HelperMarshal._stringResource = null;
Utils.InvokeJS("App.call_test_method(\"StoreAndReturnNew\", [' '+\"\u02F3o\u0302\u0303\u0308\u0930\u0903\u0951\"])");
Assert.Equal("Got: \u02F3o\u0302\u0303\u0308\u0930\u0903\u0951", HelperMarshal._stringResource);
}
[Fact]
public static void MarshalNullStringToCS()
{
HelperMarshal._stringResource = null;
Utils.InvokeJS("App.call_test_method(\"InvokeString\", [ null ])");
Assert.Null(HelperMarshal._stringResource);
}
[Fact]
public static void MarshalStringToJS()
{
HelperMarshal._marshaledString = HelperMarshal._stringResource = null;
Utils.InvokeJS(@"
var str = App.call_test_method (""InvokeMarshalString"");
App.call_test_method (""InvokeString"", [ str ]);
");
Assert.NotNull(HelperMarshal._marshaledString);
Assert.Equal(HelperMarshal._marshaledString, HelperMarshal._stringResource);
}
[Fact]
public static void JSObjectKeepIdentityAcrossCalls()
{
HelperMarshal._object1 = HelperMarshal._object2 = null;
Utils.InvokeJS(@"
var obj = { foo: 10 };
var res = App.call_test_method (""InvokeObj1"", [ obj ]);
App.call_test_method (""InvokeObj2"", [ res ]);
");
Assert.NotNull(HelperMarshal._object1);
Assert.Same(HelperMarshal._object1, HelperMarshal._object2);
}
[Fact]
public static void CSObjectKeepIdentityAcrossCalls()
{
HelperMarshal._marshaledObject = HelperMarshal._object1 = HelperMarshal._object2 = null;
Utils.InvokeJS(@"
var obj = App.call_test_method (""InvokeMarshalObj"");
var res = App.call_test_method (""InvokeObj1"", [ obj ]);
App.call_test_method (""InvokeObj2"", [ res ]);
");
Assert.NotNull(HelperMarshal._object1);
Assert.Same(HelperMarshal._marshaledObject, HelperMarshal._object1);
Assert.Same(HelperMarshal._object1, HelperMarshal._object2);
}
[Theory]
[InlineData(byte.MinValue)]
[InlineData(byte.MaxValue)]
[InlineData(SByte.MinValue)]
[InlineData(SByte.MaxValue)]
[InlineData(uint.MaxValue)]
[InlineData(uint.MinValue)]
[InlineData(int.MaxValue)]
[InlineData(int.MinValue)]
[InlineData(double.MaxValue)]
[InlineData(double.MinValue)]
public static void InvokeUnboxNumberString(object o)
{
HelperMarshal._marshaledObject = o;
HelperMarshal._object1 = HelperMarshal._object2 = null;
var value = Utils.InvokeJS(@"
var obj = App.call_test_method (""InvokeReturnMarshalObj"");
var res = App.call_test_method (""InvokeObj1"", [ obj.toString() ]);
");
Assert.Equal(o.ToString().ToLower(), HelperMarshal._object1);
}
[Theory]
[InlineData(byte.MinValue, 0)]
[InlineData(byte.MaxValue, 255)]
[InlineData(SByte.MinValue, -128)]
[InlineData(SByte.MaxValue, 127)]
[InlineData(uint.MaxValue)]
[InlineData(uint.MinValue, 0)]
[InlineData(int.MaxValue)]
[InlineData(int.MinValue)]
[InlineData(double.MaxValue)]
[InlineData(double.MinValue)]
public static void InvokeUnboxNumber(object o, object expected = null)
{
HelperMarshal._marshaledObject = o;
HelperMarshal._object1 = HelperMarshal._object2 = null;
Utils.InvokeJS(@"
var obj = App.call_test_method (""InvokeReturnMarshalObj"");
var res = App.call_test_method (""InvokeObj1"", [ obj ]);
");
Assert.Equal(expected ?? o, HelperMarshal._object1);
}
[Fact]
public static void InvokeUnboxInt()
{
Utils.InvokeJS(@"
var obj = App.call_test_method (""InvokeReturnInt"");
var res = App.call_test_method (""InvokeObj1"", [ obj ]);
");
Assert.Equal(42, HelperMarshal._object1);
}
[Fact]
public static void InvokeUnboxDouble()
{
Utils.InvokeJS(@"
var obj = App.call_test_method (""InvokeReturnDouble"");
var res = App.call_test_method (""InvokeObj1"", [ obj ]);
");
Assert.Equal(double.Pi, HelperMarshal._object1);
}
[Fact]
public static void InvokeUnboxLongFail()
{
var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@"
console.log(""the exception in InvokeReturnLong after this is intentional"");
App.call_test_method (""InvokeReturnLong"");
"));
Assert.Contains("int64 not available", ex.Message);
}
[Theory]
[InlineData(byte.MinValue, 0)]
[InlineData(byte.MaxValue, 255)]
[InlineData(SByte.MinValue, -128)]
[InlineData(SByte.MaxValue, 127)]
[InlineData(uint.MaxValue)]
[InlineData(uint.MinValue, 0)]
[InlineData(int.MaxValue)]
[InlineData(int.MinValue)]
[InlineData(double.MaxValue)]
[InlineData(double.MinValue)]
public static void InvokeUnboxStringNumber(object o, object expected = null)
{
HelperMarshal._marshaledObject = HelperMarshal._object1 = HelperMarshal._object2 = null;
Utils.InvokeJS(String.Format(@"
var res = App.call_test_method (""InvokeObj1"", [ {0} ]);
", o));
Assert.Equal(expected ?? o, HelperMarshal._object1);
}
[Fact]
public static void JSInvokeInt()
{
Utils.InvokeJS(@"
var obj = {
foo: 10,
inc: function() {
var c = this.foo;
++this.foo;
return c;
},
add: function(val){
return this.foo + val;
}
};
App.call_test_method (""ManipulateObject"", [ obj ]);
");
Assert.Equal(10, HelperMarshal._valOne);
Assert.Equal(31, HelperMarshal._valTwo);
}
[Fact]
public static void JSInvokeTypes()
{
Utils.InvokeJS(@"
var obj = {
return_int: function() { return 100; },
return_double: function() { return 4.5; },
return_string: function() { return 'Hic Sunt Dracones'; },
return_bool: function() { return true; },
};
App.call_test_method (""MinipulateObjTypes"", [ obj ]);
");
Assert.Equal(100, HelperMarshal._jsObjects[0]);
Assert.Equal(4.5, HelperMarshal._jsObjects[1]);
Assert.Equal("Hic Sunt Dracones", HelperMarshal._jsObjects[2]);
Assert.NotEqual("HIC SVNT LEONES", HelperMarshal._jsObjects[2]);
Assert.Equal(true, HelperMarshal._jsObjects[3]);
}
[Fact]
public static void JSObjectApply()
{
Utils.InvokeJS(@"
var do_add = function(a, b) { return a + b };
App.call_test_method (""UseFunction"", [ do_add ]);
");
Assert.Equal(30, HelperMarshal._jsAddFunctionResult);
}
[Fact]
public static void JSObjectAsFunction()
{
Utils.InvokeJS(@"
var do_add = function(a, b) { return a + b };
App.call_test_method (""UseAsFunction"", [ do_add ]);
");
Assert.Equal(50, HelperMarshal._jsAddAsFunctionResult);
}
[Fact]
public static void BindStaticMethod()
{
HelperMarshal._intValue = 0;
Utils.InvokeJS(@$"
var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
invoke_int (200);
");
Assert.Equal(200, HelperMarshal._intValue);
}
[Fact]
public static void BindIntPtrStaticMethod()
{
HelperMarshal._intPtrValue = IntPtr.Zero;
Utils.InvokeJS(@$"
var invoke_int_ptr = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeIntPtr"");
invoke_int_ptr (42);
");
Assert.Equal(42, (int)HelperMarshal._intPtrValue);
}
[Fact]
public static void MarshalIntPtrToJS()
{
HelperMarshal._marshaledIntPtrValue = IntPtr.Zero;
Utils.InvokeJS(@$"
var invokeMarshalIntPtr = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeMarshalIntPtr"");
var r = invokeMarshalIntPtr ();
if (r != 42) throw `Invalid int_ptr value`;
");
Assert.Equal(42, (int)HelperMarshal._marshaledIntPtrValue);
}
[Fact]
public static void ResolveMethod()
{
HelperMarshal._intValue = 0;
Utils.InvokeJS(@$"
var invoke_int = INTERNAL.mono_method_resolve (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
App.call_test_method (""InvokeInt"", [ invoke_int ]);
");
Assert.NotEqual(0, HelperMarshal._intValue);
}
[Fact]
public static void GetObjectProperties()
{
Utils.InvokeJS(@"
var obj = {myInt: 100, myDouble: 4.5, myString: ""Hic Sunt Dracones"", myBoolean: true};
App.call_test_method (""RetrieveObjectProperties"", [ obj ]);
");
Assert.Equal(100, HelperMarshal._jsProperties[0]);
Assert.Equal(4.5, HelperMarshal._jsProperties[1]);
Assert.Equal("Hic Sunt Dracones", HelperMarshal._jsProperties[2]);
Assert.Equal(true, HelperMarshal._jsProperties[3]);
}
[Fact]
public static void SetObjectProperties()
{
Utils.InvokeJS(@"
var obj = {myInt: 200, myDouble: 0, myString: ""foo"", myBoolean: false};
App.call_test_method (""PopulateObjectProperties"", [ obj, false ]);
App.call_test_method (""RetrieveObjectProperties"", [ obj ]);
");
Assert.Equal(100, HelperMarshal._jsProperties[0]);
Assert.Equal(4.5, HelperMarshal._jsProperties[1]);
Assert.Equal("qwerty", HelperMarshal._jsProperties[2]);
Assert.Equal(true, HelperMarshal._jsProperties[3]);
}
[Fact]
public static void SetObjectPropertiesIfNotExistsFalse()
{
// This test will not create the properties if they do not already exist
Utils.InvokeJS(@"
var obj = {myInt: 200};
App.call_test_method (""PopulateObjectProperties"", [ obj, false ]);
App.call_test_method (""RetrieveObjectProperties"", [ obj ]);
");
Assert.Equal(100, HelperMarshal._jsProperties[0]);
Assert.Null(HelperMarshal._jsProperties[1]);
Assert.Null(HelperMarshal._jsProperties[2]);
Assert.Null(HelperMarshal._jsProperties[3]);
}
[Fact]
public static void SetObjectPropertiesIfNotExistsTrue()
{
// This test will set the value of the property if it exists and will create and
// set the value if it does not exists
Utils.InvokeJS(@"
var obj = {myInt: 200};
App.call_test_method (""PopulateObjectProperties"", [ obj, true ]);
App.call_test_method (""RetrieveObjectProperties"", [ obj ]);
");
Assert.Equal(100, HelperMarshal._jsProperties[0]);
Assert.Equal(4.5, HelperMarshal._jsProperties[1]);
Assert.Equal("qwerty", HelperMarshal._jsProperties[2]);
Assert.Equal(true, HelperMarshal._jsProperties[3]);
}
[Fact]
public static void MarshalTypedArray()
{
Utils.InvokeJS(@"
var buffer = new ArrayBuffer(16);
var uint8View = new Uint8Array(buffer);
App.call_test_method (""MarshalByteBuffer"", [ uint8View ]);
");
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(@"
var obj = { };
App.call_test_method (""SetTypedArray" + type + @""", [ obj ]);
App.call_test_method (""GetTypedArray" + type + @""", [ obj ]);
");
}
[Fact]
public static void MarshalTypedArrayByte()
{
RunMarshalTypedArrayJS("Byte");
Assert.Equal(17, HelperMarshal._taByte.Length);
Assert.Equal(104, HelperMarshal._taByte[0]);
Assert.Equal(115, HelperMarshal._taByte[HelperMarshal._taByte.Length - 1]);
Assert.Equal("hic sunt dracones", System.Text.Encoding.Default.GetString(HelperMarshal._taByte));
}
[Fact]
public static void TestFunctionSum()
{
HelperMarshal._sumValue = 0;
Utils.InvokeJS(@"
App.call_test_method (""CreateFunctionSum"", []);
App.call_test_method (""CallFunctionSum"", []);
");
Assert.Equal(8, HelperMarshal._sumValue);
}
[Fact]
public static void TestFunctionApply()
{
HelperMarshal._minValue = 0;
Utils.InvokeJS(@"
App.call_test_method (""CreateFunctionApply"", []);
App.call_test_method (""CallFunctionApply"", []);
");
Assert.Equal(2, HelperMarshal._minValue);
}
[Fact]
public static void BoundStaticMethodMissingArgs()
{
HelperMarshal._intValue = 1;
var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
invoke_int ();
"));
Assert.Contains("Value is not an integer: undefined (undefined)", ex.Message);
Assert.Equal(1, HelperMarshal._intValue);
}
[Fact]
public static void BoundStaticMethodExtraArgs()
{
HelperMarshal._intValue = 0;
Utils.InvokeJS(@$"
var invoke_int = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeInt"");
invoke_int (200, 400);
");
Assert.Equal(200, HelperMarshal._intValue);
}
[Fact]
public static void RangeCheckInt()
{
HelperMarshal._intValue = 0;
// no numbers bigger than 32 bits
var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
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);
Assert.Equal(0, HelperMarshal._intValue);
}
[Fact]
public static void IntegerCheckInt()
{
HelperMarshal._intValue = 0;
// no floating point rounding
var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
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);
Assert.Equal(0, HelperMarshal._intValue);
}
[Fact]
public static void TypeCheckInt()
{
HelperMarshal._intValue = 0;
// no string conversion
var ex = Assert.Throws<JSException>(() => Utils.InvokeJS(@$"
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);
Assert.Equal(0, HelperMarshal._intValue);
}
[Fact]
public static void PassUintArgument()
{
HelperMarshal._uintValue = 0;
Utils.InvokeJS(@$"
var invoke_uint = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeUInt"");
invoke_uint (0xFFFFFFFE);
");
Assert.Equal(0xFFFFFFFEu, HelperMarshal._uintValue);
}
[Fact]
public static void ReturnUintEnum()
{
HelperMarshal._uintValue = 0;
HelperMarshal._enumValue = TestEnum.BigValue;
Utils.InvokeJS(@$"
var get_value = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}GetEnumValue"");
var e = get_value ();
var invoke_uint = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}InvokeUInt"");
invoke_uint (e);
");
Assert.Equal((uint)TestEnum.BigValue, HelperMarshal._uintValue);
}
[Fact]
public static void PassUintEnumByValue()
{
HelperMarshal._enumValue = TestEnum.Zero;
Utils.InvokeJS(@$"
var set_enum = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}SetEnumValue"", ""j"");
set_enum (0xFFFFFFFE);
");
Assert.Equal(TestEnum.BigValue, HelperMarshal._enumValue);
}
[Fact]
public static void PassUintEnumByNameIsNotImplemented()
{
HelperMarshal._enumValue = TestEnum.Zero;
var exc = Assert.Throws<JSException>(() =>
Utils.InvokeJS(@$"
var set_enum = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}SetEnumValue"", ""j"");
set_enum (""BigValue"");
")
);
Assert.StartsWith("Error: Expected numeric value for enum argument, got 'BigValue'", exc.Message);
}
[Fact]
public static void CannotUnboxUint64()
{
var exc = Assert.Throws<JSException>(() =>
Utils.InvokeJS(@$"
var get_u64 = BINDING.bind_static_method (""{HelperMarshal.INTEROP_CLASS}GetUInt64"", """");
var u64 = get_u64();
")
);
Assert.StartsWith("Error: int64 not available", exc.Message);
}
[Fact]
public static void BareStringArgumentsAreNotInterned()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
Utils.InvokeJS(@"
var jsLiteral = ""hello world"";
App.call_test_method (""InvokeString"", [ jsLiteral ]);
App.call_test_method (""InvokeString2"", [ jsLiteral ]);
");
Assert.Equal("hello world", HelperMarshal._stringResource);
Assert.Equal(HelperMarshal._stringResource, HelperMarshal._stringResource2);
Assert.False(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
}
[Fact]
public static void InternedStringSignaturesAreInternedOnJavascriptSide()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
Utils.InvokeJS(@"
var sym = ""interned string"";
App.call_test_method (""InvokeString"", [ sym ], ""S"");
App.call_test_method (""InvokeString2"", [ sym ], ""S"");
");
Assert.Equal("interned string", HelperMarshal._stringResource);
Assert.Equal(HelperMarshal._stringResource, HelperMarshal._stringResource2);
Assert.True(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
}
[Fact]
public static void OnceAJSStringIsInternedItIsAlwaysUsedIfPossible()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
Utils.InvokeJS(@"
var sym = ""interned string 2"";
App.call_test_method (""InvokeString"", [ sym ], ""S"");
App.call_test_method (""InvokeString2"", [ sym ], ""s"");
");
Assert.Equal("interned string 2", HelperMarshal._stringResource);
Assert.Equal(HelperMarshal._stringResource, HelperMarshal._stringResource2);
Assert.True(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
}
[Fact]
public static void ManuallyInternString()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
Utils.InvokeJS(@"
var sym = INTERNAL.stringToMonoStringIntern(""interned string 3"");
App.call_test_method (""InvokeString"", [ sym ], ""s"");
App.call_test_method (""InvokeString2"", [ sym ], ""s"");
");
Assert.Equal("interned string 3", HelperMarshal._stringResource);
Assert.Equal(HelperMarshal._stringResource, HelperMarshal._stringResource2);
Assert.True(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
}
[Fact]
public static void LargeStringsAreNotAutomaticallyLocatedInInternTable()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
Utils.InvokeJS(@"
var s = ""long interned string"";
for (var i = 0; i < 1024; i++)
s += String(i % 10);
var sym = INTERNAL.stringToMonoStringIntern(s);
App.call_test_method (""InvokeString"", [ sym ], ""S"");
App.call_test_method (""InvokeString2"", [ sym ], ""s"");
");
Assert.Equal(HelperMarshal._stringResource, HelperMarshal._stringResource2);
Assert.False(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
}
[Fact]
public static void CanInternVeryManyStrings()
{
HelperMarshal._stringResource = null;
Utils.InvokeJS(@"
for (var i = 0; i < 10240; i++)
INTERNAL.stringToMonoStringIntern('s' + i);
App.call_test_method (""InvokeString"", [ 's5000' ], ""S"");
");
Assert.Equal("s5000", HelperMarshal._stringResource);
Assert.Equal(HelperMarshal._stringResource, string.IsInterned(HelperMarshal._stringResource));
}
[Fact]
public static void SymbolsAreMarshaledAsStrings()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
Utils.InvokeJS(@"
var jsLiteral = Symbol(""custom symbol"");
App.call_test_method (""InvokeString"", [ jsLiteral ]);
App.call_test_method (""InvokeString2"", [ jsLiteral ]);
");
Assert.Equal("custom symbol", HelperMarshal._stringResource);
Assert.Equal(HelperMarshal._stringResource, HelperMarshal._stringResource2);
Assert.True(Object.ReferenceEquals(HelperMarshal._stringResource, HelperMarshal._stringResource2));
}
[Fact]
public static void InternedStringReturnValuesWork()
{
HelperMarshal._stringResource = HelperMarshal._stringResource2 = null;
var fqn = "[System.Runtime.InteropServices.JavaScript.Legacy.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:StoreArgumentAndReturnLiteral";
Utils.InvokeJS(
$"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);
Assert.Equal("1", HelperMarshal._stringResource2);
}
[Fact]
public static void InvokeJSExpression()
{
var result = Utils.InvokeJS(@"1 + 2");
Assert.Equal("3", result);
}
[Fact]
public static void InvokeJSNullExpression()
{
var result = Utils.InvokeJS(@"null");
Assert.Null(result);
}
[Fact]
public static void InvokeJSUndefinedExpression()
{
var result = Utils.InvokeJS(@"undefined");
Assert.Null(result);
}
[Fact]
public static void InvokeJSNotInGlobalScope()
{
var result = Utils.InvokeJS(@"var test_local_variable_name = 5; globalThis.test_local_variable_name");
Assert.Null(result);
}
private static async Task<bool> MarshalTask(string helperMethodName, string helperMethodArgs = "", string resolvedBody = "")
{
Utils.InvokeJS(
@"globalThis.__test_promise_completed = false; " +
@"globalThis.__test_promise_resolved = false; " +
@"globalThis.__test_promise_failed = false; " +
$@"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; }); " +
""
);
await Task.Delay(1);
var completed = bool.Parse(Utils.InvokeJS(@"globalThis.__test_promise_completed"));
Assert.True(completed, "JavasScript promise did not completed.");
var resolved = bool.Parse(Utils.InvokeJS(@"globalThis.__test_promise_resolved"));
return resolved;
}
private static async Task MarshalTaskReturningInt(string helperMethodName)
{
HelperMarshal._intValue = 0;
bool success = await MarshalTask(helperMethodName, "7", "App.call_test_method ('InvokeInt', [ result ], 'i');");
Assert.True(success, $"{helperMethodName} didn't succeeded.");
Assert.Equal(7, HelperMarshal._intValue);
}
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/94253", typeof(PlatformDetection), nameof(PlatformDetection.IsWasmThreadingSupported))]
public static async Task MarshalSynchronousTask()
{
bool success = await MarshalTask("SynchronousTask");
Assert.True(success, "SynchronousTask didn't succeeded.");
}
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/94253", typeof(PlatformDetection), nameof(PlatformDetection.IsWasmThreadingSupported))]
public static async Task MarshalAsynchronousTask()
{
bool success = await MarshalTask("AsynchronousTask");
Assert.True(success, "AsynchronousTask didn't succeeded.");
}
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/94253", typeof(PlatformDetection), nameof(PlatformDetection.IsWasmThreadingSupported))]
public static Task MarshalSynchronousTaskInt()
{
return MarshalTaskReturningInt("SynchronousTaskInt");
}
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/94253", typeof(PlatformDetection), nameof(PlatformDetection.IsWasmThreadingSupported))]
public static Task MarshalAsynchronousTaskInt()
{
return MarshalTaskReturningInt("AsynchronousTaskInt");
}
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/94253", typeof(PlatformDetection), nameof(PlatformDetection.IsWasmThreadingSupported))]
public static async Task MarshalFailedSynchronousTask()
{
bool success = await MarshalTask("FailedSynchronousTask");
Assert.False(success, "FailedSynchronousTask didn't failed.");
}
[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/94253", typeof(PlatformDetection), nameof(PlatformDetection.IsWasmThreadingSupported))]
public static async Task MarshalFailedAsynchronousTask()
{
bool success = await MarshalTask("FailedAsynchronousTask");
Assert.False(success, "FailedAsynchronousTask didn't failed.");
}
}
}

View file

@ -1,144 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
using Xunit;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public class MemoryTests
{
[Theory]
[InlineData(-1L)]
[InlineData(-42L)]
[InlineData(int.MinValue)]
[InlineData(-9007199254740990L)]//MIN_SAFE_INTEGER+1
[InlineData(-9007199254740991L)]//MIN_SAFE_INTEGER
[InlineData(1L)]
[InlineData(0L)]
[InlineData(42L)]
[InlineData(int.MaxValue)]
[InlineData(0xF_FFFF_FFFFL)]
[InlineData(9007199254740991L)]//MAX_SAFE_INTEGER
public static unsafe void Int52TestOK(long value)
{
long expected = value;
long dummy = 0xA6A6A6A6L;
long actual2 = dummy;
var bagFn = new Function("ptr", "ptr2", @"
const value=globalThis.App.runtime.getHeapI52(ptr);
globalThis.App.runtime.setHeapI52(ptr2, value);
return ''+value;");
uint ptr = (uint)Unsafe.AsPointer(ref expected);
uint ptr2 = (uint)Unsafe.AsPointer(ref actual2);
object actual = (string)bagFn.Call(null, ptr, ptr2);
Assert.Equal(""+ value, actual);
Assert.Equal(value, actual2);
Assert.Equal(0xA6A6A6A6L, dummy);
}
[Theory]
[InlineData(uint.MinValue)]
[InlineData(1UL)]
[InlineData(0UL)]
[InlineData(42UL)]
[InlineData(uint.MaxValue)]
[InlineData(0xF_FFFF_FFFFUL)]
[InlineData(9007199254740991UL)]//MAX_SAFE_INTEGER
public static unsafe void UInt52TestOK(ulong value)
{
ulong expected = value;
ulong dummy = 0xA6A6A6A6UL;
ulong actual2 = dummy;
var bagFn = new Function("ptr", "ptr2", @"
const value=globalThis.App.runtime.getHeapI52(ptr);
globalThis.App.runtime.setHeapU52(ptr2, value);
return ''+value;");
uint ptr = (uint)Unsafe.AsPointer(ref expected);
uint ptr2 = (uint)Unsafe.AsPointer(ref actual2);
string actual = (string)bagFn.Call(null, ptr, ptr2);
Assert.Equal(""+value, actual);
Assert.Equal(value, actual2);
Assert.Equal(0xA6A6A6A6UL, dummy);
}
[Fact]
public static unsafe void UInt52TestRandom()
{
for(int i = 0; i < 1000; i++)
{
var value = (ulong)Random.Shared.NextInt64();
value&= 0x1F_FFFF_FFFF_FFFFUL;// only safe range
UInt52TestOK(value);
}
}
[Fact]
public static unsafe void Int52TestRandom()
{
for(int i = 0; i < 1000; i++)
{
var value = Random.Shared.NextInt64(-9007199254740991L, 9007199254740991L);
Int52TestOK(value);
}
}
[Theory]
[InlineData(double.NegativeInfinity)]
[InlineData(double.PositiveInfinity)]
[InlineData(double.MinValue)]
[InlineData(double.MaxValue)]
[InlineData(double.Pi)]
[InlineData(9007199254740993.0)]//MAX_SAFE_INTEGER +2
public static unsafe void Int52TestRange(double value)
{
long actual = 0;
uint ptr = (uint)Unsafe.AsPointer(ref actual);
var bagFn = new Function("ptr", "value", @"
globalThis.App.runtime.setHeapI52(ptr, value);");
var ex=Assert.Throws<JSException>(() => bagFn.Call(null, ptr, value));
Assert.Contains("Value is not a safe integer", ex.Message);
double expectedD = value;
uint ptrD = (uint)Unsafe.AsPointer(ref expectedD);
var bagFnD = new Function("ptr", "value", @"
globalThis.App.runtime.getHeapI52(ptr);");
var exD = Assert.Throws<JSException>(() => bagFn.Call(null, ptr, value));
Assert.Contains("Value is not a safe integer", ex.Message);
}
[Theory]
[InlineData(-1.0)]
public static unsafe void UInt52TestRange(double value)
{
long actual = 0;
uint ptr = (uint)Unsafe.AsPointer(ref actual);
var bagFn = new Function("ptr", "value", @"
globalThis.App.runtime.setHeapU52(ptr, value);");
var ex=Assert.Throws<JSException>(() => bagFn.Call(null, ptr, value));
Assert.Contains("Can't convert negative Number into UInt64", ex.Message);
double expectedD = value;
uint ptrD = (uint)Unsafe.AsPointer(ref expectedD);
var bagFnD = new Function("ptr", "value", @"
globalThis.App.runtime.getHeapU52(ptr);");
var exD = Assert.Throws<JSException>(() => bagFn.Call(null, ptr, value));
Assert.Contains("Can't convert negative Number into UInt64", ex.Message);
}
[Fact]
public static unsafe void Int52TestNaN()
{
long actual = 0;
uint ptr = (uint)Unsafe.AsPointer(ref actual);
var bagFn = new Function("ptr", "value", @"
globalThis.App.runtime.setHeapI52(ptr, value);");
var ex=Assert.Throws<JSException>(() => bagFn.Call(null, ptr, double.NaN));
Assert.Contains("Value is not a safe integer: NaN (number)", ex.Message);
}
}
}

View file

@ -1,70 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices.JavaScript;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class ParallelTests
{
// The behavior of APIs like Invoke depends on how many items they are asked to invoke
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(5)]
[InlineData(32)]
[InlineData(250)]
public static void ParallelInvokeActionArray(int count)
{
var actions = new List<Action>();
int sum = 0, expected = 0;
for (int i = 0; i < count; i++) {
int j = i;
actions.Add(() => {
sum += j;
});
expected += j;
}
Parallel.Invoke(actions.ToArray());
Assert.Equal(expected, sum);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(32)]
[InlineData(250)]
public static void ParallelFor(int count)
{
int sum = 0, expected = 0;
for (int i = 0; i < count; i++)
expected += i;
Parallel.For(0, count, (i) => { sum += i; });
Assert.Equal(expected, sum);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(32)]
[InlineData(250)]
public static void ParallelForEach(int count)
{
int sum = 0, expected = 0;
var items = new List<int>();
for (int i = 0; i < count; i++) {
items.Add(i);
expected += i;
}
Parallel.ForEach(items, (i) => { sum += i; });
Assert.Equal(expected, sum);
}
}
}

View file

@ -1,38 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using Xunit;
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public static class TypedArrayTests
{
private static Function _objectPrototype;
public static IEnumerable<object[]> Object_Prototype()
{
_objectPrototype ??= new Function("return Object.prototype.toString;");
yield return new object[] { _objectPrototype.Call() };
}
[Theory]
[MemberData(nameof(Object_Prototype))]
public static void Uint8ArrayFrom(Function objectPrototype)
{
var array = new byte[50];
Uint8Array from = Uint8Array.From(array);
Assert.Equal(50, from.Length);
Assert.Equal("[object Uint8Array]", objectPrototype.Call(from));
}
[Theory]
[MemberData(nameof(Object_Prototype))]
public static void Uint8ArrayFromArrayBuffer(Function objectPrototype)
{
Uint8Array from = new Uint8Array(new ArrayBuffer(50));
Assert.True(from.Length == 50);
Assert.Equal("[object Uint8Array]", objectPrototype.Call(from));
}
}
}

View file

@ -8,10 +8,8 @@
<WasmXHarnessArgs>$(WasmXHarnessArgs) --engine-arg=--expose-gc --web-server-use-cop</WasmXHarnessArgs>
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
<PublishTrimmed>true</PublishTrimmed>
<WasmEnableLegacyJsInterop>false</WasmEnableLegacyJsInterop>
<FeatureWasmThreads Condition="'$(TargetPlatformIdentifier)' == 'browser' and '$(MonoWasmBuildVariant)' == 'multithread'">true</FeatureWasmThreads>
<DefineConstants Condition="'$(FeatureWasmThreads)' == 'true'">$(DefineConstants);FEATURE_WASM_THREADS</DefineConstants>
<DefineConstants Condition="'$(WasmEnableLegacyJsInterop)' == 'false'">$(DefineConstants);DISABLE_LEGACY_JS_INTEROP</DefineConstants>
<!-- Use following lines to write the generated files to disk. -->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>
@ -24,12 +22,15 @@
<Compile Include="System\Runtime\InteropServices\JavaScript\JavaScriptTestHelper.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\JSImportExportTest.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\SecondRuntimeTest.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\HttpRequestMessageTest.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\TimerTests.cs" />
<Compile Include="System\Runtime\InteropServices\JavaScript\Utils.cs" />
<None Include="System\Runtime\InteropServices\JavaScript\JavaScriptTestHelper.mjs" />
<None Include="$(CompilerGeneratedFilesOutputPath)\..\browser-wasm\generated\Microsoft.Interop.JavaScript.JSImportGenerator\Microsoft.Interop.JavaScript.JSImportGenerator\JSImports.g.cs" />
<None Include="$(CompilerGeneratedFilesOutputPath)\..\browser-wasm\generated\Microsoft.Interop.JavaScript.JSImportGenerator\Microsoft.Interop.JavaScript.JsExportGenerator\JSExports.g.cs" />
<WasmExtraFilesToDeploy Include="System\Runtime\InteropServices\JavaScript\JavaScriptTestHelper.mjs" />
<WasmExtraFilesToDeploy Include="System\Runtime\InteropServices\JavaScript\SecondRuntimeTest.js" />
<WasmExtraFilesToDeploy Include="System\Runtime\InteropServices\JavaScript\timers.mjs" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime.InteropServices.JavaScript\src\System.Runtime.InteropServices.JavaScript.csproj" SkipUseReferenceAssembly="true"/>
</ItemGroup>
<ItemGroup Condition="'$(FeatureWasmThreads)' == 'true'" >

View file

@ -366,89 +366,6 @@ namespace System.Runtime.InteropServices.JavaScript.Http.Tests
"}", rm.ToString());
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBrowserDomSupported))]
public async Task BlobUri_Marshal_CorrectValues_Browser()
{
Utils.InvokeJS(@"
function typedArrayToURL(typedArray, mimeType) {
return URL.createObjectURL(new Blob([typedArray.buffer], {type: mimeType}))
}
const bytes = new Uint8Array(59);
for(let i = 0; i < 59; i++) {
bytes[i] = 32 + i;
}
const url = typedArrayToURL(bytes, 'text/plain');
// Calls method with string that will be marshaled as valid URI
App.call_test_method (""InvokeString"", [ url ]);
");
var client = new HttpClient ();
Assert.StartsWith ("blob:", HelperMarshal._stringResource);
HttpRequestMessage rm = new HttpRequestMessage(HttpMethod.Get, new Uri (HelperMarshal._stringResource));
HttpResponseMessage resp = await client.SendAsync (rm);
Assert.NotNull (resp.Content);
string content = await resp.Content.ReadAsStringAsync();
Assert.Equal (59, content.Length);
}
[Fact]
public void BlobStringUri_Marshal_CorrectValues()
{
Utils.InvokeJS(@"
function typedArrayToURL(typedArray, mimeType) {
// URL.createObjectURL does not work outside of browser but since this was actual
// test code from https://developer.mozilla.org/en-US/docs/Web/API/Blob
// left it in to show what this should do if the test code were to actually run
//return URL.createObjectURL(new Blob([typedArray.buffer], {type: mimeType}))
return 'blob:https://mdn.mozillademos.org/ca45b575-6348-4d3e-908a-3dbf3d146ea7';
}
const bytes = new Uint8Array(59);
for(let i = 0; i < 59; i++) {
bytes[i] = 32 + i;
}
const url = typedArrayToURL(bytes, 'text/plain');
// Calls method with string that will be converted to a valid Uri
// within the method
App.call_test_method (""SetBlobUrl"", [ url ]);
");
var rm = new HttpRequestMessage(HttpMethod.Post, HelperMarshal._blobURL);
Assert.Equal(HttpMethod.Post, rm.Method);
Assert.Equal(_expectedRequestMessageVersion, rm.Version);
Assert.Null(rm.Content);
Assert.Equal(new Uri("blob:https://mdn.mozillademos.org/ca45b575-6348-4d3e-908a-3dbf3d146ea7"), rm.RequestUri);
}
[Fact]
public void BlobUri_Marshal_CorrectValues()
{
Utils.InvokeJS(@"
function typedArrayToURL(typedArray, mimeType) {
// URL.createObjectURL does not work outside of browser but since this was actual
// test code from https://developer.mozilla.org/en-US/docs/Web/API/Blob
// left it in to show what this should do if the test code were to actually run
//return URL.createObjectURL(new Blob([typedArray.buffer], {type: mimeType}))
return 'blob:https://mdn.mozillademos.org/ca45b575-6348-4d3e-908a-3dbf3d146ea7';
}
const bytes = new Uint8Array(59);
for(let i = 0; i < 59; i++) {
bytes[i] = 32 + i;
}
const url = typedArrayToURL(bytes, 'text/plain');
// Calls method with string that will be marshaled as valid URI
App.call_test_method (""SetBlobAsUri"", [ url ]);
");
var rm = new HttpRequestMessage(HttpMethod.Post, HelperMarshal._blobURI);
Assert.Equal(HttpMethod.Post, rm.Method);
Assert.Equal(_expectedRequestMessageVersion, rm.Version);
Assert.Null(rm.Content);
Assert.Equal(new Uri("blob:https://mdn.mozillademos.org/ca45b575-6348-4d3e-908a-3dbf3d146ea7"), rm.RequestUri);
}
#region Helper methods
private class MockContent : HttpContent

View file

@ -68,11 +68,6 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
[Fact]
public unsafe void DotnetInstance()
{
#if !DISABLE_LEGACY_JS_INTEROP
Assert.True(JSHost.DotnetInstance.HasProperty("MONO"));
Assert.Equal("object", JSHost.DotnetInstance.GetTypeOfProperty("MONO"));
#endif
JSHost.DotnetInstance.SetProperty("testBool", true);
Assert.Equal("boolean", JSHost.DotnetInstance.GetTypeOfProperty("testBool"));

View file

@ -525,7 +525,6 @@
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Net.Http.Json\tests\FunctionalTests\System.Net.Http.Json.Functional.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.ObjectModel\tests\System.ObjectModel.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Private.Xml\tests\XmlSerializer\ReflectionOnly\System.Xml.XmlSerializer.ReflectionOnly.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Runtime.InteropServices.JavaScript\tests\System.Runtime.InteropServices.JavaScript.Legacy.UnitTests\System.Runtime.InteropServices.JavaScript.Legacy.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Runtime.Serialization.Formatters\tests\System.Runtime.Serialization.Formatters.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Runtime.Serialization.Json\tests\ReflectionOnly\System.Runtime.Serialization.Json.ReflectionOnly.Tests.csproj" />
<ProjectExclusions Include="$(MSBuildThisFileDirectory)System.Runtime.Serialization.Json\tests\System.Runtime.Serialization.Json.Tests.csproj" />

View file

@ -3,4 +3,3 @@
emsdk
runtime/dotnet.d.ts.sha256
runtime/dotnet-legacy.d.ts.sha256

View file

@ -26,7 +26,6 @@
<ICULibDir Condition="'$(MonoWasmThreads)' == 'true'">$([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'lib'))</ICULibDir>
<WasmEnableSIMD Condition="'$(WasmEnableSIMD)' == ''">true</WasmEnableSIMD>
<WasmEnableExceptionHandling Condition="'$(WasmEnableExceptionHandling)' == ''">true</WasmEnableExceptionHandling>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<WasmEnableJsInteropByValue Condition="'$(WasmEnableJsInteropByValue)' == '' and '$(MonoWasmThreads)' == 'true'">true</WasmEnableJsInteropByValue>
<WasmEnableJsInteropByValue Condition="'$(WasmEnableJsInteropByValue)' == ''">false</WasmEnableJsInteropByValue>
<FilterSystemTimeZones Condition="'$(FilterSystemTimeZones)' == ''">false</FilterSystemTimeZones>
@ -393,7 +392,6 @@
<CMakeBuildRuntimeConfigureCmd Condition="'$(WasmEnableSIMD)' != 'true'">$(CMakeBuildRuntimeConfigureCmd) -DCONFIGURATION_INTERPSIMDTABLES_LIB=&quot;nosimd&quot;</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd Condition="'$(MonoWasmThreads)' == 'true'">$(CMakeBuildRuntimeConfigureCmd) -DDISABLE_THREADS=0</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd Condition="'$(WasmEnableJsInteropByValue)' == 'true'">$(CMakeBuildRuntimeConfigureCmd) -DENABLE_JS_INTEROP_BY_VALUE=1</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd Condition="'$(WasmEnableLegacyJsInterop)' == 'false'">$(CMakeBuildRuntimeConfigureCmd) -DDISABLE_LEGACY_JS_INTEROP=1</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd>$(CMakeBuildRuntimeConfigureCmd) $(CMakeConfigurationEmsdkPath)</CMakeBuildRuntimeConfigureCmd>
<CMakeBuildRuntimeConfigureCmd Condition="'$(OS)' == 'Windows_NT'">call &quot;$(RepositoryEngineeringDir)native\init-vs-env.cmd&quot; &amp;&amp; call &quot;$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'emsdk_env.bat'))&quot; &amp;&amp; $(CMakeBuildRuntimeConfigureCmd)</CMakeBuildRuntimeConfigureCmd>
@ -405,8 +403,6 @@
<CMakeBuildRuntimeCmd Condition="'$(OS)' != 'Windows_NT'">bash -c 'source $(EMSDK_PATH)/emsdk_env.sh 2>&amp;1 &amp;&amp; $(CMakeBuildRuntimeCmd)'</CMakeBuildRuntimeCmd>
</PropertyGroup>
<ItemGroup>
<_CmakeEnvironmentVariable Include="DISABLE_LEGACY_JS_INTEROP=1" Condition="'$(WasmEnableLegacyJsInterop)' == 'false'"/>
<_CmakeEnvironmentVariable Include="DISABLE_LEGACY_JS_INTEROP=0" Condition="'$(WasmEnableLegacyJsInterop)' != 'false'"/>
<_CmakeEnvironmentVariable Include="ENABLE_JS_INTEROP_BY_VALUE=1" Condition="'$(WasmEnableJsInteropByValue)' != 'false'"/>
<_CmakeEnvironmentVariable Include="ENABLE_JS_INTEROP_BY_VALUE=0" Condition="'$(WasmEnableJsInteropByValue)' == 'false'"/>
<_CmakeEnvironmentVariable Include="WASM_ENABLE_SIMD=1" Condition="'$(WasmEnableSIMD)' != 'false'" />
@ -480,7 +476,6 @@
$(NativeBinDir)dotnet.runtime.js.map;
$(NativeBinDir)dotnet.native.js;
$(NativeBinDir)dotnet.d.ts;
$(NativeBinDir)dotnet-legacy.d.ts;
$(NativeBinDir)package.json;
$(NativeBinDir)dotnet.native.wasm"
DestinationFolder="$(MicrosoftNetCoreAppRuntimePackNativeDir)"
@ -529,7 +524,7 @@
<ItemGroup>
<_RollupInputs Include="$(BrowserProjectRoot)runtime/**/*.ts"
Exclude="$(BrowserProjectRoot)runtime/dotnet.d.ts;$(BrowserProjectRoot)runtime/dotnet-legacy.d.ts;$(BrowserProjectRoot)runtime/diagnostics-mock.d.ts;$(BrowserProjectRoot)runtime/node_modules/**/*.ts" />
Exclude="$(BrowserProjectRoot)runtime/dotnet.d.ts;$(BrowserProjectRoot)runtime/diagnostics-mock.d.ts;$(BrowserProjectRoot)runtime/node_modules/**/*.ts" />
<_RollupInputs Include="$(BrowserProjectRoot)runtime/**/tsconfig.*"
Exclude="$(BrowserProjectRoot)runtime/node_modules/**/tsconfig.*" />
<_RollupInputs Include="$(BrowserProjectRoot)runtime/workers/**/*.js"/>
@ -549,8 +544,6 @@
<_MonoRollupEnvironmentVariable Include="WASM_ENABLE_SIMD:0" Condition="'$(WasmEnableSIMD)' == 'false'" />
<_MonoRollupEnvironmentVariable Include="WASM_ENABLE_EH:1" Condition="'$(WasmEnableExceptionHandling)' != 'false'" />
<_MonoRollupEnvironmentVariable Include="WASM_ENABLE_EH:0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" />
<_MonoRollupEnvironmentVariable Include="DISABLE_LEGACY_JS_INTEROP:1" Condition="'$(WasmEnableLegacyJsInterop)' == 'false'" />
<_MonoRollupEnvironmentVariable Include="DISABLE_LEGACY_JS_INTEROP:0" Condition="'$(WasmEnableLegacyJsInterop)' != 'false'" />
<_MonoRollupEnvironmentVariable Include="ENABLE_JS_INTEROP_BY_VALUE:1" Condition="'$(WasmEnableJsInteropByValue)' == 'true'" />
<_MonoRollupEnvironmentVariable Include="ENABLE_JS_INTEROP_BY_VALUE:0" Condition="'$(WasmEnableJsInteropByValue)' != 'true'" />
<_MonoRollupEnvironmentVariable Include="MonoDiagnosticsMock:$(MonoDiagnosticsMock)" />

View file

@ -28,7 +28,6 @@
_WasmGenerateRunV8Script;
</WasmGenerateAppBundleDependsOn>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<WasmEnableJsInteropByValue Condition="'$(WasmEnableJsInteropByValue)' == '' and ( '$(WasmEnableThreads)' == 'true' or '$(MonoWasmBuildVariant)' == 'multithread' )">true</WasmEnableJsInteropByValue>
<WasmEnableJsInteropByValue Condition="'$(WasmEnableJsInteropByValue)' == ''">false</WasmEnableJsInteropByValue>
@ -48,7 +47,6 @@
<_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' == 'true' and '$(RunAOTCompilation)' == 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.WasmIntrinsics.xml"</_ExtraTrimmerArgs>
<_ExtraTrimmerArgs Condition="'$(WasmEnableSIMD)' != 'true'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.NoWasmIntrinsics.xml"</_ExtraTrimmerArgs>
<_ExtraTrimmerArgs Condition="'$(WasmEnableLegacyJsInterop)' == 'false'">$(_ExtraTrimmerArgs) --substitutions "$(MSBuildThisFileDirectory)ILLink.Substitutions.LegacyJsInterop.xml"</_ExtraTrimmerArgs>
<WasmUseEMSDK_PATH Condition="'$(WasmUseEMSDK_PATH)' == '' and '$(EMSDK_PATH)' != '' and Exists('$(MSBuildThisFileDirectory)WasmApp.InTree.targets')">true</WasmUseEMSDK_PATH>
<WasmClang>emcc</WasmClang>
@ -64,7 +62,6 @@
<!-- Allow running/debugging from VS -->
<ProjectCapability Include="DotNetCoreWeb"/>
<_BoolPropertiesThatTriggerRelinking Include="WasmEnableLegacyJsInterop" DefaultValueInRuntimePack="true" />
<_BoolPropertiesThatTriggerRelinking Include="WasmEnableSIMD" DefaultValueInRuntimePack="true" />
<_BoolPropertiesThatTriggerRelinking Include="WasmEnableExceptionHandling" DefaultValueInRuntimePack="true" />
<_BoolPropertiesThatTriggerRelinking Include="WasmNativeStrip" DefaultValueInRuntimePack="true" />
@ -278,7 +275,6 @@
<WasmInitialHeapSize Condition="'$(WasmInitialHeapSize)' == ''">$(EmccInitialHeapSize)</WasmInitialHeapSize>
<EmccStackSize Condition="'$(EmccStackSize)' == ''">5MB</EmccStackSize>
<WasmAllowUndefinedSymbols Condition="'$(WasmAllowUndefinedSymbols)' == ''">false</WasmAllowUndefinedSymbols>
<WasmEnableLegacyJsInterop Condition="'$(WasmEnableLegacyJsInterop)' == ''">true</WasmEnableLegacyJsInterop>
<WasmClang>$(EmscriptenUpstreamEmscriptenPath)emcc</WasmClang>
</PropertyGroup>
@ -310,7 +306,6 @@
<_EmccCFlags Include="-DLINK_ICALLS=1" Condition="'$(WasmLinkIcalls)' == 'true'" />
<_EmccCFlags Include="-DENABLE_AOT_PROFILER=1" Condition="$(WasmProfilers.Contains('aot'))" />
<_EmccCFlags Include="-DENABLE_BROWSER_PROFILER=1" Condition="$(WasmProfilers.Contains('browser'))" />
<_EmccCFlags Include="-DDISABLE_LEGACY_JS_INTEROP=1" Condition="'$(WasmEnableLegacyJsInterop)' == 'false'" />
<_EmccCFlags Include="-DENABLE_JS_INTEROP_BY_VALUE=1" Condition="'$(WasmEnableJsInteropByValue)' == 'true'" />
<_EmccCFlags Include="-DGEN_PINVOKE=1" />
@ -356,8 +351,6 @@
<EmscriptenEnvVars Include="PYTHONHOME=" Condition="'$(OS)' == 'Windows_NT'" />
<EmscriptenEnvVars Include="EM_CACHE=$(WasmCachePath)" Condition="'$(WasmCachePath)' != ''" />
<EmscriptenEnvVars Include="EM_FROZEN_CACHE=True" Condition="'$(WasmCachePath)' == '$(EmscriptenCacheSdkCacheDir)'" />
<EmscriptenEnvVars Include="DISABLE_LEGACY_JS_INTEROP=1" Condition="'$(WasmEnableLegacyJsInterop)' == 'false'" />
<EmscriptenEnvVars Include="DISABLE_LEGACY_JS_INTEROP=0" Condition="'$(WasmEnableLegacyJsInterop)' != 'false'" />
<EmscriptenEnvVars Include="ENABLE_JS_INTEROP_BY_VALUE=1" Condition="'$(WasmEnableJsInteropByValue)' == 'true'" />
<EmscriptenEnvVars Include="ENABLE_JS_INTEROP_BY_VALUE=0" Condition="'$(WasmEnableJsInteropByValue)' != 'true'" />
<EmscriptenEnvVars Include="WASM_ENABLE_SIMD=1" Condition="'$(WasmEnableSIMD)' != 'false'" />

View file

@ -1,7 +0,0 @@
<linker>
<assembly fullname="System.Runtime.InteropServices.JavaScript">
<type fullname="System.Runtime.InteropServices.JavaScript.LegacyExportsTrimmingRoot">
<method signature="System.Void TrimWhenNotWasmEnableLegacyJsInterop()" body="remove" />
</type>
</assembly>
</linker>

View file

@ -32,8 +32,6 @@ Implementation:
- *after* any of the wasm build targets, use `AfterTargets="WasmBuildApp"` on that target
- Avoid depending on this target, because it is available only when the workload is installed. Use `$(WasmNativeWorkload)` to check if it is installed.
- When `Module.disableDotnet6Compatibility` is set it would not pollute global namespace.
## `Publish`
Implementation:

View file

@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.20)
project(mono-wasm-runtime C)
option(DISABLE_THREADS "defined if the build does NOT support multithreading" ON)
option(DISABLE_LEGACY_JS_INTEROP "defined if the build does not support legacy JavaScript interop" OFF)
option(ENABLE_JS_INTEROP_BY_VALUE "defined when JS interop without pointers to managed objects" OFF)
set(CMAKE_EXECUTABLE_SUFFIX ".js")

View file

@ -22,21 +22,6 @@ extern void mono_wasm_resolve_or_reject_promise(void *data);
typedef void (*background_job_cb)(void);
#ifndef DISABLE_LEGACY_JS_INTEROP
extern void mono_wasm_invoke_js_with_args_ref (int js_handle, MonoString **method, MonoArray **args, int *is_exception, MonoObject **result);
extern void mono_wasm_get_object_property_ref (int js_handle, MonoString **propertyName, int *is_exception, MonoObject **result);
extern void mono_wasm_set_object_property_ref (int js_handle, MonoString **propertyName, MonoObject **value, int createIfNotExist, int hasOwnProperty, int *is_exception, MonoObject **result);
extern void mono_wasm_get_by_index_ref (int js_handle, int property_index, int *is_exception, MonoObject **result);
extern void mono_wasm_set_by_index_ref (int js_handle, int property_index, MonoObject **value, int *is_exception, MonoObject **result);
extern void mono_wasm_get_global_object_ref (MonoString **global_name, 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_create_cs_owned_object_ref (MonoString **core_name, MonoArray **args, 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);
// Blazor specific custom routines - see dotnet_support.js for backing code
extern void* mono_wasm_invoke_js_blazor (MonoString **exceptionMessage, void *callInfo, void* arg0, void* arg1, void* arg2);
#endif /* DISABLE_LEGACY_JS_INTEROP */
#ifndef DISABLE_THREADS
extern void mono_wasm_install_js_worker_interop (int context_gc_handle);
extern void mono_wasm_uninstall_js_worker_interop ();
@ -87,21 +72,6 @@ void bindings_initialize_internals (void)
mono_add_internal_call ("Interop/Runtime::InvokeJSFunction", mono_wasm_invoke_js_function);
#endif /* DISABLE_THREADS */
#ifndef DISABLE_LEGACY_JS_INTEROP
// legacy
mono_add_internal_call ("Interop/Runtime::InvokeJSWithArgsRef", mono_wasm_invoke_js_with_args_ref);
mono_add_internal_call ("Interop/Runtime::GetObjectPropertyRef", mono_wasm_get_object_property_ref);
mono_add_internal_call ("Interop/Runtime::SetObjectPropertyRef", mono_wasm_set_object_property_ref);
mono_add_internal_call ("Interop/Runtime::GetByIndexRef", mono_wasm_get_by_index_ref);
mono_add_internal_call ("Interop/Runtime::SetByIndexRef", mono_wasm_set_by_index_ref);
mono_add_internal_call ("Interop/Runtime::GetGlobalObjectRef", mono_wasm_get_global_object_ref);
mono_add_internal_call ("Interop/Runtime::TypedArrayToArrayRef", mono_wasm_typed_array_to_array_ref);
mono_add_internal_call ("Interop/Runtime::CreateCSOwnedObjectRef", mono_wasm_create_cs_owned_object_ref);
mono_add_internal_call ("Interop/Runtime::TypedArrayFromRef", mono_wasm_typed_array_from_ref);
// Blazor specific custom routines - see dotnet_support.js for backing code
mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJS", mono_wasm_invoke_js_blazor);
#endif /* DISABLE_LEGACY_JS_INTEROP */
mono_add_internal_call ("Interop/JsGlobalization::ChangeCaseInvariant", mono_wasm_change_case_invariant);
mono_add_internal_call ("Interop/JsGlobalization::ChangeCase", mono_wasm_change_case);
mono_add_internal_call ("Interop/JsGlobalization::CompareString", mono_wasm_compare_string);

View file

@ -2,36 +2,19 @@
// The .NET Foundation licenses this file to you under the MIT license.
import MonoWasmThreads from "consts:monoWasmThreads";
import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
import type {
MonoArray, MonoAssembly, MonoClass,
MonoAssembly, MonoClass,
MonoMethod, MonoObject,
MonoType, MonoObjectRef, MonoStringRef, JSMarshalerArguments
} from "./types/internal";
import type { VoidPtr, CharPtrPtr, Int32Ptr, CharPtr, ManagedPointer } from "./types/emscripten";
import { linkerDisableLegacyJsInterop, linkerEnableAotProfiler, linkerEnableBrowserProfiler, Module } from "./globals";
import { linkerEnableAotProfiler, linkerEnableBrowserProfiler, Module } from "./globals";
import { mono_log_error } from "./logging";
import { mono_assert } from "./globals";
type SigLine = [lazyOrSkip: boolean | (() => boolean), name: string, returnType: string | null, argTypes?: string[], opts?: any];
const legacy_interop_cwraps: SigLine[] = WasmEnableLegacyJsInterop ? [
[true, "mono_wasm_array_get_ref", "void", ["number", "number", "number"]],
[true, "mono_wasm_obj_array_new_ref", "void", ["number", "number"]],
[true, "mono_wasm_obj_array_set_ref", "void", ["number", "number", "number"]],
[true, "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_string_array_new_ref", "void", ["number", "number"]],
[true, "mono_wasm_typed_array_new_ref", "void", ["number", "number", "number", "number", "number"]],
[true, "mono_wasm_get_delegate_invoke_ref", "number", ["number"]],
[true, "mono_wasm_get_type_name", "string", ["number"]],
[true, "mono_wasm_get_type_aqn", "string", ["number"]],
[true, "mono_wasm_obj_array_new", "number", ["number"]],
[true, "mono_wasm_obj_array_set", "void", ["number", "number", "number"]],
[true, "mono_wasm_array_length_ref", "number", ["number"]],
] : [];
const threading_cwraps: SigLine[] = MonoWasmThreads ? [
// MONO.diagnostics
[true, "mono_wasm_event_pipe_enable", "bool", ["string", "number", "number", "string", "bool", "number"]],
@ -46,7 +29,6 @@ const threading_cwraps: SigLine[] = MonoWasmThreads ? [
// 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
[true, "mono_wasm_register_root", "number", ["number", "number", "string"]],
[true, "mono_wasm_deregister_root", null, ["number"]],
[true, "mono_wasm_string_get_data_ref", null, ["number", "number", "number", "number"]],
@ -64,7 +46,6 @@ const fn_signatures: SigLine[] = [
[false, "mono_wasm_load_runtime", null, ["string", "number"]],
[true, "mono_wasm_change_debugger_log_level", "void", ["number"]],
// BINDING
[true, "mono_wasm_get_corlib", "number", []],
[true, "mono_wasm_assembly_load", "number", ["string"]],
[true, "mono_wasm_assembly_find_class", "number", ["number", "string", "string"]],
@ -76,7 +57,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_wasm_assembly_get_entry_point", "number", ["number", "number"]],
[true, "mono_wasm_class_get_type", "number", ["number"]],
//INTERNAL
[false, "mono_wasm_exit", "void", ["number"]],
[false, "mono_wasm_abort", "void", []],
[true, "mono_wasm_getenv", "number", ["string"]],
@ -155,26 +135,8 @@ const fn_signatures: SigLine[] = [
[true, "mono_interp_pgo_save_table", "number", ["number", "number"]],
...threading_cwraps,
...legacy_interop_cwraps,
];
export interface t_LegacyCwraps {
// legacy interop
mono_wasm_array_get_ref(array: MonoObjectRef, idx: number, result: MonoObjectRef): void;
mono_wasm_obj_array_new_ref(size: number, result: MonoObjectRef): void;
mono_wasm_obj_array_set_ref(array: MonoObjectRef, idx: number, obj: MonoObjectRef): void;
mono_wasm_try_unbox_primitive_and_get_type_ref(obj: MonoObjectRef, buffer: VoidPtr, buffer_size: number): number;
mono_wasm_box_primitive_ref(klass: MonoClass, value: VoidPtr, value_size: number, result: MonoObjectRef): void;
mono_wasm_string_array_new_ref(size: number, result: MonoObjectRef): void;
mono_wasm_typed_array_new_ref(arr: VoidPtr, length: number, size: number, type: number, result: MonoObjectRef): void;
mono_wasm_get_delegate_invoke_ref(delegate: MonoObjectRef): MonoMethod;
mono_wasm_get_type_name(ty: MonoType): string;
mono_wasm_get_type_aqn(ty: MonoType): string;
mono_wasm_obj_array_new(size: number): MonoArray;
mono_wasm_obj_array_set(array: MonoArray, idx: number, obj: MonoObject): void;
mono_wasm_array_length_ref(array: MonoObjectRef): number;
}
export interface t_ThreadingCwraps {
// MONO.diagnostics
mono_wasm_event_pipe_enable(outputPath: string | null, stream: VoidPtr, bufferSizeInMB: number, providers: string, rundownRequested: boolean, outSessionId: VoidPtr): boolean;
@ -193,7 +155,6 @@ export interface t_ProfilerCwraps {
}
export interface t_Cwraps {
// MONO
mono_wasm_register_root(start: VoidPtr, size: number, name: string): number;
mono_wasm_deregister_root(addr: VoidPtr): void;
mono_wasm_string_get_data_ref(stringRef: MonoStringRef, outChars: CharPtrPtr, outLengthBytes: Int32Ptr, outIsInterned: Int32Ptr): void;
@ -211,7 +172,6 @@ export interface t_Cwraps {
mono_wasm_load_runtime(unused: string, debugLevel: number): void;
mono_wasm_change_debugger_log_level(value: number): void;
// BINDING
mono_wasm_get_corlib(): MonoAssembly;
mono_wasm_assembly_load(name: string): MonoAssembly;
mono_wasm_assembly_find_class(assembly: MonoAssembly, namespace: string, name: string): MonoClass;
@ -222,7 +182,6 @@ export interface t_Cwraps {
mono_wasm_assembly_get_entry_point(assembly: MonoAssembly, idx: number): MonoMethod;
mono_wasm_intern_string_ref(strRef: MonoStringRef): void;
//INTERNAL
mono_wasm_exit(exit_code: number): void;
mono_wasm_abort(): void;
mono_wasm_getenv(name: string): CharPtr;
@ -308,7 +267,6 @@ export interface t_Cwraps {
const wrapped_c_functions: t_Cwraps = <any>{};
export default wrapped_c_functions;
export const legacy_c_functions: t_LegacyCwraps & t_Cwraps = wrapped_c_functions as any;
export const threads_c_functions: t_ThreadingCwraps & t_Cwraps = wrapped_c_functions as any;
export const profiler_c_functions: t_ProfilerCwraps & t_Cwraps = wrapped_c_functions as any;
@ -353,8 +311,7 @@ function cwrap(name: string, returnType: string | null, argTypes: string[] | und
}
export function init_c_exports(): void {
const lfns = WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop ? legacy_interop_cwraps : [];
const fns = [...fn_signatures, ...lfns];
const fns = [...fn_signatures];
for (const sig of fns) {
const wf: any = wrapped_c_functions;
const [lazyOrSkip, name, returnType, argTypes, opts] = sig;

View file

@ -1,295 +0,0 @@
//! Licensed to the .NET Foundation under one or more agreements.
//! The .NET Foundation licenses this file to you under the MIT license.
//!
//! This is generated file, see src/mono/wasm/runtime/rollup.config.js
//! This is not considered public API with backward compatibility guarantees.
declare interface ManagedPointer {
__brandManagedPointer: "ManagedPointer";
}
declare interface NativePointer {
__brandNativePointer: "NativePointer";
}
declare interface VoidPtr extends NativePointer {
__brand: "VoidPtr";
}
interface MonoObject extends ManagedPointer {
__brandMonoObject: "MonoObject";
}
interface MonoString extends MonoObject {
__brand: "MonoString";
}
interface MonoArray extends MonoObject {
__brand: "MonoArray";
}
interface MonoObjectRef extends ManagedPointer {
__brandMonoObjectRef: "MonoObjectRef";
}
type MemOffset = number | VoidPtr | NativePointer | ManagedPointer;
type NumberOrPointer = number | VoidPtr | NativePointer | ManagedPointer;
interface WasmRoot<T extends MonoObject> {
get_address(): MonoObjectRef;
get_address_32(): number;
get address(): MonoObjectRef;
get(): T;
set(value: T): T;
get value(): T;
set value(value: T);
copy_from_address(source: MonoObjectRef): void;
copy_to_address(destination: MonoObjectRef): void;
copy_from(source: WasmRoot<T>): void;
copy_to(destination: WasmRoot<T>): void;
valueOf(): T;
clear(): void;
release(): void;
toString(): string;
}
interface WasmRootBuffer {
get_address(index: number): MonoObjectRef;
get_address_32(index: number): number;
get(index: number): ManagedPointer;
set(index: number, value: ManagedPointer): ManagedPointer;
copy_value_from_address(index: number, sourceAddress: MonoObjectRef): void;
clear(): void;
release(): void;
toString(): string;
}
/**
* @deprecated Please use methods in top level API object instead
*/
type BINDINGType = {
/**
* @deprecated Please use [JSExportAttribute] instead
*/
bind_static_method: (fqn: string, signature?: string) => Function;
/**
* @deprecated Please use runMain() instead
*/
call_assembly_entry_point: (assembly: string, args?: any[], signature?: string) => number;
/**
* @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: (string: string) => MonoString;
/**
* @deprecated Not GC or thread safe
*/
js_typed_array_to_array: (js_obj: any) => MonoArray;
/**
* @deprecated Not GC or thread safe
*/
mono_array_to_js_array: (mono_array: MonoArray) => any[] | null;
/**
* @deprecated Not GC or thread safe
*/
js_to_mono_obj: (js_obj: any) => MonoObject;
/**
* @deprecated Not GC or thread safe
*/
conv_string: (mono_obj: MonoString) => string | null;
/**
* @deprecated Not GC or thread safe
*/
unbox_mono_obj: (mono_obj: MonoObject) => any;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_obj_array_new_ref: (size: number, result: MonoObjectRef) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_obj_array_set_ref: (array: MonoObjectRef, idx: number, obj: MonoObjectRef) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
js_string_to_mono_string_root: (string: string, result: WasmRoot<MonoString>) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
js_typed_array_to_array_root: (js_obj: any, result: WasmRoot<MonoArray>) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
js_to_mono_obj_root: (js_obj: any, result: WasmRoot<MonoObject>, should_add_in_flight: boolean) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
conv_string_root: (root: WasmRoot<MonoString>) => string | null;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
unbox_mono_obj_root: (root: WasmRoot<any>) => any;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_array_root_to_js_array: (arrayRoot: WasmRoot<MonoArray>) => any[] | null;
};
/**
* @deprecated Please use methods in top level API object instead
*/
type MONOType = {
/**
* @deprecated Please use setEnvironmentVariable() instead
*/
mono_wasm_setenv: (name: string, value: string) => void;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_load_bytes_into_heap: (bytes: Uint8Array) => VoidPtr;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_load_icu_data: (offset: VoidPtr) => boolean;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_runtime_ready: () => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_new_root_buffer: (capacity: number, name?: string) => WasmRootBuffer;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_new_root: <T extends MonoObject>(value?: T | undefined) => WasmRoot<T>;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_new_external_root: <T extends MonoObject>(address: VoidPtr | MonoObjectRef) => WasmRoot<T>;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_release_roots: (...args: WasmRoot<any>[]) => void;
/**
* @deprecated Please use runMain instead
*/
mono_run_main: (main_assembly_name: string, args: string[]) => Promise<number>;
/**
* @deprecated Please use runMainAndExit instead
*/
mono_run_main_and_exit: (main_assembly_name: string, args: string[]) => Promise<number>;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_load_runtime: (unused: string, debugLevel: number) => void;
/**
* @deprecated Please use getConfig() instead
*/
config: any;
/**
* @deprecated Please use config.assets instead
*/
loaded_files: string[];
/**
* @deprecated Please use setHeapB32
*/
setB32: (offset: MemOffset, value: number | boolean) => void;
/**
* @deprecated Please use setHeapI8
*/
setI8: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI16
*/
setI16: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI32
*/
setI32: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI52
*/
setI52: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapU52
*/
setU52: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI64Big
*/
setI64Big: (offset: MemOffset, value: bigint) => void;
/**
* @deprecated Please use setHeapU8
*/
setU8: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapU16
*/
setU16: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapU32
*/
setU32: (offset: MemOffset, value: NumberOrPointer) => void;
/**
* @deprecated Please use setHeapF32
*/
setF32: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapF64
*/
setF64: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use getHeapB32
*/
getB32: (offset: MemOffset) => boolean;
/**
* @deprecated Please use getHeapI8
*/
getI8: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI16
*/
getI16: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI32
*/
getI32: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI52
*/
getI52: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapU52
*/
getU52: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI64Big
*/
getI64Big: (offset: MemOffset) => bigint;
/**
* @deprecated Please use getHeapU8
*/
getU8: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapU16
*/
getU16: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapU32
*/
getU32: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapF32
*/
getF32: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapF64
*/
getF64: (offset: MemOffset) => number;
};
export { BINDINGType, MONOType, MonoArray, MonoObject, MonoString };

View file

@ -18,24 +18,6 @@ declare interface Int32Ptr extends NativePointer {
__brand: "Int32Ptr";
}
declare interface EmscriptenModule {
/** @deprecated Please use localHeapViewI8() instead.*/
HEAP8: Int8Array;
/** @deprecated Please use localHeapViewI16() instead.*/
HEAP16: Int16Array;
/** @deprecated Please use localHeapViewI32() instead. */
HEAP32: Int32Array;
/** @deprecated Please use localHeapViewI64() instead. */
HEAP64: BigInt64Array;
/** @deprecated Please use localHeapViewU8() instead. */
HEAPU8: Uint8Array;
/** @deprecated Please use localHeapViewU16() instead. */
HEAPU16: Uint16Array;
/** @deprecated Please use localHeapViewU32() instead */
HEAPU32: Uint32Array;
/** @deprecated Please use localHeapViewF32() instead */
HEAPF32: Float32Array;
/** @deprecated Please use localHeapViewF64() instead. */
HEAPF64: Float64Array;
_malloc(size: number): VoidPtr;
_free(ptr: VoidPtr): void;
out(message: string): void;
@ -378,7 +360,6 @@ declare const enum GlobalizationMode {
Hybrid = "hybrid"
}
type DotnetModuleConfig = {
disableDotnet6Compatibility?: boolean;
config?: MonoConfig;
configSrc?: string;
onConfigLoaded?: (config: MonoConfig) => void | Promise<void>;
@ -430,14 +411,6 @@ type APIType = {
localHeapViewF64: () => Float64Array;
};
type RuntimeAPI = {
/**
* @deprecated Please use API object instead. See also MONOType in dotnet-legacy.d.ts
*/
MONO: any;
/**
* @deprecated Please use API object instead. See also BINDINGType in dotnet-legacy.d.ts
*/
BINDING: any;
INTERNAL: any;
Module: EmscriptenModule;
runtimeId: number;

View file

@ -52,64 +52,6 @@ extern void mono_bundled_resources_add_assembly_resource (const char *id, const
extern void mono_bundled_resources_add_assembly_symbol_resource (const char *id, const uint8_t *data, uint32_t size, void (*free_func)(void *, void *), void *free_data);
extern void mono_bundled_resources_add_satellite_assembly_resource (const char *id, const char *name, const char *culture, const uint8_t *data, uint32_t size, void (*free_func)(void *, void*), void *free_data);
#ifndef DISABLE_LEGACY_JS_INTEROP
#define MARSHAL_TYPE_NULL 0
#define MARSHAL_TYPE_INT 1
#define MARSHAL_TYPE_FP64 2
#define MARSHAL_TYPE_STRING 3
#define MARSHAL_TYPE_VT 4
#define MARSHAL_TYPE_DELEGATE 5
#define MARSHAL_TYPE_TASK 6
#define MARSHAL_TYPE_OBJECT 7
#define MARSHAL_TYPE_BOOL 8
#define MARSHAL_TYPE_ENUM 9
#define MARSHAL_TYPE_DATE 20
#define MARSHAL_TYPE_DATEOFFSET 21
#define MARSHAL_TYPE_URI 22
#define MARSHAL_TYPE_SAFEHANDLE 23
// typed array marshaling
#define MARSHAL_ARRAY_BYTE 10
#define MARSHAL_ARRAY_UBYTE 11
#define MARSHAL_ARRAY_UBYTE_C 12
#define MARSHAL_ARRAY_SHORT 13
#define MARSHAL_ARRAY_USHORT 14
#define MARSHAL_ARRAY_INT 15
#define MARSHAL_ARRAY_UINT 16
#define MARSHAL_ARRAY_FLOAT 17
#define MARSHAL_ARRAY_DOUBLE 18
#define MARSHAL_TYPE_FP32 24
#define MARSHAL_TYPE_UINT32 25
#define MARSHAL_TYPE_INT64 26
#define MARSHAL_TYPE_UINT64 27
#define MARSHAL_TYPE_CHAR 28
#define MARSHAL_TYPE_STRING_INTERNED 29
#define MARSHAL_TYPE_VOID 30
#define MARSHAL_TYPE_POINTER 32
// errors
#define MARSHAL_ERROR_BUFFER_TOO_SMALL 512
#define MARSHAL_ERROR_NULL_CLASS_POINTER 513
#define MARSHAL_ERROR_NULL_TYPE_POINTER 514
static MonoClass* datetime_class;
static MonoClass* datetimeoffset_class;
static MonoClass* uri_class;
static MonoClass* task_class;
static MonoClass* safehandle_class;
static MonoClass* voidtaskresult_class;
static int resolved_datetime_class = 0,
resolved_datetimeoffset_class = 0,
resolved_uri_class = 0,
resolved_task_class = 0,
resolved_safehandle_class = 0,
resolved_voidtaskresult_class = 0;
#endif /* DISABLE_LEGACY_JS_INTEROP */
int
mono_string_instance_is_interned (MonoString *str_raw);
@ -421,470 +363,6 @@ mono_wasm_string_from_utf16_ref (const mono_unichar2 * chars, int length, MonoSt
MONO_EXIT_GC_UNSAFE;
}
#ifndef DISABLE_LEGACY_JS_INTEROP
static int
class_is_task (MonoClass *klass)
{
if (!klass)
return 0;
int result;
MONO_ENTER_GC_UNSAFE;
if (!task_class && !resolved_task_class) {
task_class = mono_class_from_name (mono_get_corlib(), "System.Threading.Tasks", "Task");
resolved_task_class = 1;
}
result = task_class && (klass == task_class || mono_class_is_subclass_of(klass, task_class, 0));
MONO_EXIT_GC_UNSAFE;
return result;
}
static MonoClass*
_get_uri_class(MonoException** exc)
{
MonoAssembly* assembly = mono_wasm_assembly_load ("System");
if (!assembly)
return NULL;
MonoClass* klass = mono_wasm_assembly_find_class(assembly, "System", "Uri");
return klass;
}
static void
_ensure_classes_resolved (void)
{
MONO_ENTER_GC_UNSAFE;
if (!datetime_class && !resolved_datetime_class) {
datetime_class = mono_class_from_name (mono_get_corlib(), "System", "DateTime");
resolved_datetime_class = 1;
}
if (!datetimeoffset_class && !resolved_datetimeoffset_class) {
datetimeoffset_class = mono_class_from_name (mono_get_corlib(), "System", "DateTimeOffset");
resolved_datetimeoffset_class = 1;
}
if (!uri_class && !resolved_uri_class) {
PVOLATILE(MonoException) exc = NULL;
uri_class = _get_uri_class((MonoException **)&exc);
resolved_uri_class = 1;
}
if (!safehandle_class && !resolved_safehandle_class) {
safehandle_class = mono_class_from_name (mono_get_corlib(), "System.Runtime.InteropServices", "SafeHandle");
resolved_safehandle_class = 1;
}
if (!voidtaskresult_class && !resolved_voidtaskresult_class) {
voidtaskresult_class = mono_class_from_name (mono_get_corlib(), "System.Threading.Tasks", "VoidTaskResult");
resolved_voidtaskresult_class = 1;
}
MONO_EXIT_GC_UNSAFE;
}
// This must be run inside a GC unsafe region
static int
_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType *type)
{
switch (mono_type) {
// case MONO_TYPE_CHAR: prob should be done not as a number?
case MONO_TYPE_VOID:
return MARSHAL_TYPE_VOID;
case MONO_TYPE_BOOLEAN:
return MARSHAL_TYPE_BOOL;
case MONO_TYPE_I: // IntPtr
case MONO_TYPE_U: // UIntPtr
case MONO_TYPE_PTR:
return MARSHAL_TYPE_POINTER;
case MONO_TYPE_I1:
case MONO_TYPE_I2:
case MONO_TYPE_I4:
return MARSHAL_TYPE_INT;
case MONO_TYPE_CHAR:
return MARSHAL_TYPE_CHAR;
case MONO_TYPE_U1:
case MONO_TYPE_U2:
case MONO_TYPE_U4: // The distinction between this and signed int is
// important due to how numbers work in JavaScript
return MARSHAL_TYPE_UINT32;
case MONO_TYPE_I8:
return MARSHAL_TYPE_INT64;
case MONO_TYPE_U8:
return MARSHAL_TYPE_UINT64;
case MONO_TYPE_R4:
return MARSHAL_TYPE_FP32;
case MONO_TYPE_R8:
return MARSHAL_TYPE_FP64;
case MONO_TYPE_STRING:
return MARSHAL_TYPE_STRING;
case MONO_TYPE_SZARRAY: { // simple zero based one-dim-array
if (klass) {
MonoClass *eklass = mono_class_get_element_class (klass);
MonoType *etype = mono_class_get_type (eklass);
switch (mono_type_get_type (etype)) {
case MONO_TYPE_U1:
return MARSHAL_ARRAY_UBYTE;
case MONO_TYPE_I1:
return MARSHAL_ARRAY_BYTE;
case MONO_TYPE_U2:
return MARSHAL_ARRAY_USHORT;
case MONO_TYPE_I2:
return MARSHAL_ARRAY_SHORT;
case MONO_TYPE_U4:
return MARSHAL_ARRAY_UINT;
case MONO_TYPE_I4:
return MARSHAL_ARRAY_INT;
case MONO_TYPE_R4:
return MARSHAL_ARRAY_FLOAT;
case MONO_TYPE_R8:
return MARSHAL_ARRAY_DOUBLE;
default:
return MARSHAL_TYPE_OBJECT;
}
} else {
return MARSHAL_TYPE_OBJECT;
}
}
default:
_ensure_classes_resolved ();
if (klass) {
if (klass == datetime_class)
return MARSHAL_TYPE_DATE;
if (klass == datetimeoffset_class)
return MARSHAL_TYPE_DATEOFFSET;
if (uri_class && mono_class_is_assignable_from(uri_class, klass))
return MARSHAL_TYPE_URI;
if (klass == voidtaskresult_class)
return MARSHAL_TYPE_VOID;
if (mono_class_is_enum (klass))
return MARSHAL_TYPE_ENUM;
if (type && !mono_type_is_reference (type)) //vt
return MARSHAL_TYPE_VT;
if (mono_class_is_delegate (klass))
return MARSHAL_TYPE_DELEGATE;
if (class_is_task(klass))
return MARSHAL_TYPE_TASK;
if (safehandle_class && (klass == safehandle_class || mono_class_is_subclass_of(klass, safehandle_class, 0)))
return MARSHAL_TYPE_SAFEHANDLE;
}
return MARSHAL_TYPE_OBJECT;
}
}
EMSCRIPTEN_KEEPALIVE void
mono_wasm_typed_array_new_ref (char *arr, int length, int size, int type, PPVOLATILE(MonoArray) result)
{
MONO_ENTER_GC_UNSAFE;
MonoClass * typeClass = mono_get_byte_class(); // default is Byte
switch (type) {
case MARSHAL_ARRAY_BYTE:
typeClass = mono_get_sbyte_class();
break;
case MARSHAL_ARRAY_SHORT:
typeClass = mono_get_int16_class();
break;
case MARSHAL_ARRAY_USHORT:
typeClass = mono_get_uint16_class();
break;
case MARSHAL_ARRAY_INT:
typeClass = mono_get_int32_class();
break;
case MARSHAL_ARRAY_UINT:
typeClass = mono_get_uint32_class();
break;
case MARSHAL_ARRAY_FLOAT:
typeClass = mono_get_single_class();
break;
case MARSHAL_ARRAY_DOUBLE:
typeClass = mono_get_double_class();
break;
case MARSHAL_ARRAY_UBYTE:
case MARSHAL_ARRAY_UBYTE_C:
typeClass = mono_get_byte_class();
break;
default:
printf ("Invalid marshal type %d in mono_wasm_typed_array_new", type);
abort();
}
PVOLATILE(MonoArray) buffer;
buffer = mono_array_new (mono_get_root_domain(), typeClass, length);
memcpy(mono_array_addr_with_size(buffer, sizeof(char), 0), arr, length * size);
store_volatile((PPVOLATILE(MonoObject))result, (MonoObject *)buffer);
MONO_EXIT_GC_UNSAFE;
}
EMSCRIPTEN_KEEPALIVE MonoMethod*
mono_wasm_get_delegate_invoke_ref (MonoObject **delegate)
{
MonoMethod * result;
MONO_ENTER_GC_UNSAFE;
result = mono_get_delegate_invoke(mono_object_get_class (*delegate));
MONO_EXIT_GC_UNSAFE;
return result;
}
EMSCRIPTEN_KEEPALIVE void
mono_wasm_box_primitive_ref (MonoClass *klass, void *value, int value_size, PPVOLATILE(MonoObject) result)
{
assert (klass);
MONO_ENTER_GC_UNSAFE;
MonoType *type = mono_class_get_type (klass);
int alignment;
if (mono_type_size (type, &alignment) <= value_size)
// TODO: use mono_value_box_checked and propagate error out
store_volatile(result, mono_value_box (root_domain, klass, value));
MONO_EXIT_GC_UNSAFE;
}
EMSCRIPTEN_KEEPALIVE char *
mono_wasm_get_type_name (MonoType * typePtr) {
return mono_type_get_name_full (typePtr, MONO_TYPE_NAME_FORMAT_REFLECTION);
}
EMSCRIPTEN_KEEPALIVE char *
mono_wasm_get_type_aqn (MonoType * typePtr) {
return mono_type_get_name_full (typePtr, MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED);
}
// this will return bool value if the object is a bool, otherwise it will return -1 or error
EMSCRIPTEN_KEEPALIVE int
mono_wasm_read_as_bool_or_null_unsafe (PVOLATILE(MonoObject) obj) {
int result = -1;
MONO_ENTER_GC_UNSAFE;
MonoClass *klass = mono_object_get_class (obj);
if (!klass) {
goto end;
}
MonoType *type = mono_class_get_type (klass);
if (!type) {
goto end;
}
int mono_type = mono_type_get_type (type);
if (MONO_TYPE_BOOLEAN == mono_type) {
result = ((signed char*)mono_object_unbox (obj) == 0 ? 0 : 1);
}
end:
MONO_EXIT_GC_UNSAFE;
return result;
}
// This code runs inside a gc unsafe region
static int
_mono_wasm_try_unbox_primitive_and_get_type_ref_impl (PVOLATILE(MonoObject) obj, void *result, int result_capacity) {
void **resultP = result;
int *resultI = result;
uint32_t *resultU = result;
int64_t *resultL = result;
float *resultF = result;
double *resultD = result;
/* Process obj before calling into the runtime, class_from_name () can invoke managed code */
MonoClass *klass = mono_object_get_class (obj);
if (!klass)
return MARSHAL_ERROR_NULL_CLASS_POINTER;
MonoType *type = mono_class_get_type (klass), *original_type = type;
if (!type)
return MARSHAL_ERROR_NULL_TYPE_POINTER;
if ((klass == mono_get_string_class ()) &&
mono_string_instance_is_interned ((MonoString *)obj)) {
*resultL = 0;
*resultP = type;
return MARSHAL_TYPE_STRING_INTERNED;
}
if (mono_class_is_enum (klass))
type = mono_type_get_underlying_type (type);
if (!type)
return MARSHAL_ERROR_NULL_TYPE_POINTER;
int mono_type = mono_type_get_type (type);
if (mono_type == MONO_TYPE_GENERICINST) {
// HACK: While the 'any other type' fallback is valid for classes, it will do the
// wrong thing for structs, so we need to make sure the valuetype handler is used
if (mono_type_generic_inst_is_valuetype (type))
mono_type = MONO_TYPE_VALUETYPE;
}
// FIXME: We would prefer to unbox once here but it will fail if the value isn't unboxable
switch (mono_type) {
case MONO_TYPE_I1:
case MONO_TYPE_BOOLEAN:
*resultI = *(signed char*)mono_object_unbox (obj);
break;
case MONO_TYPE_U1:
*resultU = *(unsigned char*)mono_object_unbox (obj);
break;
case MONO_TYPE_I2:
case MONO_TYPE_CHAR:
*resultI = *(short*)mono_object_unbox (obj);
break;
case MONO_TYPE_U2:
*resultU = *(unsigned short*)mono_object_unbox (obj);
break;
case MONO_TYPE_I4:
case MONO_TYPE_I:
*resultI = *(int*)mono_object_unbox (obj);
break;
case MONO_TYPE_U4:
*resultU = *(uint32_t*)mono_object_unbox (obj);
break;
case MONO_TYPE_R4:
*resultF = *(float*)mono_object_unbox (obj);
break;
case MONO_TYPE_R8:
*resultD = *(double*)mono_object_unbox (obj);
break;
case MONO_TYPE_PTR:
*resultU = (uint32_t)(*(void**)mono_object_unbox (obj));
break;
case MONO_TYPE_I8:
case MONO_TYPE_U8:
// FIXME: At present the javascript side of things can't handle this,
// but there's no reason not to future-proof this API
*resultL = *(int64_t*)mono_object_unbox (obj);
break;
case MONO_TYPE_VALUETYPE:
{
int obj_size = mono_object_get_size (obj),
required_size = (sizeof (int)) + (sizeof (MonoType *)) + obj_size;
// Check whether this struct has special-case marshaling
// FIXME: Do we need to null out obj before this?
int marshal_type = _marshal_type_from_mono_type (mono_type, klass, original_type);
if (marshal_type != MARSHAL_TYPE_VT)
return marshal_type;
// Check whether the result buffer is big enough for the struct and padding
if (result_capacity < required_size)
return MARSHAL_ERROR_BUFFER_TOO_SMALL;
// Store a header before the struct data with the size of the data and its MonoType
*resultP = type;
int * resultSize = (int *)(resultP + 1);
*resultSize = obj_size;
void * resultVoid = (resultP + 2);
void * unboxed = mono_object_unbox (obj);
memcpy (resultVoid, unboxed, obj_size);
return MARSHAL_TYPE_VT;
}
break;
default:
// If we failed to do a fast unboxing, return the original type information so
// that the caller can do a proper, slow unboxing later
// HACK: Store the class pointer into the result buffer so our caller doesn't
// have to call back into the native runtime later to get it
*resultP = type;
int fallbackResultType = _marshal_type_from_mono_type (mono_type, klass, original_type);
assert (fallbackResultType != MARSHAL_TYPE_VT);
return fallbackResultType;
}
// We successfully performed a fast unboxing here so use the type information
// matching what we unboxed (i.e. an enum's underlying type instead of its type)
int resultType = _marshal_type_from_mono_type (mono_type, klass, type);
assert (resultType != MARSHAL_TYPE_VT);
return resultType;
}
EMSCRIPTEN_KEEPALIVE int
mono_wasm_try_unbox_primitive_and_get_type_ref (MonoObject **objRef, void *result, int result_capacity)
{
if (!result)
return MARSHAL_ERROR_BUFFER_TOO_SMALL;
int retval;
int *resultI = result;
int64_t *resultL = result;
if (result_capacity >= sizeof (int64_t))
*resultL = 0;
else if (result_capacity >= sizeof (int))
*resultI = 0;
if (result_capacity < 16)
return MARSHAL_ERROR_BUFFER_TOO_SMALL;
if (!objRef || !(*objRef))
return MARSHAL_TYPE_NULL;
MONO_ENTER_GC_UNSAFE;
retval = _mono_wasm_try_unbox_primitive_and_get_type_ref_impl (*objRef, result, result_capacity);
MONO_EXIT_GC_UNSAFE;
return retval;
}
EMSCRIPTEN_KEEPALIVE int
mono_wasm_array_length_ref (MonoArray **array)
{
return mono_array_length (*array);
}
EMSCRIPTEN_KEEPALIVE void
mono_wasm_array_get_ref (PPVOLATILE(MonoArray) array, int idx, PPVOLATILE(MonoObject) result)
{
MONO_ENTER_GC_UNSAFE;
mono_gc_wbarrier_generic_store_atomic((void*)result, mono_array_get ((MonoArray*)*array, MonoObject*, idx));
MONO_EXIT_GC_UNSAFE;
}
EMSCRIPTEN_KEEPALIVE void
mono_wasm_obj_array_new_ref (int size, MonoArray **result)
{
MONO_ENTER_GC_UNSAFE;
mono_gc_wbarrier_generic_store_atomic(result, (MonoObject *)mono_array_new (root_domain, mono_get_object_class (), size));
MONO_EXIT_GC_UNSAFE;
}
// Deprecated
EMSCRIPTEN_KEEPALIVE MonoArray*
mono_wasm_obj_array_new (int size)
{
PVOLATILE(MonoArray) result = NULL;
mono_wasm_obj_array_new_ref(size, (MonoArray **)&result);
return result;
}
EMSCRIPTEN_KEEPALIVE void
mono_wasm_obj_array_set (MonoArray *array, int idx, MonoObject *obj)
{
mono_array_setref (array, idx, obj);
}
EMSCRIPTEN_KEEPALIVE void
mono_wasm_obj_array_set_ref (MonoArray **array, int idx, MonoObject **obj)
{
MONO_ENTER_GC_UNSAFE;
mono_array_setref (*array, idx, *obj);
MONO_EXIT_GC_UNSAFE;
}
EMSCRIPTEN_KEEPALIVE void
mono_wasm_string_array_new_ref (int size, MonoArray **result)
{
MONO_ENTER_GC_UNSAFE;
mono_gc_wbarrier_generic_store_atomic(result, (MonoObject *)mono_array_new (root_domain, mono_get_string_class (), size));
MONO_EXIT_GC_UNSAFE;
}
#endif /* DISABLE_LEGACY_JS_INTEROP */
EMSCRIPTEN_KEEPALIVE int
mono_wasm_exec_regression (int verbose_level, char *image)
{
@ -1099,3 +577,32 @@ EMSCRIPTEN_KEEPALIVE int mono_wasm_is_zero_page_reserved () {
// https://github.com/emscripten-core/emscripten/issues/19389
return (emscripten_stack_get_base() > 512) && (emscripten_stack_get_end() > 512);
}
// this will return bool value if the object is a bool, otherwise it will return -1 or error
// we use it in Blazor's renderBatch as internal only
EMSCRIPTEN_KEEPALIVE int
mono_wasm_read_as_bool_or_null_unsafe (PVOLATILE(MonoObject) obj) {
int result = -1;
MONO_ENTER_GC_UNSAFE;
MonoClass *klass = mono_object_get_class (obj);
if (!klass) {
goto end;
}
MonoType *type = mono_class_get_type (klass);
if (!type) {
goto end;
}
int mono_type = mono_type_get_type (type);
if (MONO_TYPE_BOOLEAN == mono_type) {
result = ((signed char*)mono_object_unbox (obj) == 0 ? 0 : 1);
}
end:
MONO_EXIT_GC_UNSAFE;
return result;
}

View file

@ -7,7 +7,6 @@
// -- this javascript file is evaluated by emcc during compilation! --
// because we can't pass custom define symbols to acorn optimizer, we use environment variables to pass other build options
const DISABLE_LEGACY_JS_INTEROP = process.env.DISABLE_LEGACY_JS_INTEROP === "1";
const WASM_ENABLE_SIMD = process.env.WASM_ENABLE_SIMD === "1";
const WASM_ENABLE_EH = process.env.WASM_ENABLE_EH === "1";
const ENABLE_BROWSER_PROFILER = process.env.ENABLE_BROWSER_PROFILER === "1";
@ -83,12 +82,7 @@ function injectDependencies() {
createWasmImportStubsFrom(methodIndexByName.mono_wasm_threads_imports);
#endif
if (!DISABLE_LEGACY_JS_INTEROP) {
createWasmImportStubsFrom(methodIndexByName.mono_wasm_legacy_interop_imports);
}
DotnetSupportLib["$DOTNET__postset"] = `DOTNET.setup({ ` +
`linkerDisableLegacyJsInterop: ${DISABLE_LEGACY_JS_INTEROP ? "true" : "false"},` +
`linkerWasmEnableSIMD: ${WASM_ENABLE_SIMD ? "true" : "false"},` +
`linkerWasmEnableEH: ${WASM_ENABLE_EH ? "true" : "false"},` +
`linkerEnableAotProfiler: ${ENABLE_AOT_PROFILER ? "true" : "false"}, ` +

View file

@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
import MonoWasmThreads from "consts:monoWasmThreads";
import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
import { mono_wasm_debugger_log, mono_wasm_add_dbg_command_received, mono_wasm_set_entrypoint_breakpoint, mono_wasm_fire_debugger_agent_message_with_data, mono_wasm_fire_debugger_agent_message_with_data_to_pause } from "./debug";
import { mono_wasm_release_cs_owned_object } from "./gc-handles";
@ -26,13 +25,6 @@ import { mono_wasm_compare_string, mono_wasm_ends_with, mono_wasm_starts_with, m
import { mono_wasm_get_calendar_info } from "./hybrid-globalization/calendar";
import { mono_wasm_install_js_worker_interop, mono_wasm_uninstall_js_worker_interop } from "./pthreads/shared";
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_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";
import { mono_wasm_typed_array_from_ref } from "./net6-legacy/buffers";
import { mono_wasm_get_culture_info } from "./hybrid-globalization/culture-info";
import { mono_wasm_get_first_day_of_week, mono_wasm_get_first_week_of_year } from "./hybrid-globalization/locales";
import { mono_wasm_browser_entropy } from "./crypto";
@ -57,20 +49,6 @@ export const mono_wasm_threads_imports = !MonoWasmThreads ? [] : [
mono_wasm_invoke_import_sync,
];
export const mono_wasm_legacy_interop_imports = !WasmEnableLegacyJsInterop ? [] : [
// 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_typed_array_to_array_ref,
mono_wasm_typed_array_from_ref,
mono_wasm_invoke_js_blazor,
];
export const mono_wasm_imports = [
// mini-wasm.c
mono_wasm_schedule_timer,
@ -127,8 +105,6 @@ const wasmImports: Function[] = [
...mono_wasm_imports,
// threading exports, if threading is enabled
...mono_wasm_threads_imports,
// legacy interop exports, if enabled
...mono_wasm_legacy_interop_imports
];
export function replace_linker_placeholders(imports: WebAssembly.Imports) {

View file

@ -1,14 +1,13 @@
// 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_imports, mono_wasm_legacy_interop_imports, mono_wasm_threads_imports } from "./exports-binding";
import { mono_wasm_imports, mono_wasm_threads_imports } from "./exports-binding";
import gitHash from "consts:gitHash";
export function export_linker_indexes_as_code(): string {
const indexByName: any = {
mono_wasm_imports: {},
mono_wasm_threads_imports: {},
mono_wasm_legacy_interop_imports: {},
};
let idx = 0;
for (const wi of mono_wasm_imports) {
@ -19,10 +18,6 @@ export function export_linker_indexes_as_code(): string {
indexByName.mono_wasm_threads_imports[wi.name] = idx;
idx++;
}
for (const wi of mono_wasm_legacy_interop_imports) {
indexByName.mono_wasm_legacy_interop_imports[wi.name] = idx;
idx++;
}
return `
var gitHash = "${gitHash}";
var methodIndexByName = ${JSON.stringify(indexByName, null, 2)};

View file

@ -3,11 +3,10 @@
import ProductVersion from "consts:productVersion";
import BuildConfiguration from "consts:configuration";
import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
import type { RuntimeAPI } from "./types";
import { Module, linkerDisableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setRuntimeGlobals, } from "./globals";
import { GlobalObjects, is_nullish } from "./types/internal";
import { Module, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setRuntimeGlobals, } from "./globals";
import { GlobalObjects } from "./types/internal";
import { configureEmscriptenStartup, configureRuntimeStartup, configureWorkerStartup } from "./startup";
import { create_weak_ref } from "./weak-ref";
@ -15,11 +14,7 @@ import { export_internal } from "./exports-internal";
import { export_api } from "./export-api";
import { initializeReplacements } from "./polyfills";
// legacy
import { mono_bind_static_method } from "./net6-legacy/method-calls";
import { export_binding_api, export_internal_api, export_mono_api } from "./net6-legacy/exports-legacy";
import { initializeLegacyExports } from "./net6-legacy/globals";
import { mono_log_warn, mono_wasm_stringify_as_error_with_stack } from "./logging";
import { mono_wasm_stringify_as_error_with_stack } from "./logging";
import { instantiate_asset, instantiate_symbols_asset, instantiate_segmentation_rules_asset } from "./assets";
import { jiterpreter_dump_stats } from "./jiterpreter";
import { forceDisposeProxies } from "./gc-handles";
@ -29,16 +24,6 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI {
const globals = globalObjects;
const globalThisAny = globalThis as any;
if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
initializeLegacyExports(globals);
}
// here we merge methods from the local objects into exported objects
if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
Object.assign(globals.mono, export_mono_api());
Object.assign(globals.binding, export_binding_api());
Object.assign(globals.internal, export_internal_api());
}
Object.assign(globals.internal, export_internal());
Object.assign(runtimeHelpers, {
stringify_as_error_with_stack: mono_wasm_stringify_as_error_with_stack,
@ -60,60 +45,6 @@ function initializeExports(globalObjects: GlobalObjects): RuntimeAPI {
},
...API,
});
if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
Object.assign(exportedRuntimeAPI, {
MONO: globals.mono,
BINDING: globals.binding,
});
}
if (typeof module.disableDotnet6Compatibility === "undefined") {
module.disableDotnet6Compatibility = true;
}
// here we expose objects global namespace for tests and backward compatibility
if (!module.disableDotnet6Compatibility) {
Object.assign(module, exportedRuntimeAPI);
if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
// backward compatibility
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
module.mono_bind_static_method = (fqn: string, signature: string/*ArgsMarshalString*/): Function => {
mono_log_warn("Module.mono_bind_static_method is obsolete, please use [JSExportAttribute] interop instead");
return mono_bind_static_method(fqn, signature);
};
}
const warnWrap = (name: string, provider: () => any) => {
if (typeof globalThisAny[name] !== "undefined") {
// it already exists in the global namespace
return;
}
let value: any = undefined;
Object.defineProperty(globalThis, name, {
get: () => {
if (is_nullish(value)) {
const stack = (new Error()).stack;
const nextLine = stack ? stack.substr(stack.indexOf("\n", 8) + 1) : "";
mono_log_warn(`global ${name} is obsolete, please use Module.${name} instead ${nextLine}`);
value = provider();
}
return value;
}
});
};
if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
globalThisAny.MONO = globals.mono;
globalThisAny.BINDING = globals.binding;
globalThisAny.INTERNAL = globals.internal;
}
globalThisAny.Module = module;
// Blazor back compat
warnWrap("cwrap", () => module.cwrap);
warnWrap("addRunDependency", () => module.addRunDependency);
warnWrap("removeRunDependency", () => module.removeRunDependency);
}
// this code makes it possible to find dotnet runtime on a page via global namespace, even when there are multiple runtimes at the same time
let list: RuntimeList;

View file

@ -28,8 +28,7 @@ export let ENVIRONMENT_IS_PTHREAD: boolean;
export let exportedRuntimeAPI: RuntimeAPI = null as any;
export let runtimeHelpers: RuntimeHelpers = null as any;
export let loaderHelpers: LoaderHelpers = null as any;
// this is when we link with workload tools. The consts:wasmEnableLegacyJsInterop is when we compile with rollup.
export let linkerDisableLegacyJsInterop = false;
export let linkerWasmEnableSIMD = true;
export let linkerWasmEnableEH = true;
export let linkerEnableAotProfiler = false;
@ -39,7 +38,6 @@ export let _runtimeModuleLoaded = false; // please keep it in place also as roll
export function passEmscriptenInternals(internals: EmscriptenInternals): void {
ENVIRONMENT_IS_PTHREAD = internals.isPThread;
linkerDisableLegacyJsInterop = internals.linkerDisableLegacyJsInterop;
linkerWasmEnableSIMD = internals.linkerWasmEnableSIMD;
linkerWasmEnableEH = internals.linkerWasmEnableEH;
linkerEnableAotProfiler = internals.linkerEnableAotProfiler;

View file

@ -70,7 +70,6 @@ export function setLoaderGlobals(
});
Object.assign(globalObjects.module, {
disableDotnet6Compatibility: true,
config: deep_merge_config(monoConfig, { environmentVariables: {} }),
});
Object.assign(runtimeHelpers, {

View file

@ -1,114 +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 { wrap_error_root, wrap_no_error_root } from "../invoke-js";
import { mono_wasm_new_external_root } from "../roots";
import { MonoArray, MonoObjectRef, MonoObject } from "../types/internal";
import { Int32Ptr, TypedArray } from "../types/emscripten";
import { js_to_mono_obj_root } from "./js-to-cs";
import { localHeapViewU8 } from "../memory";
// 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);
wrap_no_error_root(is_exception);
} 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(localHeapViewU8().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;
}

View file

@ -1,115 +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, MonoMethod, MonoObject, WasmRoot, PromiseController } from "../types/internal";
import { mono_bind_method, _create_primitive_converters } from "./method-binding";
import { mono_wasm_new_root } from "../roots";
import { Module, runtimeHelpers } from "../globals";
import cwraps from "../cwraps";
import { legacyHelpers, wasm_type_symbol } from "./globals";
import { find_corlib_class } from "../class-loader";
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"],
[true, "_create_cs_owned_proxy_ref", "CreateCSOwnedProxyRef", "iiim"],
[true, "_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"],
[true, "_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 {
// please keep System.Runtime.InteropServices.JavaScript.JSHostImplementation.MappedType in sync
(<any>Object.prototype)[wasm_type_symbol] = 0;
(<any>Array.prototype)[wasm_type_symbol] = 1;
(<any>ArrayBuffer.prototype)[wasm_type_symbol] = 2;
(<any>DataView.prototype)[wasm_type_symbol] = 3;
(<any>Function.prototype)[wasm_type_symbol] = 4;
(<any>Uint8Array.prototype)[wasm_type_symbol] = 11;
const box_buffer_size = 65536;
legacyHelpers._unbox_buffer_size = 65536;
legacyHelpers._box_buffer = Module._malloc(box_buffer_size);
legacyHelpers._unbox_buffer = Module._malloc(legacyHelpers._unbox_buffer_size);
legacyHelpers._class_int32 = find_corlib_class("System", "Int32");
legacyHelpers._class_uint32 = find_corlib_class("System", "UInt32");
legacyHelpers._class_double = find_corlib_class("System", "Double");
legacyHelpers._class_boolean = find_corlib_class("System", "Boolean");
legacyHelpers._null_root = mono_wasm_new_root<MonoObject>();
_create_primitive_converters();
legacyHelpers.runtime_legacy_exports_classname = "LegacyExports";
legacyHelpers.runtime_legacy_exports_class = cwraps.mono_wasm_assembly_find_class(runtimeHelpers.runtime_interop_module, runtimeHelpers.runtime_interop_namespace, legacyHelpers.runtime_legacy_exports_classname);
if (!legacyHelpers.runtime_legacy_exports_class)
throw "Can't find " + runtimeHelpers.runtime_interop_namespace + "." + legacyHelpers.runtime_legacy_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(legacyHelpers.runtime_legacy_exports_class, method_name, -1);
if (!res)
throw "Can't find method " + runtimeHelpers.runtime_interop_namespace + "." + legacyHelpers.runtime_legacy_exports_classname + "." + method_name;
return res;
}

View file

@ -1,354 +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 { Int32Ptr, VoidPtr } from "../types/emscripten";
import { MarshalType, MonoType, MarshalError, MonoTypeNull, MonoArray, MonoArrayNull, MonoObject, MonoObjectNull, GCHandle, MonoStringRef, MonoObjectRef, MonoString, JSHandleDisposed, is_nullish, WasmRoot } from "../types/internal";
import { _are_promises_supported } from "../cancelable-promise";
import { legacy_c_functions as 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 { wrap_error_root, wrap_no_error_root } from "../invoke-js";
import { ManagedObject } from "../marshal";
import { getU32, getI32, getF32, getF64, setI32_unchecked } from "../memory";
import { mono_wasm_new_root, mono_wasm_new_external_root } from "../roots";
import { monoStringToString, monoStringToStringUnsafe } from "../strings";
import { legacyManagedExports } from "./corebindings";
import { legacyHelpers } from "./globals";
import { js_to_mono_obj_root } from "./js-to-cs";
import { assert_legacy_interop, mono_bind_method, mono_method_get_call_signature_ref } from "./method-binding";
import { createPromiseController } from "../globals";
const delegate_invoke_symbol = Symbol.for("wasm delegate_invoke");
// this is only used from Blazor
export function unbox_mono_obj(mono_obj: MonoObject): any {
assert_legacy_interop();
if (mono_obj === MonoObjectNull)
return undefined;
const root = mono_wasm_new_root(mono_obj);
try {
return unbox_mono_obj_root(root);
} finally {
root.release();
}
}
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 = 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;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function _unbox_mono_obj_root_with_known_nonprimitive_type_impl(root: WasmRoot<any>, type: MarshalType, typePtr: MonoType, unbox_buffer: VoidPtr): any {
//See MARSHAL_TYPE_ defines in driver.c
switch (type) {
case MarshalType.NULL:
return null;
case MarshalType.INT64:
case MarshalType.UINT64:
// TODO: Fix this once emscripten offers HEAPI64/HEAPU64 or can return them
throw new Error("int64 not available");
case MarshalType.STRING:
case MarshalType.STRING_INTERNED:
return monoStringToString(root);
case MarshalType.VT:
throw new Error("no idea on how to unbox value types");
case MarshalType.DELEGATE:
return _wrap_delegate_root_as_function(root);
case MarshalType.TASK:
return _unbox_task_root_as_promise(root);
case MarshalType.OBJECT:
return _unbox_ref_type_root_as_js_object(root);
case MarshalType.ARRAY_BYTE:
case MarshalType.ARRAY_UBYTE:
case MarshalType.ARRAY_UBYTE_C:
case MarshalType.ARRAY_SHORT:
case MarshalType.ARRAY_USHORT:
case MarshalType.ARRAY_INT:
case MarshalType.ARRAY_UINT:
case MarshalType.ARRAY_FLOAT:
case MarshalType.ARRAY_DOUBLE:
throw new Error("Marshaling of primitive arrays are not supported.");
case <MarshalType>20: // clr .NET DateTime
return new Date(legacyManagedExports._get_date_value_ref(root.address));
case <MarshalType>21: // clr .NET DateTimeOffset
return legacyManagedExports._object_to_string_ref(root.address);
case MarshalType.URI:
return legacyManagedExports._object_to_string_ref(root.address);
case MarshalType.SAFEHANDLE:
return _unbox_cs_owned_root_as_js_object(root);
case MarshalType.VOID:
return undefined;
default:
throw new Error(`no idea on how to unbox object of MarshalType ${type} at offset ${root.value} (root address is ${root.address})`);
}
}
export function _unbox_mono_obj_root_with_known_nonprimitive_type(root: WasmRoot<any>, type: MarshalType, unbox_buffer: VoidPtr): any {
if (type >= MarshalError.FIRST)
throw new Error(`Got marshaling error ${type} when attempting to unbox object at address ${root.value} (root located at ${root.address})`);
let typePtr = MonoTypeNull;
if ((type === MarshalType.VT) || (type == MarshalType.OBJECT)) {
typePtr = <MonoType><any>getU32(unbox_buffer);
if (<number><any>typePtr < 1024)
throw new Error(`Got invalid MonoType ${typePtr} for object at address ${root.value} (root located at ${root.address})`);
}
return _unbox_mono_obj_root_with_known_nonprimitive_type_impl(root, type, typePtr, unbox_buffer);
}
export function unbox_mono_obj_root(root: WasmRoot<any>): any {
if (root.value === 0)
return undefined;
const unbox_buffer = legacyHelpers._unbox_buffer;
const type = cwraps.mono_wasm_try_unbox_primitive_and_get_type_ref(root.address, unbox_buffer, legacyHelpers._unbox_buffer_size);
switch (type) {
case MarshalType.INT:
return getI32(unbox_buffer);
case MarshalType.UINT32:
return getU32(unbox_buffer);
case MarshalType.POINTER:
// FIXME: Is this right?
return getU32(unbox_buffer);
case MarshalType.FP32:
return getF32(unbox_buffer);
case MarshalType.FP64:
return getF64(unbox_buffer);
case MarshalType.BOOL:
return (getI32(unbox_buffer)) !== 0;
case MarshalType.CHAR:
return String.fromCharCode(getI32(unbox_buffer));
case MarshalType.NULL:
return null;
default:
return _unbox_mono_obj_root_with_known_nonprimitive_type(root, type, unbox_buffer);
}
}
export function mono_array_to_js_array(mono_array: MonoArray): any[] | null {
assert_legacy_interop();
if (mono_array === MonoArrayNull)
return null;
const arrayRoot = mono_wasm_new_root(mono_array);
try {
return mono_array_root_to_js_array(arrayRoot);
} finally {
arrayRoot.release();
}
}
function is_nested_array_ref(ele: WasmRoot<MonoObject>) {
return legacyManagedExports._is_simple_array_ref(ele.address);
}
export function mono_array_root_to_js_array(arrayRoot: WasmRoot<MonoArray>): any[] | null {
if (arrayRoot.value === MonoArrayNull)
return null;
const arrayAddress = arrayRoot.address;
const elemRoot = mono_wasm_new_root<MonoObject>();
const elemAddress = elemRoot.address;
try {
const len = cwraps.mono_wasm_array_length_ref(arrayAddress);
const res = new Array(len);
for (let i = 0; i < len; ++i) {
// TODO: pass arrayRoot.address and elemRoot.address into new API that copies
cwraps.mono_wasm_array_get_ref(arrayAddress, i, elemAddress);
if (is_nested_array_ref(elemRoot))
res[i] = mono_array_root_to_js_array(<any>elemRoot);
else
res[i] = unbox_mono_obj_root(elemRoot);
}
return res;
} finally {
elemRoot.release();
}
}
export function _wrap_delegate_root_as_function(root: WasmRoot<MonoObject>): Function | null {
if (root.value === MonoObjectNull)
return null;
// get strong reference to the Delegate
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): 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[]) {
assert_not_disposed(result);
const boundMethod = result[delegate_invoke_symbol];
return boundMethod(...args);
};
// bind the method
const delegateRoot = mono_wasm_new_root<MonoObject>();
get_js_owned_object_by_gc_handle_ref(gc_handle, delegateRoot.address);
try {
if (typeof result[delegate_invoke_symbol] === "undefined") {
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.");
}
}
} finally {
delegateRoot.release();
}
setup_managed_proxy(result, gc_handle);
} else {
assert_not_disposed(result);
}
return result;
}
export function mono_wasm_create_cs_owned_object_ref(core_name: MonoStringRef, args: MonoObjectRef, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
const argsRoot = mono_wasm_new_external_root<MonoArray>(args),
nameRoot = mono_wasm_new_external_root<MonoString>(core_name),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
const js_name = monoStringToString(nameRoot);
if (!js_name) {
wrap_error_root(is_exception, "Invalid name @" + nameRoot.value, resultRoot);
return;
}
const coreObj = (<any>globalThis)[js_name];
if (coreObj === null || typeof coreObj === "undefined") {
wrap_error_root(is_exception, "JavaScript host object '" + js_name + "' not found.", resultRoot);
return;
}
try {
const js_args = mono_array_root_to_js_array(argsRoot);
// This is all experimental !!!!!!
const allocator = function (constructor: Function, js_args: any[] | null) {
// Not sure if we should be checking for anything here
let argsList = [];
argsList[0] = constructor;
if (js_args)
argsList = argsList.concat(js_args);
// eslint-disable-next-line prefer-spread
const tempCtor = constructor.bind.apply(constructor, <any>argsList);
const js_obj = new tempCtor();
return js_obj;
};
const js_obj = allocator(coreObj, js_args);
const js_handle = mono_wasm_get_js_handle(js_obj);
// returns boxed js_handle int, because on exception we need to return String on same method signature
// here we don't have anything to in-flight reference, as the JSObject doesn't exist yet
js_to_mono_obj_root(js_handle, resultRoot, false);
wrap_no_error_root(is_exception);
} catch (ex) {
wrap_error_root(is_exception, ex, resultRoot);
return;
}
} finally {
resultRoot.release();
argsRoot.release();
nameRoot.release();
}
}
function _unbox_task_root_as_promise(root: WasmRoot<MonoObject>) {
if (root.value === MonoObjectNull)
return null;
if (!_are_promises_supported)
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 = 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);
// If the promise for this gc_handle was already collected (or was never created)
if (!result) {
const explicitFinalization = () => teardown_managed_proxy(result, gc_handle);
const { promise, promise_control } = createPromiseController(explicitFinalization, explicitFinalization);
// note that we do not implement promise/task roundtrip
// With more complexity we could recover original instance when this promise is marshaled back to C#.
result = promise;
// register C# side of the continuation
legacyManagedExports._setup_js_cont_ref(root.address, promise_control);
setup_managed_proxy(result, gc_handle);
}
return result;
}
export function _unbox_ref_type_root_as_js_object(root: WasmRoot<MonoObject>): any {
if (root.value === MonoObjectNull)
return null;
// 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 = 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);
}
return mono_wasm_get_jsobj_from_js_handle(js_handle);
}
// otherwise this is C# only object
// get strong reference to Object
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);
// If the JS object for this gc_handle was already collected (or was never created)
if (is_nullish(result)) {
result = new ManagedObject();
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);
}
/**
* @deprecated Not GC or thread safe
*/
export function conv_string(mono_obj: MonoString): string | null {
assert_legacy_interop();
return monoStringToStringUnsafe(mono_obj);
}

View file

@ -1,243 +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 type { MemOffset, MonoArray, MonoObject, MonoObjectRef, MonoString, NumberOrPointer, WasmRoot, WasmRootBuffer } from "../types/internal";
import type { VoidPtr } from "../types/emscripten";
/**
* @deprecated Please use methods in top level API object instead
*/
export type BINDINGType = {
/**
* @deprecated Please use [JSExportAttribute] instead
*/
bind_static_method: (fqn: string, signature?: string) => Function;
/**
* @deprecated Please use runMain() instead
*/
call_assembly_entry_point: (assembly: string, args?: any[], signature?: string) => number;
/**
* @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: (string: string) => MonoString;
/**
* @deprecated Not GC or thread safe
*/
js_typed_array_to_array: (js_obj: any) => MonoArray;
/**
* @deprecated Not GC or thread safe
*/
mono_array_to_js_array: (mono_array: MonoArray) => any[] | null;
/**
* @deprecated Not GC or thread safe
*/
js_to_mono_obj: (js_obj: any) => MonoObject;
/**
* @deprecated Not GC or thread safe
*/
conv_string: (mono_obj: MonoString) => string | null;
/**
* @deprecated Not GC or thread safe
*/
unbox_mono_obj: (mono_obj: MonoObject) => any;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_obj_array_new_ref: (size: number, result: MonoObjectRef) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_obj_array_set_ref: (array: MonoObjectRef, idx: number, obj: MonoObjectRef) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
js_string_to_mono_string_root: (string: string, result: WasmRoot<MonoString>) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
js_typed_array_to_array_root: (js_obj: any, result: WasmRoot<MonoArray>) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
js_to_mono_obj_root: (js_obj: any, result: WasmRoot<MonoObject>, should_add_in_flight: boolean) => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
conv_string_root: (root: WasmRoot<MonoString>) => string | null;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
unbox_mono_obj_root: (root: WasmRoot<any>) => any;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_array_root_to_js_array: (arrayRoot: WasmRoot<MonoArray>) => any[] | null;
};
/**
* @deprecated Please use methods in top level API object instead
*/
export type MONOType = {
/**
* @deprecated Please use setEnvironmentVariable() instead
*/
mono_wasm_setenv: (name: string, value: string) => void;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_load_bytes_into_heap: (bytes: Uint8Array) => VoidPtr;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_load_icu_data: (offset: VoidPtr) => boolean;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_runtime_ready: () => void;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_new_root_buffer: (capacity: number, name?: string) => WasmRootBuffer;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_new_root: <T extends MonoObject>(value?: T | undefined) => WasmRoot<T>;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_new_external_root: <T extends MonoObject>(address: VoidPtr | MonoObjectRef) => WasmRoot<T>;
/**
* @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead.
*/
mono_wasm_release_roots: (...args: WasmRoot<any>[]) => void;
/**
* @deprecated Please use runMain instead
*/
mono_run_main: (main_assembly_name: string, args: string[]) => Promise<number>;
/**
* @deprecated Please use runMainAndExit instead
*/
mono_run_main_and_exit: (main_assembly_name: string, args: string[]) => Promise<number>;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number;
/**
* @deprecated Please use config.assets instead
*/
mono_wasm_load_runtime: (unused: string, debugLevel: number) => void;
/**
* @deprecated Please use getConfig() instead
*/
config: any;
/**
* @deprecated Please use config.assets instead
*/
loaded_files: string[];
/**
* @deprecated Please use setHeapB32
*/
setB32: (offset: MemOffset, value: number | boolean) => void;
/**
* @deprecated Please use setHeapI8
*/
setI8: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI16
*/
setI16: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI32
*/
setI32: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI52
*/
setI52: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapU52
*/
setU52: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapI64Big
*/
setI64Big: (offset: MemOffset, value: bigint) => void;
/**
* @deprecated Please use setHeapU8
*/
setU8: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapU16
*/
setU16: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapU32
*/
setU32: (offset: MemOffset, value: NumberOrPointer) => void;
/**
* @deprecated Please use setHeapF32
*/
setF32: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use setHeapF64
*/
setF64: (offset: MemOffset, value: number) => void;
/**
* @deprecated Please use getHeapB32
*/
getB32: (offset: MemOffset) => boolean;
/**
* @deprecated Please use getHeapI8
*/
getI8: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI16
*/
getI16: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI32
*/
getI32: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI52
*/
getI52: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapU52
*/
getU52: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapI64Big
*/
getI64Big: (offset: MemOffset) => bigint;
/**
* @deprecated Please use getHeapU8
*/
getU8: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapU16
*/
getU16: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapU32
*/
getU32: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapF32
*/
getF32: (offset: MemOffset) => number;
/**
* @deprecated Please use getHeapF64
*/
getF64: (offset: MemOffset) => number;
};
export { MonoArray, MonoObject, MonoString };

View file

@ -1,115 +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 { legacy_c_functions as cwraps } from "../cwraps";
import { mono_wasm_runtime_ready } from "../debug";
import { mono_wasm_load_icu_data } from "../icu";
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 } from "../startup";
import { stringToMonoStringRoot, monoStringToString } from "../strings";
import { mono_array_to_js_array, unbox_mono_obj, unbox_mono_obj_root, mono_array_root_to_js_array, conv_string } 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";
import { BINDINGType, MONOType } from "./export-types";
import { mono_method_resolve } from "./method-binding";
import { runtimeHelpers } from "../globals";
import { stringToMonoStringIntern, stringToMonoStringUnsafe } from "./strings";
export function export_mono_api(): MONOType {
return {
// legacy MONO API
mono_wasm_setenv,
mono_wasm_load_bytes_into_heap,
mono_wasm_load_icu_data,
mono_wasm_runtime_ready,
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,
// for Blazor's future!
mono_wasm_add_assembly: <any>null,
mono_wasm_load_runtime,
config: 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,
};
}
export function cwraps_mono_api(mono: MONOType): void {
Object.assign(mono, {
mono_wasm_add_assembly: cwraps.mono_wasm_add_assembly,
});
}
export function export_internal_api(): any {
return {
stringToMonoStringIntern, // MarshalTests.cs
mono_method_resolve, //MarshalTests.cs
};
}
export function export_binding_api(): BINDINGType {
return {
// legacy 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: stringToMonoStringUnsafe,
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: stringToMonoStringRoot,
js_typed_array_to_array_root,
js_to_mono_obj_root,
conv_string_root: monoStringToString,
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,
});
}

View file

@ -1,37 +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 type { GlobalObjects, MonoClass } from "../types/internal";
import type { VoidPtr } from "../types/emscripten";
import type { BINDINGType, MONOType } from "./export-types";
export let MONO: MONOType;
export let BINDING: BINDINGType;
export const legacyHelpers: LegacyHelpers = <any>{
};
export function initializeLegacyExports(
globals: GlobalObjects,
): void {
MONO = globals.mono;
BINDING = globals.binding;
}
export type LegacyHelpers = {
runtime_legacy_exports_classname: string;
runtime_legacy_exports_class: MonoClass;
// A WasmRoot that is guaranteed to contain 0
_null_root: any;
_class_int32: MonoClass;
_class_uint32: MonoClass;
_class_double: MonoClass;
_class_boolean: MonoClass;
_unbox_buffer_size: number;
_box_buffer: VoidPtr;
_unbox_buffer: VoidPtr;
_box_root: any;
}
export const wasm_type_symbol = Symbol.for("wasm type");

View file

@ -1,294 +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 { isThenable } from "../cancelable-promise";
import { legacy_c_functions as 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 { Module } from "../globals";
import { wrap_error_root, wrap_no_error_root } from "../invoke-js";
import { setI32_unchecked, setU32_unchecked, setF64, setB32, localHeapViewU8 } from "../memory";
import { mono_wasm_new_root, mono_wasm_release_roots, mono_wasm_new_external_root } from "../roots";
import { stringToMonoStringRoot, stringToInternedMonoStringRoot } from "../strings";
import { MonoObject, is_nullish, MonoClass, MonoArray, MonoObjectNull, JSHandle, MonoObjectRef, JSHandleNull, JSHandleDisposed, WasmRoot } from "../types/internal";
import { TypedArray, Int32Ptr } from "../types/emscripten";
import { has_backing_array_buffer } from "./buffers";
import { legacyManagedExports } from "./corebindings";
import { get_js_owned_object_by_gc_handle_ref } from "./cs-to-js";
import { legacyHelpers, wasm_type_symbol } from "./globals";
import { assert_legacy_interop } from "./method-binding";
export function _js_to_mono_uri_root(should_add_in_flight: boolean, js_obj: any, result: WasmRoot<MonoObject>): void {
switch (true) {
case js_obj === null:
case typeof js_obj === "undefined":
result.clear();
return;
case typeof js_obj === "symbol":
case typeof js_obj === "string":
legacyManagedExports._create_uri_ref(js_obj, result.address);
return;
default:
_extract_mono_obj_root(should_add_in_flight, js_obj, result);
return;
}
}
// this is only used from Blazor
/**
* @deprecated Not GC or thread safe. For blazor use only
*/
export function js_to_mono_obj(js_obj: any): MonoObject {
assert_legacy_interop();
const temp = mono_wasm_new_root<MonoObject>();
try {
js_to_mono_obj_root(js_obj, temp, false);
return temp.value;
} finally {
temp.release();
}
}
/**
* @deprecated Not GC or thread safe
*/
export function _js_to_mono_obj_unsafe(should_add_in_flight: boolean, js_obj: any): MonoObject {
const temp = mono_wasm_new_root<MonoObject>();
try {
js_to_mono_obj_root(js_obj, temp, should_add_in_flight);
return temp.value;
} finally {
temp.release();
}
}
export function js_to_mono_obj_root(js_obj: any, result: WasmRoot<MonoObject>, should_add_in_flight: boolean): void {
assert_legacy_interop();
if (is_nullish(result))
throw new Error("Expected (value, WasmRoot, boolean)");
switch (true) {
case js_obj === null:
case typeof js_obj === "undefined":
result.clear();
return;
case typeof js_obj === "number": {
let box_class: MonoClass;
if ((js_obj | 0) === js_obj) {
setI32_unchecked(legacyHelpers._box_buffer, js_obj);
box_class = legacyHelpers._class_int32;
} else if ((js_obj >>> 0) === js_obj) {
setU32_unchecked(legacyHelpers._box_buffer, js_obj);
box_class = legacyHelpers._class_uint32;
} else {
setF64(legacyHelpers._box_buffer, js_obj);
box_class = legacyHelpers._class_double;
}
cwraps.mono_wasm_box_primitive_ref(box_class, legacyHelpers._box_buffer, 8, result.address);
return;
}
case typeof js_obj === "string":
stringToMonoStringRoot(js_obj, <any>result);
return;
case typeof js_obj === "symbol":
stringToInternedMonoStringRoot(js_obj, <any>result);
return;
case typeof js_obj === "boolean":
setB32(legacyHelpers._box_buffer, js_obj);
cwraps.mono_wasm_box_primitive_ref(legacyHelpers._class_boolean, legacyHelpers._box_buffer, 4, result.address);
return;
case isThenable(js_obj) === true: {
_wrap_js_thenable_as_task_root(js_obj, result);
return;
}
case js_obj.constructor.name === "Date":
// getTime() is always UTC
legacyManagedExports._create_date_time_ref(js_obj.getTime(), result.address);
return;
default:
_extract_mono_obj_root(should_add_in_flight, js_obj, result);
return;
}
}
function _extract_mono_obj_root(should_add_in_flight: boolean, js_obj: any, result: WasmRoot<MonoObject>): void {
result.clear();
if (js_obj === null || typeof js_obj === "undefined")
return;
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
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]) {
get_cs_owned_object_by_js_handle_ref(js_obj[cs_owned_js_handle_symbol], should_add_in_flight, result.address);
// It's possible the managed object corresponding to this JS object was collected,
// in which case we need to make a new one.
// FIXME: This check is not thread safe
if (!result.value) {
delete js_obj[cs_owned_js_handle_symbol];
}
}
// FIXME: This check is not thread safe
if (!result.value) {
// Obtain the JS -> C# type mapping.
const wasm_type = js_obj[wasm_type_symbol];
const wasm_type_id = typeof wasm_type === "undefined" ? 0 : wasm_type;
const js_handle = mono_wasm_get_js_handle(js_obj);
legacyManagedExports._create_cs_owned_proxy_ref(js_handle, wasm_type_id, should_add_in_flight ? 1 : 0, result.address);
}
}
// https://github.com/Planeshifter/emscripten-examples/blob/master/01_PassingArrays/sum_post.js
function js_typedarray_to_heap(typedArray: TypedArray) {
assert_legacy_interop();
const numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
const ptr = Module._malloc(numBytes);
const heapU8 = localHeapViewU8();
const heapBytes = new Uint8Array(heapU8.buffer, <any>ptr, numBytes);
heapBytes.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, numBytes));
// WARNING: returned memory view will get stale when linear memory grows on another thread. This is legacy interop so we don't try to fix it. The view will be fine when used in synchronous calls.
return heapBytes;
}
export function js_typed_array_to_array_root(js_obj: any, result: WasmRoot<MonoArray>): void {
// 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(js_obj) && js_obj.BYTES_PER_ELEMENT) {
const arrayType = js_obj[wasm_type_symbol];
const heapBytes = js_typedarray_to_heap(js_obj);
cwraps.mono_wasm_typed_array_new_ref(<any>heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType, result.address);
Module._free(<any>heapBytes.byteOffset);
}
else {
throw new Error("Object '" + js_obj + "' is not a typed array");
}
}
/**
* @deprecated Not GC or thread safe
*/
export function js_typed_array_to_array(js_obj: any): MonoArray {
const temp = mono_wasm_new_root<MonoArray>();
try {
js_typed_array_to_array_root(js_obj, temp);
return temp.value;
} finally {
temp.release();
}
}
export function js_to_mono_enum(js_obj: any): number {
if (typeof (js_obj) !== "number")
throw new Error(`Expected numeric value for enum argument, got '${js_obj}'`);
return js_obj | 0;
}
export function js_array_to_mono_array(js_array: any[], asString: boolean, should_add_in_flight: boolean): MonoArray {
const arrayRoot = mono_wasm_new_root<MonoArray>();
if (asString)
cwraps.mono_wasm_string_array_new_ref(js_array.length, arrayRoot.address);
else
cwraps.mono_wasm_obj_array_new_ref(js_array.length, arrayRoot.address);
const elemRoot = mono_wasm_new_root(MonoObjectNull);
const arrayAddress = arrayRoot.address;
const elemAddress = elemRoot.address;
try {
for (let i = 0; i < js_array.length; ++i) {
let obj = js_array[i];
if (asString)
obj = obj.toString();
js_to_mono_obj_root(obj, elemRoot, should_add_in_flight);
cwraps.mono_wasm_obj_array_set_ref(arrayAddress, i, elemAddress);
}
return arrayRoot.value;
} finally {
mono_wasm_release_roots(arrayRoot, elemRoot);
}
}
export function _wrap_js_thenable_as_task_root(thenable: Promise<any>, resultRoot: WasmRoot<MonoObject>): {
then_js_handle: JSHandle,
} {
if (!thenable) {
resultRoot.clear();
return <any>null;
}
// hold strong JS reference to thenable while in flight
// ideally, this should be hold alive by lifespan of the resulting C# Task, but this is good cheap aproximation
const thenable_js_handle = mono_wasm_get_js_handle(thenable);
// 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 = legacyManagedExports._create_tcs();
const holder: any = { tcs_gc_handle };
setup_managed_proxy(holder, tcs_gc_handle);
thenable.then((result) => {
legacyManagedExports._set_tcs_result_ref(tcs_gc_handle, result);
}, (reason) => {
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);
teardown_managed_proxy(holder, tcs_gc_handle); // this holds holder alive for finalizer, until the promise is freed
});
legacyManagedExports._get_tcs_task_ref(tcs_gc_handle, resultRoot.address);
// returns raw pointer to tcs.Task
return {
then_js_handle: thenable_js_handle,
};
}
export function mono_wasm_typed_array_to_array_ref(js_handle: JSHandle, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
const resultRoot = mono_wasm_new_external_root<MonoArray>(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, "ERR06: Invalid JS object handle '" + js_handle + "'", resultRoot);
return;
}
// returns pointer to C# array
js_typed_array_to_array_root(js_obj, resultRoot);
wrap_no_error_root(is_exception);
} catch (exc) {
wrap_error_root(is_exception, String(exc), resultRoot);
} finally {
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);
}

View file

@ -1,682 +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 MonoWasmThreads from "consts:monoWasmThreads";
import { legacy_c_functions as cwraps } from "../cwraps";
import { ENVIRONMENT_IS_PTHREAD, Module, mono_assert } from "../globals";
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 { mono_wasm_new_external_root, mono_wasm_new_root } from "../roots";
import { stringToMonoStringRoot, stringToInternedMonoStringRoot, monoStringToString } from "../strings";
import { MonoMethod, MonoObject, VoidPtrNull, MarshalType, MonoString, MonoObjectNull, WasmRootBuffer, WasmRoot } from "../types/internal";
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 { legacyHelpers } from "./globals";
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";
import { mono_log_warn } from "../logging";
import { assert_js_interop } from "../invoke-js";
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();
function _create_named_function(name: string, argumentNames: string[], body: string, closure: any): Function {
let result = null;
let closureArgumentList: any[] | null = null;
let closureArgumentNames = null;
if (closure) {
closureArgumentNames = Object.keys(closure);
closureArgumentList = new Array(closureArgumentNames.length);
for (let i = 0, l = closureArgumentNames.length; i < l; i++)
closureArgumentList[i] = closure[closureArgumentNames[i]];
}
const constructor = _create_rebindable_named_function(name, argumentNames, body, closureArgumentNames);
// eslint-disable-next-line prefer-spread
result = constructor.apply(null, closureArgumentList);
return result;
}
function _create_rebindable_named_function(name: string, argumentNames: string[], body: string, closureArgNames: string[] | null): Function {
const strictPrefix = "\"use strict\";\r\n";
let uriPrefix = "", escapedFunctionIdentifier = "";
if (name) {
uriPrefix = "//# sourceURL=https://dotnet.generated.invalid/" + name + "\r\n";
escapedFunctionIdentifier = name;
} else {
escapedFunctionIdentifier = "unnamed";
}
let rawFunctionText = "function " + escapedFunctionIdentifier + "(" +
argumentNames.join(", ") +
") {\r\n" +
body +
"\r\n};\r\n";
const lineBreakRE = /\r(\n?)/g;
rawFunctionText =
uriPrefix + strictPrefix +
rawFunctionText.replace(lineBreakRE, "\r\n ") +
` return ${escapedFunctionIdentifier};\r\n`;
let result = null, keys = null;
if (closureArgNames) {
keys = closureArgNames.concat([rawFunctionText]);
} else {
keys = [rawFunctionText];
}
result = Function.apply(Function, keys);
return result;
}
export function _create_primitive_converters(): void {
const result = primitiveConverters;
result.set("m", { steps: [{}], size: 0 });
result.set("s", { steps: [{ convert_root: stringToMonoStringRoot.bind(Module) }], size: 0, needs_root: true });
result.set("S", { steps: [{ convert_root: stringToInternedMonoStringRoot.bind(Module) }], size: 0, needs_root: true });
// note we also bind first argument to false for both _js_to_mono_obj and _js_to_mono_uri,
// because we will root the reference, so we don't need in-flight reference
// also as those are callback arguments and we don't have platform code which would release the in-flight reference on C# end
result.set("o", { steps: [{ convert_root: js_to_mono_obj_root.bind(Module) }], size: 0, needs_root: true });
result.set("u", { steps: [{ convert_root: _js_to_mono_uri_root.bind(Module, false) }], size: 0, needs_root: true });
// ref object aka T&&
result.set("R", { steps: [{ convert_root: js_to_mono_obj_root.bind(Module), byref: true }], size: 0, needs_root: true });
// result.set ('k', { steps: [{ convert: js_to_mono_enum.bind (this), indirect: 'i64'}], size: 8});
result.set("j", { steps: [{ convert: js_to_mono_enum.bind(Module), indirect: "i32" }], size: 8 });
result.set("b", { steps: [{ indirect: "bool" }], size: 8 });
result.set("i", { steps: [{ indirect: "i32" }], size: 8 });
result.set("I", { steps: [{ indirect: "u32" }], size: 8 });
result.set("l", { steps: [{ indirect: "i52" }], size: 8 });
result.set("L", { steps: [{ indirect: "u52" }], size: 8 });
result.set("f", { steps: [{ indirect: "float" }], size: 8 });
result.set("d", { steps: [{ indirect: "double" }], size: 8 });
}
function _create_converter_for_marshal_string(args_marshal: string/*ArgsMarshalString*/): Converter {
const steps = [];
let size = 0;
let is_result_definitely_unmarshaled = false,
is_result_possibly_unmarshaled = false,
result_unmarshaled_if_argc = -1,
needs_root_buffer = false;
for (let i = 0; i < args_marshal.length; ++i) {
const key = args_marshal[i];
if (i === args_marshal.length - 1) {
if (key === "!") {
is_result_definitely_unmarshaled = true;
continue;
} else if (key === "m") {
is_result_possibly_unmarshaled = true;
result_unmarshaled_if_argc = args_marshal.length - 1;
}
} else if (key === "!")
throw new Error("! must be at the end of the signature");
const conv = primitiveConverters.get(key);
if (!conv)
throw new Error("Unknown parameter type " + key);
const localStep = Object.create(conv.steps[0]);
localStep.size = conv.size;
if (conv.needs_root)
needs_root_buffer = true;
localStep.needs_root = conv.needs_root;
localStep.key = key;
steps.push(localStep);
size += conv.size;
}
return {
steps, size, args_marshal,
is_result_definitely_unmarshaled,
is_result_possibly_unmarshaled,
result_unmarshaled_if_argc,
needs_root_buffer
};
}
function _get_converter_for_marshal_string(args_marshal: string/*ArgsMarshalString*/): Converter {
let converter = _signature_converters.get(args_marshal);
if (!converter) {
converter = _create_converter_for_marshal_string(args_marshal);
_signature_converters.set(args_marshal, converter);
}
return converter;
}
function _compile_converter_for_marshal_string(args_marshal: string/*ArgsMarshalString*/): Converter {
const converter = _get_converter_for_marshal_string(args_marshal);
if (typeof (converter.args_marshal) !== "string")
throw new Error("Corrupt converter for '" + args_marshal + "'");
if (converter.compiled_function && converter.compiled_variadic_function)
return converter;
const converterName = args_marshal.replace("!", "_result_unmarshaled");
converter.name = converterName;
let body = [];
let argumentNames = ["method"];
const closure: any = {
Module,
setI32,
setU32,
setF32,
setF64,
setU52,
setI52,
setB32,
setI32_unchecked,
setU32_unchecked,
scratchValueRoot: converter.scratchValueRoot,
stackAlloc: Module.stackAlloc,
_zero_region
};
let indirectLocalOffset = 0;
// ensure the indirect values are 8-byte aligned so that aligned loads and stores will work
const indirectBaseOffset = ((((args_marshal.length * 4) + 7) / 8) | 0) * 8;
// worst-case allocation size instead of allocating dynamically, plus padding
// the padding is necessary to ensure that we don't overrun the buffer due to
// the 8-byte alignment we did above
const bufferSizeBytes = converter.size + (args_marshal.length * 4) + 16;
body.push(
"if (!method) throw new Error('no method provided');",
`const buffer = stackAlloc(${bufferSizeBytes});`,
`_zero_region(buffer, ${bufferSizeBytes});`,
`const indirectStart = buffer + ${indirectBaseOffset};`,
""
);
for (let i = 0; i < converter.steps.length; i++) {
const step = converter.steps[i];
const closureKey = "step" + i;
const valueKey = "value" + i;
const argKey = "arg" + i;
const offsetText = `(indirectStart + ${indirectLocalOffset})`;
argumentNames.push(argKey);
if (step.convert_root) {
mono_assert(!step.indirect, "converter step cannot both be rooted and indirect");
if (!converter.scratchValueRoot) {
// HACK: new_external_root rightly won't accept a null address
const dummyAddress = Module.stackSave();
converter.scratchValueRoot = mono_wasm_new_external_root<MonoObject>(dummyAddress);
closure.scratchValueRoot = converter.scratchValueRoot;
}
closure[closureKey] = step.convert_root;
// Update our scratch external root to point to the indirect slot where our
// managed pointer is destined to live
body.push(`scratchValueRoot._set_address(${offsetText});`);
// Convert the object and store the managed reference through our scratch external root
body.push(`${closureKey}(${argKey}, scratchValueRoot);`);
if (step.byref) {
// for T&& we pass the address of the pointer stored on the stack
body.push(`let ${valueKey} = ${offsetText};`);
} else {
// It is safe to pass the pointer by value now since we know it is pinned
body.push(`let ${valueKey} = scratchValueRoot.value;`);
}
} else if (step.convert) {
closure[closureKey] = step.convert;
body.push(`let ${valueKey} = ${closureKey}(${argKey}, method, ${i});`);
} else {
body.push(`let ${valueKey} = ${argKey};`);
}
if (step.needs_root && !step.convert_root) {
body.push("if (!rootBuffer) throw new Error('no root buffer provided');");
body.push(`rootBuffer.set (${i}, ${valueKey});`);
}
if (step.indirect) {
switch (step.indirect) {
case "bool":
body.push(`setB32(${offsetText}, ${valueKey});`);
break;
case "u32":
body.push(`setU32(${offsetText}, ${valueKey});`);
break;
case "i32":
body.push(`setI32(${offsetText}, ${valueKey});`);
break;
case "float":
body.push(`setF32(${offsetText}, ${valueKey});`);
break;
case "double":
body.push(`setF64(${offsetText}, ${valueKey});`);
break;
case "i52":
body.push(`setI52(${offsetText}, ${valueKey});`);
break;
case "u52":
body.push(`setU52(${offsetText}, ${valueKey});`);
break;
default:
throw new Error("Unimplemented indirect type: " + step.indirect);
}
body.push(`setU32_unchecked(buffer + (${i} * 4), ${offsetText});`);
indirectLocalOffset += step.size!;
} else {
body.push(`setU32_unchecked(buffer + (${i} * 4), ${valueKey});`);
indirectLocalOffset += 4;
}
body.push("");
}
body.push("return buffer;");
let bodyJs = body.join("\r\n"), compiledFunction = null, compiledVariadicFunction = null;
try {
compiledFunction = _create_named_function("converter_" + converterName, argumentNames, bodyJs, closure);
converter.compiled_function = <ConverterFunction>compiledFunction;
} catch (exc) {
converter.compiled_function = null;
mono_log_warn("compiling converter failed for", bodyJs, "with error", exc);
throw exc;
}
argumentNames = ["method", "args"];
const variadicClosure = {
converter: compiledFunction
};
body = [
"return converter(",
" method,"
];
for (let i = 0; i < converter.steps.length; i++) {
body.push(
" args[" + i +
(
(i == converter.steps.length - 1)
? "]"
: "], "
)
);
}
body.push(");");
bodyJs = body.join("\r\n");
try {
compiledVariadicFunction = _create_named_function("variadic_converter_" + converterName, argumentNames, bodyJs, variadicClosure);
converter.compiled_variadic_function = <VariadicConverterFunction>compiledVariadicFunction;
} catch (exc) {
converter.compiled_variadic_function = null;
mono_log_warn("compiling converter failed for", bodyJs, "with error", exc);
throw exc;
}
converter.scratchRootBuffer = null;
converter.scratchBuffer = VoidPtrNull;
return converter;
}
function _maybe_produce_signature_warning(converter: Converter) {
if (converter.has_warned_about_signature)
return;
mono_log_warn("Deprecated raw return value signature: '" + converter.args_marshal + "'. End the signature with '!' instead of 'm'.");
converter.has_warned_about_signature = true;
}
export function _decide_if_result_is_marshaled(converter: Converter, argc: number): boolean {
if (!converter)
return true;
if (
converter.is_result_possibly_unmarshaled &&
(argc === converter.result_unmarshaled_if_argc)
) {
if (argc < converter.result_unmarshaled_if_argc)
throw new Error(`Expected >= ${converter.result_unmarshaled_if_argc} argument(s) but got ${argc} for signature '${converter.args_marshal}'`);
_maybe_produce_signature_warning(converter);
return false;
} else {
if (argc < converter.steps.length)
throw new Error(`Expected ${converter.steps.length} argument(s) but got ${argc} for signature '${converter.args_marshal}'`);
return !converter.is_result_definitely_unmarshaled;
}
}
export function mono_bind_method(method: MonoMethod, args_marshal: string/*ArgsMarshalString*/, has_this_arg: boolean, friendly_name?: string): Function {
assert_legacy_interop();
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);
}
// FIXME
const unbox_buffer_size = 128;
const unbox_buffer = Module._malloc(unbox_buffer_size);
const token: BoundMethodToken = {
method,
converter,
scratchRootBuffer: null,
scratchBuffer: VoidPtrNull,
scratchResultRoot: 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: cwraps.mono_wasm_try_unbox_primitive_and_get_type_ref,
_unbox_mono_obj_root_with_known_nonprimitive_type,
invoke_method_ref: cwraps.mono_wasm_invoke_method_ref,
method,
token,
unbox_buffer,
unbox_buffer_size,
getB32,
getI32,
getU32,
getF32,
getF64,
stackSave: Module.stackSave
};
const converterKey = converter ? "converter_" + converter.name : "";
if (converter)
closure[converterKey] = converter;
const argumentNames = [];
const body = [
"_create_temp_frame();",
"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 ();",
""
];
if (converter) {
body.push(
`let buffer = ${converterKey}.compiled_function(`,
" method,"
);
for (let i = 0; i < converter.steps.length; i++) {
const argName = "arg" + i;
argumentNames.push(argName);
body.push(
" " + argName +
(
(i == converter.steps.length - 1)
? ""
: ", "
)
);
}
body.push(");");
} else {
body.push("let buffer = 0;");
}
if (converter && converter.is_result_definitely_unmarshaled) {
body.push("let is_result_marshaled = false;");
} else if (converter && converter.is_result_possibly_unmarshaled) {
body.push(`let is_result_marshaled = arguments.length !== ${converter.result_unmarshaled_if_argc};`);
} else {
body.push("let is_result_marshaled = true;");
}
// We inline a bunch of the invoke and marshaling logic here in order to eliminate the GC pressure normally
// created by the unboxing part of the call process. Because unbox_mono_obj(_root) can return non-numeric
// types, v8 and spidermonkey allocate and store its result on the heap (in the nursery, to be fair).
// For a bound method however, we know the result will always be the same type because C# methods have known
// return types. Inlining the invoke and marshaling logic means that even though the bound method has logic
// for handling various types, only one path through the method (for its appropriate return type) will ever
// be taken, and the JIT will see that the 'result' local and thus the return value of this function are
// always of the exact same type. All of the branches related to this end up being predicted and low-cost.
// The end result is that bound method invocations don't always allocate, so no more nursery GCs. Yay! -kg
body.push(
"",
"",
"",
);
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;"
);
if (converter) {
if (converter.is_result_possibly_unmarshaled)
body.push("if (!is_result_marshaled) ");
if (converter.is_result_definitely_unmarshaled || converter.is_result_possibly_unmarshaled)
body.push(" result = resultPtr;");
if (!converter.is_result_definitely_unmarshaled)
body.push(
"if (is_result_marshaled) {",
// For the common scenario where the return type is a primitive, we want to try and unbox it directly
// into our existing heap allocation and then read it out of the heap. Doing this all in one operation
// means that we only need to enter a gc safe region twice (instead of 3+ times with the normal,
// slower check-type-and-then-unbox flow which has extra checks since unbox verifies the type).
" let resultType = mono_wasm_try_unbox_primitive_and_get_type_ref (resultRoot.address, unbox_buffer, unbox_buffer_size);",
" switch (resultType) {",
` case ${MarshalType.INT}:`,
" result = getI32(unbox_buffer); break;",
` case ${MarshalType.POINTER}:`, // FIXME: Is this right?
` case ${MarshalType.UINT32}:`,
" result = getU32(unbox_buffer); break;",
` case ${MarshalType.FP32}:`,
" result = getF32(unbox_buffer); break;",
` case ${MarshalType.FP64}:`,
" result = getF64(unbox_buffer); break;",
` case ${MarshalType.BOOL}:`,
" result = getB32(unbox_buffer); break;",
` case ${MarshalType.CHAR}:`,
" result = String.fromCharCode(getI32(unbox_buffer)); break;",
` case ${MarshalType.NULL}:`,
" result = null; break;",
" default:",
" result = _unbox_mono_obj_root_with_known_nonprimitive_type (resultRoot, resultType, unbox_buffer); break;",
" }",
"}"
);
} else {
throw new Error("No converter");
}
let displayName = friendly_name.replace(escapeRE, "_");
if (has_this_arg)
displayName += "_this";
body.push(
`_teardown_after_call (${converterKey}, token, buffer, resultRoot, exceptionRoot, thisArgRoot, sp);`,
"return result;"
);
const bodyJs = body.join("\r\n");
result = _create_named_function(displayName, argumentNames, bodyJs, closure);
boundMethodsByMethod.set(key, result);
return result;
}
/*
We currently don't use these types because it makes typeScript compiler very slow.
declare const enum ArgsMarshal {
Int32 = "i", // int32
Int32Enum = "j", // int32 - Enum with underlying type of int32
Int64 = "l", // int64
Int64Enum = "k", // int64 - Enum with underlying type of int64
Float32 = "f", // float
Float64 = "d", // double
String = "s", // string
Char = "s", // interned string
JSObj = "o", // js object will be converted to a C# object (this will box numbers/bool/promises)
MONOObj = "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'
type _ExtraArgsMarshalOperators = "!" | "";
export type ArgsMarshalString = ""
| `${ArgsMarshal}${_ExtraArgsMarshalOperators}`
| `${ArgsMarshal}${ArgsMarshal}${_ExtraArgsMarshalOperators}`
| `${ArgsMarshal}${ArgsMarshal}${ArgsMarshal}${_ExtraArgsMarshalOperators}`
| `${ArgsMarshal}${ArgsMarshal}${ArgsMarshal}${ArgsMarshal}${_ExtraArgsMarshalOperators}`;
*/
type ConverterStepIndirects = "u32" | "i32" | "float" | "double" | "u52" | "i52" | "reference" | "bool"
type VariadicConverterFunction = (method: MonoMethod, ...args: unknown[]) => VoidPtr;
type ConverterFunction = (method: MonoMethod /* , ... */) => VoidPtr;
export type Converter = {
steps: {
// (value: any, method: MonoMethod, arg_index: int)
convert?: boolean | Function;
// (value: any, result_root: WasmRoot<MonoObject>)
convert_root?: Function;
needs_root?: boolean;
byref?: boolean;
indirect?: ConverterStepIndirects;
size?: number;
}[];
size: number;
args_marshal?: string/*ArgsMarshalString*/;
is_result_definitely_unmarshaled?: boolean;
is_result_possibly_unmarshaled?: boolean;
result_unmarshaled_if_argc?: number;
needs_root_buffer?: boolean;
key?: string;
name?: string;
needs_root?: boolean;
compiled_variadic_function?: VariadicConverterFunction | null;
compiled_function?: ConverterFunction | null;
scratchRootBuffer?: WasmRootBuffer | null;
scratchBuffer?: VoidPtr;
scratchValueRoot?: WasmRoot<MonoObject>;
has_warned_about_signature?: boolean;
convert?: Function | null;
method?: MonoMethod | null;
}
export type BoundMethodToken = {
method: MonoMethod;
converter: Converter | null;
scratchRootBuffer: WasmRootBuffer | null;
scratchBuffer: VoidPtr;
scratchResultRoot: WasmRoot<MonoObject>;
scratchExceptionRoot: WasmRoot<MonoObject>;
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 = monoStringToString(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 : legacyHelpers._null_root.address);
}
export function assert_legacy_interop(): void {
if (MonoWasmThreads) {
mono_assert(!ENVIRONMENT_IS_PTHREAD, "Legacy interop is not supported with WebAssembly threads.");
}
assert_js_interop();
}

View file

@ -1,307 +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 { mono_wasm_get_jsobj_from_js_handle } from "../gc-handles";
import { Module, INTERNAL, loaderHelpers } from "../globals";
import { wrap_error_root, wrap_no_error_root } from "../invoke-js";
import { _release_temp_frame } from "../memory";
import { mono_wasm_new_external_root, mono_wasm_new_root } from "../roots";
import { find_entry_point } from "../run";
import { monoStringToString, stringToMonoStringRoot } from "../strings";
import { JSHandle, MonoStringRef, MonoObjectRef, MonoArray, MonoString, MonoObject, is_nullish, WasmRoot } from "../types/internal";
import { Int32Ptr, VoidPtr } from "../types/emscripten";
import { mono_array_root_to_js_array, unbox_mono_obj_root } from "./cs-to-js";
import { js_array_to_mono_array, js_to_mono_obj_root } from "./js-to-cs";
import { Converter, BoundMethodToken, mono_method_resolve, mono_method_get_call_signature_ref, mono_bind_method, assert_legacy_interop } from "./method-binding";
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>,
thisArgRoot: WasmRoot<MonoObject>,
sp: VoidPtr
): void {
_release_temp_frame();
Module.stackRestore(sp);
if (typeof (resultRoot) === "object") {
resultRoot.clear();
if ((token !== null) && (token.scratchResultRoot === null))
token.scratchResultRoot = resultRoot;
else
resultRoot.release();
}
if (typeof (exceptionRoot) === "object") {
exceptionRoot.clear();
if ((token !== null) && (token.scratchExceptionRoot === null))
token.scratchExceptionRoot = exceptionRoot;
else
exceptionRoot.release();
}
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 {
assert_legacy_interop();
const key = `${fqn}-${signature}`;
let js_method = boundMethodsByFqn.get(key);
if (js_method === undefined) {
const method = mono_method_resolve(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 {
assert_legacy_interop();
const method = find_entry_point(assembly);
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[]) {
loaderHelpers.assert_runtime_running();
if (args.length > 0 && Array.isArray(args[0]))
args[0] = js_array_to_mono_array(args[0], true, false);
return js_method(...args);
};
}
export function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: string/*ArgsMarshalString*/): number {
assert_legacy_interop();
if (!args) {
args = [[]];
}
return mono_bind_assembly_entry_point(assembly, signature)(...args);
}
export function mono_wasm_invoke_js_with_args_ref(js_handle: JSHandle, method_name: MonoStringRef, args: MonoObjectRef, is_exception: Int32Ptr, result_address: MonoObjectRef): any {
assert_legacy_interop();
const argsRoot = mono_wasm_new_external_root<MonoArray>(args),
nameRoot = mono_wasm_new_external_root<MonoString>(method_name),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
const js_name = monoStringToString(nameRoot);
if (!js_name || (typeof (js_name) !== "string")) {
wrap_error_root(is_exception, "ERR12: Invalid method name object @" + nameRoot.value, resultRoot);
return;
}
const obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
if (is_nullish(obj)) {
wrap_error_root(is_exception, "ERR13: Invalid JS object handle '" + js_handle + "' while invoking '" + js_name + "'", resultRoot);
return;
}
const js_args = mono_array_root_to_js_array(argsRoot);
try {
const m = obj[js_name];
if (typeof m === "undefined")
throw new Error("Method: '" + js_name + "' not found for: '" + Object.prototype.toString.call(obj) + "'");
const res = m.apply(obj, js_args);
js_to_mono_obj_root(res, resultRoot, true);
wrap_no_error_root(is_exception);
} catch (ex) {
wrap_error_root(is_exception, ex, resultRoot);
}
} finally {
argsRoot.release();
nameRoot.release();
resultRoot.release();
}
}
export function mono_wasm_get_object_property_ref(js_handle: JSHandle, property_name: MonoStringRef, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
assert_legacy_interop();
const nameRoot = mono_wasm_new_external_root<MonoString>(property_name),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
const js_name = monoStringToString(nameRoot);
if (!js_name) {
wrap_error_root(is_exception, "Invalid property name object '" + nameRoot.value + "'", resultRoot);
return;
}
const obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
if (is_nullish(obj)) {
wrap_error_root(is_exception, "ERR01: Invalid JS object handle '" + js_handle + "' while geting '" + js_name + "'", resultRoot);
return;
}
const m = obj[js_name];
js_to_mono_obj_root(m, resultRoot, true);
wrap_no_error_root(is_exception);
} catch (ex) {
wrap_error_root(is_exception, ex, resultRoot);
} finally {
resultRoot.release();
nameRoot.release();
}
}
export function mono_wasm_set_object_property_ref(js_handle: JSHandle, property_name: MonoStringRef, value: MonoObjectRef, createIfNotExist: boolean, hasOwnProperty: boolean, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
assert_legacy_interop();
const valueRoot = mono_wasm_new_external_root<MonoObject>(value),
nameRoot = mono_wasm_new_external_root<MonoString>(property_name),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
const property = monoStringToString(nameRoot);
if (!property) {
wrap_error_root(is_exception, "Invalid property name object '" + property_name + "'", resultRoot);
return;
}
const js_obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
if (is_nullish(js_obj)) {
wrap_error_root(is_exception, "ERR02: Invalid JS object handle '" + js_handle + "' while setting '" + property + "'", resultRoot);
return;
}
const js_value = unbox_mono_obj_root(valueRoot);
if (createIfNotExist) {
js_obj[property] = js_value;
}
else {
if (!createIfNotExist) {
if (!Object.prototype.hasOwnProperty.call(js_obj, property)) {
return;
}
}
if (hasOwnProperty === true) {
if (Object.prototype.hasOwnProperty.call(js_obj, property)) {
js_obj[property] = js_value;
}
}
else {
js_obj[property] = js_value;
}
}
wrap_no_error_root(is_exception, resultRoot);
} catch (ex) {
wrap_error_root(is_exception, ex, resultRoot);
} finally {
resultRoot.release();
nameRoot.release();
valueRoot.release();
}
}
export function mono_wasm_get_by_index_ref(js_handle: JSHandle, property_index: number, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
assert_legacy_interop();
const resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
const obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
if (is_nullish(obj)) {
wrap_error_root(is_exception, "ERR03: Invalid JS object handle '" + js_handle + "' while getting [" + property_index + "]", resultRoot);
return;
}
const m = obj[property_index];
js_to_mono_obj_root(m, resultRoot, true);
wrap_no_error_root(is_exception);
} catch (ex) {
wrap_error_root(is_exception, ex, resultRoot);
} finally {
resultRoot.release();
}
}
export function mono_wasm_set_by_index_ref(js_handle: JSHandle, property_index: number, value: MonoObjectRef, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
assert_legacy_interop();
const valueRoot = mono_wasm_new_external_root<MonoObject>(value),
resultRoot = mono_wasm_new_external_root<MonoObject>(result_address);
try {
const obj = mono_wasm_get_jsobj_from_js_handle(js_handle);
if (is_nullish(obj)) {
wrap_error_root(is_exception, "ERR04: Invalid JS object handle '" + js_handle + "' while setting [" + property_index + "]", resultRoot);
return;
}
const js_value = unbox_mono_obj_root(valueRoot);
obj[property_index] = js_value;
wrap_no_error_root(is_exception, resultRoot);
} catch (ex) {
wrap_error_root(is_exception, ex, resultRoot);
} finally {
resultRoot.release();
valueRoot.release();
}
}
export function mono_wasm_get_global_object_ref(global_name: MonoStringRef, is_exception: Int32Ptr, result_address: MonoObjectRef): void {
assert_legacy_interop();
const nameRoot = mono_wasm_new_external_root<MonoString>(global_name),
resultRoot = mono_wasm_new_external_root(result_address);
try {
const js_name = monoStringToString(nameRoot);
let globalObj;
if (!js_name) {
globalObj = globalThis;
}
else if (js_name == "Module") {
globalObj = Module;
}
else if (js_name == "INTERNAL") {
globalObj = INTERNAL;
}
else {
globalObj = (<any>globalThis)[js_name];
}
// TODO returning null may be useful when probing for browser features
if (globalObj === null || typeof globalObj === undefined) {
wrap_error_root(is_exception, "Global object '" + js_name + "' not found.", resultRoot);
return;
}
js_to_mono_obj_root(globalObj, resultRoot, true);
wrap_no_error_root(is_exception);
} catch (ex) {
wrap_error_root(is_exception, ex, resultRoot);
} finally {
resultRoot.release();
nameRoot.release();
}
}
// Blazor specific custom routine
export function mono_wasm_invoke_js_blazor(exceptionMessage: Int32Ptr, callInfo: any, arg0: any, arg1: any, arg2: any): void | number {
try {
assert_legacy_interop();
const blazorExports = (<any>globalThis).Blazor;
if (!blazorExports) {
throw new Error("The blazor.webassembly.js library is not loaded.");
}
return blazorExports._internal.invokeJSFromDotNet(callInfo, arg0, arg1, arg2);
} catch (ex: any) {
const exceptionJsString = ex.message + "\n" + ex.stack;
const exceptionRoot = mono_wasm_new_root<MonoString>();
stringToMonoStringRoot(exceptionJsString, exceptionRoot);
exceptionRoot.copy_to_address(<any>exceptionMessage);
exceptionRoot.release();
return 0;
}
}

View file

@ -1,40 +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 { mono_assert } from "../globals";
import { mono_wasm_new_root } from "../roots";
import { interned_string_table, mono_wasm_empty_string, stringToInternedMonoStringRoot, stringToMonoStringRoot } from "../strings";
import { MonoString, is_nullish } from "../types/internal";
import { assert_legacy_interop } from "./method-binding";
/**
* @deprecated Not GC or thread safe
*/
export function stringToMonoStringUnsafe(string: string): MonoString {
assert_legacy_interop();
const temp = mono_wasm_new_root<MonoString>();
try {
stringToMonoStringRoot(string, temp);
return temp.value;
} finally {
temp.release();
}
}
// this is only used in legacy unit tests
export function stringToMonoStringIntern(string: string): string {
if (string.length === 0)
return mono_wasm_empty_string;
const root = mono_wasm_new_root<MonoString>();
try {
stringToInternedMonoStringRoot(string, root);
const result = interned_string_table.get(root.value);
mono_assert(!is_nullish(result), "internal error: interned_string_table did not contain string after stringToMonoStringIntern");
return result;
}
finally {
root.release();
}
}

View file

@ -22,11 +22,10 @@ const wasmObjDir = process.env.WasmObjDir ? process.env.WasmObjDir.replace(/"/g,
const monoWasmThreads = process.env.MonoWasmThreads === "true" ? true : false;
const wasmEnableSIMD = process.env.WASM_ENABLE_SIMD === "1" ? true : false;
const wasmEnableExceptionHandling = process.env.WASM_ENABLE_EH === "1" ? true : false;
const wasmEnableLegacyJsInterop = process.env.DISABLE_LEGACY_JS_INTEROP !== "1" ? true : false;
const wasmEnableJsInteropByValue = process.env.ENABLE_JS_INTEROP_BY_VALUE == "1" ? true : false;
const monoDiagnosticsMock = process.env.MonoDiagnosticsMock === "true" ? true : false;
// because of stack walk at src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
// and unit test at src\libraries\System.Runtime.InteropServices.JavaScript\tests\System.Runtime.InteropServices.JavaScript.Legacy.UnitTests\timers.mjs
// and unit test at with timers.mjs
const keep_fnames = /(mono_wasm_runtime_ready|mono_wasm_fire_debugger_agent_message_with_data|mono_wasm_fire_debugger_agent_message_with_data_to_pause|mono_wasm_schedule_timer_tick)/;
const keep_classnames = /(ManagedObject|ManagedError|Span|ArraySegment|WasmRootBuffer|SessionOptionsBuilder)/;
const terserConfig = {
@ -103,7 +102,6 @@ const envConstants = {
wasmEnableExceptionHandling,
monoDiagnosticsMock,
gitHash,
wasmEnableLegacyJsInterop,
wasmEnableJsInteropByValue,
isContinuousIntegrationBuild,
};
@ -215,20 +213,6 @@ const typesConfig = {
external: externalDependencies,
plugins: [dts()],
};
const legacyTypesConfig = {
input: "./net6-legacy/export-types.ts",
output: [
{
format: "es",
file: nativeBinDir + "/dotnet-legacy.d.ts",
banner: banner_dts,
plugins: [writeOnChangePlugin()],
}
],
external: externalDependencies,
plugins: [dts()],
};
let diagnosticMockTypesConfig = undefined;
@ -241,12 +225,6 @@ if (isDebug) {
banner: banner_dts,
plugins: [alwaysLF(), writeOnChangePlugin()],
});
legacyTypesConfig.output.push({
format: "es",
file: "./dotnet-legacy.d.ts",
banner: banner_dts,
plugins: [alwaysLF(), writeOnChangePlugin()],
});
// export types into the source code and commit to git
diagnosticMockTypesConfig = {
@ -289,7 +267,6 @@ const allConfigs = [
runtimeConfig,
wasmImportsConfig,
typesConfig,
legacyTypesConfig,
].concat(workerConfigs)
.concat(diagnosticMockTypesConfig ? [diagnosticMockTypesConfig] : []);
export default defineConfig(allConfigs);

View file

@ -2,10 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
import MonoWasmThreads from "consts:monoWasmThreads";
import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";
import { DotnetModuleInternal, CharPtrNull } from "./types/internal";
import { linkerDisableLegacyJsInterop, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_NODE, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, createPromiseController, mono_assert, linkerWasmEnableSIMD, linkerWasmEnableEH, ENVIRONMENT_IS_WORKER } from "./globals";
import { ENVIRONMENT_IS_NODE, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, createPromiseController, mono_assert, linkerWasmEnableSIMD, linkerWasmEnableEH, ENVIRONMENT_IS_WORKER } from "./globals";
import cwraps, { init_c_exports, threads_c_functions as tcwraps } from "./cwraps";
import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug";
import { toBase64StringImpl } from "./base64";
@ -30,11 +29,6 @@ import { preAllocatePThreadWorkerPool, instantiateWasmPThreadWorkerPool } from "
import { currentWorkerThreadEvents, dotnetPthreadCreated, initWorkerThreadEvents } from "./pthreads/worker";
import { mono_wasm_main_thread_ptr } from "./pthreads/shared";
import { jiterpreter_allocate_tables } from "./jiterpreter-support";
// legacy
import { init_legacy_exports } from "./net6-legacy/corebindings";
import { cwraps_binding_api, cwraps_mono_api } from "./net6-legacy/exports-legacy";
import { BINDING, MONO } from "./net6-legacy/globals";
import { localHeapViewU8 } from "./memory";
import { assertNoProxies } from "./gc-handles";
@ -382,10 +376,6 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void {
init_c_exports();
cwraps_internal(INTERNAL);
if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop) {
cwraps_mono_api(MONO);
cwraps_binding_api(BINDING);
}
// removeRunDependency triggers the dependenciesFulfilled callback (runCaller) in
// emscripten - on a worker since we don't have any other dependencies that causes run() to get
// called too soon; and then it will get called a second time when dotnet.native.js calls it directly.
@ -409,24 +399,6 @@ async function mono_wasm_pre_init_essential_async(): Promise<void> {
async function mono_wasm_after_user_runtime_initialized(): Promise<void> {
mono_log_debug("mono_wasm_after_user_runtime_initialized");
try {
if (!Module.disableDotnet6Compatibility && Module.exports) {
// Export emscripten defined in module through EXPORTED_RUNTIME_METHODS
// Useful to export IDBFS or other similar types generally exposed as
// global types when emscripten is not modularized.
const globalThisAny = globalThis as any;
for (let i = 0; i < Module.exports.length; ++i) {
const exportName = Module.exports[i];
const exportValue = (<any>Module)[exportName];
if (exportValue != undefined) {
globalThisAny[exportName] = exportValue;
}
else {
mono_log_warn(`The exported symbol ${exportName} could not be found in the emscripten module`);
}
}
}
mono_log_debug("Initializing mono runtime");
if (Module.onDotnetReady) {
@ -606,9 +578,6 @@ export function bindings_init(): void {
const mark = startMeasure();
strings_init();
init_managed_exports();
if (WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop && !ENVIRONMENT_IS_PTHREAD) {
init_legacy_exports();
}
initialize_marshalers_to_js();
initialize_marshalers_to_cs();
runtimeHelpers._i52_error_scratch_buffer = <any>Module._malloc(4);

View file

@ -16,7 +16,6 @@
},
"exclude": [
"dotnet.d.ts",
"dotnet-legacy.d.ts",
"diagnostics-mock.d.ts",
"bin"
]

View file

@ -23,25 +23,6 @@ export declare interface CharPtrPtr extends NativePointer {
}
export declare interface EmscriptenModule {
/** @deprecated Please use localHeapViewI8() instead.*/
HEAP8: Int8Array,
/** @deprecated Please use localHeapViewI16() instead.*/
HEAP16: Int16Array;
/** @deprecated Please use localHeapViewI32() instead. */
HEAP32: Int32Array;
/** @deprecated Please use localHeapViewI64() instead. */
HEAP64: BigInt64Array;
/** @deprecated Please use localHeapViewU8() instead. */
HEAPU8: Uint8Array;
/** @deprecated Please use localHeapViewU16() instead. */
HEAPU16: Uint16Array;
/** @deprecated Please use localHeapViewU32() instead */
HEAPU32: Uint32Array;
/** @deprecated Please use localHeapViewF32() instead */
HEAPF32: Float32Array;
/** @deprecated Please use localHeapViewF64() instead. */
HEAPF64: Float64Array;
// this should match emcc -s EXPORTED_FUNCTIONS
_malloc(size: number): VoidPtr;
_free(ptr: VoidPtr): void;

View file

@ -329,8 +329,6 @@ export const enum GlobalizationMode {
}
export type DotnetModuleConfig = {
disableDotnet6Compatibility?: boolean,
config?: MonoConfig,
configSrc?: string,
onConfigLoaded?: (config: MonoConfig) => void | Promise<void>;
@ -387,14 +385,6 @@ export type APIType = {
}
export type RuntimeAPI = {
/**
* @deprecated Please use API object instead. See also MONOType in dotnet-legacy.d.ts
*/
MONO: any,
/**
* @deprecated Please use API object instead. See also BINDINGType in dotnet-legacy.d.ts
*/
BINDING: any,
INTERNAL: any,
Module: EmscriptenModule,
runtimeId: number,

View file

@ -284,7 +284,6 @@ export function is_nullish<T>(value: T | null | undefined): value is null | unde
export type EmscriptenInternals = {
isPThread: boolean,
linkerDisableLegacyJsInterop: boolean,
linkerWasmEnableSIMD: boolean,
linkerWasmEnableEH: boolean,
linkerEnableAotProfiler: boolean,
@ -453,6 +452,16 @@ export interface WasmRootBuffer {
}
export declare interface EmscriptenModuleInternal {
HEAP8: Int8Array,
HEAP16: Int16Array;
HEAP32: Int32Array;
HEAP64: BigInt64Array;
HEAPU8: Uint8Array;
HEAPU16: Uint16Array;
HEAPU32: Uint32Array;
HEAPF32: Float32Array;
HEAPF64: Float64Array;
__locateFile?: (path: string, prefix?: string) => string;
locateFile?: (path: string, prefix?: string) => string;
mainScriptUrlOrBlob?: string;

View file

@ -7,9 +7,6 @@
/* Support for threads is disabled */
#cmakedefine DISABLE_THREADS
/* Support for legacy JS interop is disabled */
#cmakedefine DISABLE_LEGACY_JS_INTEROP
/* Support for JS interop without pointers to managed objects */
#cmakedefine ENABLE_JS_INTEROP_BY_VALUE

View file

@ -45,7 +45,6 @@
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'browser-wasm' and '$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
<!-- Keep in sync with WasmApp.Native.targets -->
<_WasmPropertiesDifferFromRuntimePackThusNativeBuildNeeded Condition="
'$(WasmEnableLegacyJsInterop)' == 'false' or
'$(WasmEnableSIMD)' == 'false' or
'$(WasmEnableExceptionHandling)' == 'false' or
'$(InvariantTimezone)' == 'true' or

View file

@ -4,7 +4,6 @@
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
<PublishTrimmed>true</PublishTrimmed>
<InvariantTimezone>true</InvariantTimezone>
<WasmEnableLegacyJsInterop>false</WasmEnableLegacyJsInterop>
<WasmEnableWebcil>false</WasmEnableWebcil>
<WasmEmitSymbolMap>true</WasmEmitSymbolMap>
<EmccEnableAssertions>true</EmccEnableAssertions>

View file

@ -25,9 +25,7 @@ namespace Sample
public JSInteropTask()
{
measurements = new Measurement[] {
new LegacyExportIntMeasurement(),
new JSExportIntMeasurement(),
new LegacyExportStringMeasurement(),
new JSExportStringMeasurement(),
new JSImportIntMeasurement(),
new JSImportStringMeasurement(),
@ -38,18 +36,6 @@ namespace Sample
};
}
public class LegacyExportIntMeasurement : BenchTask.Measurement
{
public override int InitialSamples => 3;
public override string Name => "LegacyExportInt";
// because of the aggressive trimming of methods reachable via JS legacy bind_static_method
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "Sample.ImportsExportsHelper", Test.AssemblyName)]
public override void RunStep()
{
ImportsExportsHelper.RunLegacyExportInt(10000);
}
}
public class JSExportIntMeasurement : BenchTask.Measurement
{
public override int InitialSamples => 10;
@ -60,19 +46,6 @@ namespace Sample
}
}
public class LegacyExportStringMeasurement : BenchTask.Measurement
{
public override int InitialSamples => 3;
public override string Name => "LegacyExportString";
// because of the aggressive trimming of methods reachable via JS legacy bind_static_method
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "Sample.ImportsExportsHelper", Test.AssemblyName)]
public override void RunStep()
{
ImportsExportsHelper.RunLegacyExportString(10000);
}
}
public class JSExportStringMeasurement : BenchTask.Measurement
{
public override int InitialSamples => 3;
@ -187,15 +160,9 @@ namespace Sample
partial class ImportsExportsHelper
{
[JSImport("Sample.Test.runLegacyExportInt", "main.js")]
public static partial void RunLegacyExportInt(int count);
[JSImport("Sample.Test.runJSExportInt", "main.js")]
public static partial void RunJSExportInt(int count);
[JSImport("Sample.Test.runLegacyExportString", "main.js")]
public static partial void RunLegacyExportString(int count);
[JSImport("Sample.Test.runJSExportString", "main.js")]
public static partial void RunJSExportString(int count);
@ -211,12 +178,6 @@ namespace Sample
[JSImport("Sample.Test.importTargetThrows", "main.js")]
public static partial void ImportTargetThrows(int value);
[MethodImpl(MethodImplOptions.NoInlining)]
public static int LegacyExportTargetInt(int value)
{
return value + 1;
}
[JSImport("Sample.Test.importTargetManyArgs", "main.js")]
public static partial double ImportTargetManyArgs(int arg1, int arg2, string arg3, string arg4, IntPtr arg5, bool arg6,
[JSMarshalAs<JSType.Number>] long arg7, int? arg8, double arg9,
@ -229,12 +190,6 @@ namespace Sample
return value + 1;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static string LegacyExportTargetString(string value)
{
return value + "A";
}
[JSExport]
public static string JSExportTargetString(string value)
{

View file

@ -9,30 +9,16 @@ let runBenchmark;
let setTasks;
let setExclusions;
let getFullJsonResults;
let legacyExportTargetInt;
let jsExportTargetInt;
let legacyExportTargetString;
let jsExportTargetString;
let _jiterpreter_dump_stats, _interp_pgo_save_data;
function runLegacyExportInt(count) {
for (let i = 0; i < count; i++) {
legacyExportTargetInt(i);
}
}
function runJSExportInt(count) {
for (let i = 0; i < count; i++) {
jsExportTargetInt(i);
}
}
function runLegacyExportString(count) {
for (let i = 0; i < count; i++) {
legacyExportTargetString("A" + i);
}
}
function runJSExportString(count) {
for (let i = 0; i < count; i++) {
jsExportTargetString("A" + i);
@ -61,7 +47,7 @@ function importTargetThrows(value) {
}
class MainApp {
async init({ getAssemblyExports, setModuleImports, BINDING, INTERNAL }) {
async init({ getAssemblyExports, setModuleImports, INTERNAL }) {
const exports = await getAssemblyExports("Wasm.Browser.Bench.Sample.dll");
// Capture these two internal APIs for use at the end of the benchmark run
_jiterpreter_dump_stats = INTERNAL.jiterpreter_dump_stats.bind(INTERNAL);
@ -71,17 +57,13 @@ class MainApp {
setExclusions = exports.Sample.Test.SetExclusions;
getFullJsonResults = exports.Sample.Test.GetFullJsonResults;
legacyExportTargetInt = BINDING.bind_static_method("[Wasm.Browser.Bench.Sample]Sample.ImportsExportsHelper:LegacyExportTargetInt");
jsExportTargetInt = exports.Sample.ImportsExportsHelper.JSExportTargetInt;
legacyExportTargetString = BINDING.bind_static_method("[Wasm.Browser.Bench.Sample]Sample.ImportsExportsHelper:LegacyExportTargetString");
jsExportTargetString = exports.Sample.ImportsExportsHelper.JSExportTargetString;
setModuleImports("main.js", {
Sample: {
Test: {
runLegacyExportInt,
runJSExportInt,
runLegacyExportString,
runJSExportString,
importTargetInt,
importTargetString,

View file

@ -15,7 +15,6 @@
$(WasmAppDir)/dotnet.native.js;
$(WasmAppDir)/dotnet.native.wasm;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet.d.ts;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet-legacy.d.ts;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/package.json;" Outputs="bin/dotnet-runtime/.npm-stamp">
<ItemGroup>
<NpmPackageFiles Include="$(WasmAppDir)/dotnet.js"/>
@ -23,7 +22,6 @@
<NpmPackageFiles Include="$(WasmAppDir)/dotnet.native.js"/>
<NpmPackageFiles Include="$(WasmAppDir)/dotnet.native.wasm"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet.d.ts"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet-legacy.d.ts"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/package.json"/>
</ItemGroup>
<Copy SourceFiles="@(NpmPackageFiles)" DestinationFolder="bin/dotnet-runtime" />

View file

@ -9,11 +9,9 @@
-->
<Target Name="CopyRelinkedPackage" AfterTargets="WasmBuildApp" DependsOnTargets="Build" Inputs="
$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet.d.ts;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet-legacy.d.ts;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/package.json;" Outputs="bin/$(Configuration)/AppBundle/.npm-stamp">
<ItemGroup>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet.d.ts"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet-legacy.d.ts"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/package.json"/>
</ItemGroup>
<Copy SourceFiles="@(NpmPackageFiles)" DestinationFolder="bin/$(Configuration)/AppBundle" SkipUnchangedFiles="true"/>

View file

@ -9,7 +9,6 @@
$(WasmAppDir)/_framework/dotnet.native.js;
$(WasmAppDir)/_framework/dotnet.native.wasm;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet.d.ts;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet-legacy.d.ts;
$(MicrosoftNetCoreAppRuntimePackNativeDir)/package.json;" Outputs="bin/dotnet-runtime/.npm-stamp">
<ItemGroup>
<NpmPackageFiles Include="$(WasmAppDir)/_framework/dotnet.js"/>
@ -17,7 +16,6 @@
<NpmPackageFiles Include="$(WasmAppDir)/_framework/dotnet.native.js"/>
<NpmPackageFiles Include="$(WasmAppDir)/_framework/dotnet.native.wasm"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet.d.ts"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/dotnet-legacy.d.ts"/>
<NpmPackageFiles Include="$(MicrosoftNetCoreAppRuntimePackNativeDir)/package.json"/>
</ItemGroup>
<Copy SourceFiles="@(NpmPackageFiles)" DestinationFolder="bin/dotnet-runtime" />

View file

@ -22,7 +22,6 @@ public class WorkloadRequiredTests : BlazorWasmTestBase
public static (string propertyName, bool triggerValue)[] PropertiesWithTriggerValues = new[]
{
("RunAOTCompilation", true),
("WasmEnableLegacyJsInterop", false),
("WasmEnableSIMD", false),
("WasmEnableExceptionHandling", false),
("InvariantTimezone", true),

View file

@ -23,7 +23,6 @@ namespace Wasm.Build.Tests
{
List<(string propertyName, bool defaultValueInRuntimePack)> defaults = new()
{
("WasmEnableLegacyJsInterop", true),
("WasmEnableSIMD", true),
("WasmEnableExceptionHandling", true),
("InvariantTimezone", false),
@ -128,10 +127,10 @@ namespace Wasm.Build.Tests
public static TheoryData<string, string, bool, bool> SetWasmNativeStripExplicitlyWithWasmBuildNativeTestData() => new()
{
{ "Debug", "<WasmNativeStrip>false</WasmNativeStrip><WasmEnableLegacyJsInterop>false</WasmEnableLegacyJsInterop>", true, false },
{ "Release", "<WasmNativeStrip>false</WasmNativeStrip><WasmEnableLegacyJsInterop>false</WasmEnableLegacyJsInterop>", true, false },
{ "Debug", "<WasmNativeStrip>true</WasmNativeStrip><WasmEnableLegacyJsInterop>false</WasmEnableLegacyJsInterop>", true, true },
{ "Release", "<WasmNativeStrip>true</WasmNativeStrip><WasmEnableLegacyJsInterop>false</WasmEnableLegacyJsInterop>", true, true }
{ "Debug", "<WasmNativeStrip>false</WasmNativeStrip><InvariantTimezone>true</InvariantTimezone>", true, false },
{ "Release", "<WasmNativeStrip>false</WasmNativeStrip><InvariantTimezone>true</InvariantTimezone>", true, false },
{ "Debug", "<WasmNativeStrip>true</WasmNativeStrip><InvariantTimezone>true</InvariantTimezone>", true, true },
{ "Release", "<WasmNativeStrip>true</WasmNativeStrip><InvariantTimezone>true</InvariantTimezone>", true, true }
};
[Theory]

View file

@ -32,8 +32,6 @@ Implementation:
- *after* any of the wasm build targets, use `AfterTargets="WasmBuildApp"` on that target
- Avoid depending on this target, because it is available only when the workload is installed. Use `$(WasmNativeWorkload)` to check if it is installed.
- When `Module.disableDotnet6Compatibility` is set it would not pollute global namespace.
## `Publish`
Implementation:

View file

@ -68,7 +68,6 @@
- $(RunAOTCompilationAfterBuild) - Run AOT compilation even after Build. By default, it is run only for publish.
Defaults to false.
- $(WasmAotProfilePath) - Path to an AOT profile file.
- $(WasmEnableLegacyJsInterop) - Include support for legacy JS interop. Defaults to true.
- $(WasmEnableExceptionHandling) - Enable support for the WASM post MVP Exception Handling runtime extension.
- $(WasmEnableSIMD) - Enable support for the WASM post MVP SIMD runtime extension.
- $(WasmEnableWebcil) - Enable conversion of assembly .dlls to Webcil wrapped in .wasm (default: true)

View file

@ -220,51 +220,29 @@ let mono_exit = (code, reason) => {
};
const App = {
/** Runs a particular test in legacy interop tests
* @type {(method_name: string, args: any[]=, signature: any=) => return number}
*/
call_test_method: function (method_name, args, signature) {
// note: arguments here is the array of arguments passsed to this function
if ((arguments.length > 2) && (typeof (signature) !== "string"))
throw new Error("Invalid number of arguments for call_test_method");
const fqn = "[System.Runtime.InteropServices.JavaScript.Legacy.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:" + method_name;
try {
const method = App.runtime.BINDING.bind_static_method(fqn, signature);
return method.apply(null, args || []);
} catch (exc) {
console.error("exception thrown in", fqn);
throw exc;
}
},
create_function(...args) {
const code = args.pop();
const arg_count = args.length;
args.push("MONO");
args.push("BINDING");
args.push("INTERNAL");
const userFunction = new Function(...args, code);
return function (...args) {
args[arg_count + 0] = globalThis.App.runtime.MONO;
args[arg_count + 1] = globalThis.App.runtime.BINDING;
args[arg_count + 2] = globalThis.App.runtime.INTERNAL;
args[arg_count] = globalThis.App.runtime.INTERNAL;
return userFunction(...args);
};
},
invoke_js(js_code) {
const closedEval = function (Module, MONO, BINDING, INTERNAL, code) {
const closedEval = function (Module, INTERNAL, code) {
return eval(code);
};
const res = closedEval(globalThis.App.runtime.Module, globalThis.App.runtime.MONO, globalThis.App.runtime.BINDING, globalThis.App.runtime.INTERNAL, js_code);
const res = closedEval(globalThis.App.runtime.Module, globalThis.App.runtime.INTERNAL, js_code);
return (res === undefined || res === null || typeof res === "string")
? null
: res.toString();
}
};
globalThis.App = App; // Necessary as System.Runtime.InteropServices.JavaScript.Tests.MarshalTests (among others) call the App.call_test_method directly
globalThis.App = App; // Necessary as tests use it
function configureRuntime(dotnet, runArgs) {
dotnet