forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathJSFunctionBinding.cs
226 lines (201 loc) · 9.58 KB
/
JSFunctionBinding.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
namespace System.Runtime.InteropServices.JavaScript
{
/// <summary>
/// Represents a bound imported or exported JavaScript function and contains information necessary to invoke it.
/// This API supports JSImport infrastructure and is not intended to be used directly from your code.
/// </summary>
[CLSCompliant(false)]
[SupportedOSPlatform("browser")]
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class JSFunctionBinding
{
/// <summary>
/// This API supports JSImport infrastructure and is not intended to be used directly from your code.
/// </summary>
internal JSFunctionBinding() { }
#region intentionally opaque internal structure
internal unsafe JSBindingHeader* Header;
internal unsafe JSBindingType* Sigs;// points to first arg, not exception, not result
internal IntPtr FnHandle;
[StructLayout(LayoutKind.Sequential, Pack = 4)]
internal struct JSBindingHeader
{
internal const int JSMarshalerSignatureHeaderSize = 4 + 4; // without Exception and Result
public int Version;
public int ArgumentCount;
public JSBindingType Exception;
public JSBindingType Result;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 32)]
internal struct JSBindingType
{
internal MarshalerType Type;
internal IntPtr __Reserved;
internal IntPtr JSCustomMarshallerCode;
internal int JSCustomMarshallerCodeLength;
internal MarshalerType ResultMarshalerType;
internal MarshalerType Arg1MarshalerType;
internal MarshalerType Arg2MarshalerType;
internal MarshalerType Arg3MarshalerType;
}
internal unsafe int ArgumentCount
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return Header[0].ArgumentCount;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
Header[0].ArgumentCount = value;
}
}
internal unsafe int Version
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return Header[0].Version;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
Header[0].Version = value;
}
}
internal unsafe JSBindingType Result
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return Header[0].Result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
Header[0].Result = value;
}
}
internal unsafe JSBindingType Exception
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return Header[0].Exception;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
Header[0].Exception = value;
}
}
// one based position of args, not exception, not result
internal unsafe JSBindingType this[int position]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return Sigs[position - 1];
}
}
#endregion
/// <summary>
/// Invokes a previously bound JavaScript function using the provided span to transport argument and return values.
/// This API supports JSImport infrastructure and is not intended to be used directly from your code.
/// </summary>
/// <param name="signature">Generated metadata about the method signature used for marshaling.</param>
/// <param name="arguments">The intermediate buffer with marshalled arguments.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeJS(JSFunctionBinding signature, Span<JSMarshalerArgument> arguments)
{
InvokeImportImpl(signature.FnHandle, arguments);
}
/// <summary>
/// Locates and binds a JavaScript function given name and module so that it can later be invoked by managed callers.
/// This API supports JSImport infrastructure and is not intended to be used directly from your code.
/// </summary>
/// <param name="functionName">The name of the exported JavaScript function.</param>
/// <param name="moduleName">The name of the ES6 module.</param>
/// <param name="signatures">The metadata about the signature of the marshaled parameters.</param>
/// <returns>The method metadata.</returns>
/// <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")]
// TODO make this DynamicDependency conditional
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, "System.Runtime.InteropServices.JavaScript.LegacyExports", "System.Runtime.InteropServices.JavaScript")]
public static JSFunctionBinding BindJSFunction(string functionName, string moduleName, ReadOnlySpan<JSMarshalerType> signatures)
{
if (RuntimeInformation.OSArchitecture != Architecture.Wasm)
throw new PlatformNotSupportedException();
return BindJSFunctionImpl(functionName, moduleName, signatures);
}
/// <summary>
/// Binds a specific managed function wrapper so that it can later be invoked by JavaScript callers.
/// This API supports JSImport infrastructure and is not intended to be used directly from your code.
/// </summary>
/// <param name="fullyQualifiedName">The fully qualified name of the exported method.</param>
/// <param name="signatureHash">The hash of the signature metadata.</param>
/// <param name="signatures">The metadata about the signature of the marshaled parameters.</param>
/// <returns>The method metadata.</returns>
/// <exception cref="PlatformNotSupportedException">The method is executed on architecture other than WebAssembly.</exception>
public static JSFunctionBinding BindManagedFunction(string fullyQualifiedName, int signatureHash, ReadOnlySpan<JSMarshalerType> signatures)
{
if (RuntimeInformation.OSArchitecture != Architecture.Wasm)
throw new PlatformNotSupportedException();
return BindManagedFunctionImpl(fullyQualifiedName, signatureHash, signatures);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void InvokeJSImpl(JSObject jsFunction, Span<JSMarshalerArgument> arguments)
{
IntPtr functionJSHandle = jsFunction.JSHandle;
fixed (JSMarshalerArgument* ptr = arguments)
{
Interop.Runtime.InvokeJSFunction(functionJSHandle, ptr);
ref JSMarshalerArgument exceptionArg = ref arguments[0];
if (exceptionArg.slot.Type != MarshalerType.None)
{
JSHostImplementation.ThrowException(ref exceptionArg);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void InvokeImportImpl(IntPtr fnHandle, Span<JSMarshalerArgument> arguments)
{
fixed (JSMarshalerArgument* ptr = arguments)
{
Interop.Runtime.InvokeImport(fnHandle, ptr);
ref JSMarshalerArgument exceptionArg = ref arguments[0];
if (exceptionArg.slot.Type != MarshalerType.None)
{
JSHostImplementation.ThrowException(ref exceptionArg);
}
}
}
internal static unsafe JSFunctionBinding BindJSFunctionImpl(string functionName, string moduleName, ReadOnlySpan<JSMarshalerType> signatures)
{
var signature = JSHostImplementation.GetMethodSignature(signatures);
Interop.Runtime.BindJSFunction(functionName, moduleName, signature.Header, out IntPtr jsFunctionHandle, out int isException, out object exceptionMessage);
if (isException != 0)
throw new JSException((string)exceptionMessage);
signature.FnHandle = jsFunctionHandle;
return signature;
}
internal static unsafe JSFunctionBinding BindManagedFunctionImpl(string fullyQualifiedName, int signatureHash, ReadOnlySpan<JSMarshalerType> signatures)
{
var signature = JSHostImplementation.GetMethodSignature(signatures);
Interop.Runtime.BindCSFunction(fullyQualifiedName, signatureHash, signature.Header, out int isException, out object exceptionMessage);
if (isException != 0)
{
throw new JSException((string)exceptionMessage);
}
return signature;
}
}
}