Skip to content

Commit 1b423c3

Browse files
authored
Extract various changes from the invoke and custom marshaler PRs (#60877)
Various code cleanup and refactorings for the wasm bindings
1 parent 966ca29 commit 1b423c3

13 files changed

Lines changed: 786 additions & 244 deletions

File tree

src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ public static partial class Runtime
1212
private const string TaskGetResultName = "get_Result";
1313
private static readonly MethodInfo _taskGetResultMethodInfo = typeof(Task<>).GetMethod(TaskGetResultName)!;
1414

15-
// <summary>
16-
// Execute the provided string in the JavaScript context
17-
// </summary>
18-
// <returns>The js.</returns>
19-
// <param name="str">String.</param>
15+
/// <summary>
16+
/// Execute the provided string in the JavaScript context
17+
/// </summary>
18+
/// <returns>The js.</returns>
19+
/// <param name="str">String.</param>
2020
public static string InvokeJS(string str)
2121
{
2222
return Interop.Runtime.InvokeJS(str);
@@ -50,6 +50,52 @@ private struct IntPtrAndHandle
5050

5151
[FieldOffset(0)]
5252
internal RuntimeMethodHandle handle;
53+
54+
[FieldOffset(0)]
55+
internal RuntimeTypeHandle typeHandle;
56+
}
57+
58+
// see src/mono/wasm/driver.c MARSHAL_TYPE_xxx
59+
public enum MarshalType : int {
60+
NULL = 0,
61+
INT = 1,
62+
FP64 = 2,
63+
STRING = 3,
64+
VT = 4,
65+
DELEGATE = 5,
66+
TASK = 6,
67+
OBJECT = 7,
68+
BOOL = 8,
69+
ENUM = 9,
70+
URI = 22,
71+
SAFEHANDLE = 23,
72+
ARRAY_BYTE = 10,
73+
ARRAY_UBYTE = 11,
74+
ARRAY_UBYTE_C = 12,
75+
ARRAY_SHORT = 13,
76+
ARRAY_USHORT = 14,
77+
ARRAY_INT = 15,
78+
ARRAY_UINT = 16,
79+
ARRAY_FLOAT = 17,
80+
ARRAY_DOUBLE = 18,
81+
FP32 = 24,
82+
UINT32 = 25,
83+
INT64 = 26,
84+
UINT64 = 27,
85+
CHAR = 28,
86+
STRING_INTERNED = 29,
87+
VOID = 30,
88+
ENUM64 = 31,
89+
POINTER = 32
90+
}
91+
92+
// see src/mono/wasm/driver.c MARSHAL_ERROR_xxx
93+
public enum MarshalError : int {
94+
BUFFER_TOO_SMALL = 512,
95+
NULL_CLASS_POINTER = 513,
96+
NULL_TYPE_POINTER = 514,
97+
UNSUPPORTED_TYPE = 515,
98+
FIRST = BUFFER_TOO_SMALL
5399
}
54100

55101
public static string GetCallSignature(IntPtr methodHandle, object objForRuntimeType)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { MonoAssembly, MonoClass, MonoType, MonoTypeNull, MonoAssemblyNull } from "./types";
2+
import cwraps from "./cwraps";
3+
4+
const _assembly_cache_by_name = new Map<string, MonoAssembly>();
5+
const _class_cache_by_assembly = new Map<MonoAssembly, Map<string, Map<string, MonoClass>>>();
6+
let _corlib : MonoAssembly = MonoAssemblyNull;
7+
8+
export function assembly_load (name : string) : MonoAssembly {
9+
if (_assembly_cache_by_name.has(name))
10+
return <MonoAssembly>_assembly_cache_by_name.get(name);
11+
12+
const result = cwraps.mono_wasm_assembly_load(name);
13+
_assembly_cache_by_name.set(name, result);
14+
return result;
15+
}
16+
17+
function _find_cached_class (assembly : MonoAssembly, namespace : string, name : string) : MonoClass | undefined {
18+
let namespaces = _class_cache_by_assembly.get(assembly);
19+
if (!namespaces)
20+
_class_cache_by_assembly.set(assembly, namespaces = new Map());
21+
22+
let classes = namespaces.get(namespace);
23+
if (!classes) {
24+
classes = new Map<string, MonoClass>();
25+
namespaces.set(namespace, classes);
26+
}
27+
28+
return classes.get(name);
29+
}
30+
31+
function _set_cached_class (assembly : MonoAssembly, namespace : string, name : string, ptr : MonoClass) {
32+
const namespaces = _class_cache_by_assembly.get(assembly);
33+
if (!namespaces)
34+
throw new Error("internal error");
35+
const classes = namespaces.get(namespace);
36+
if (!classes)
37+
throw new Error("internal error");
38+
classes.set(name, ptr);
39+
}
40+
41+
export function find_corlib_class (namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoClass {
42+
if (!_corlib)
43+
_corlib = cwraps.mono_wasm_get_corlib();
44+
let result = _find_cached_class (_corlib, namespace, name);
45+
if (result !== undefined)
46+
return result;
47+
result = cwraps.mono_wasm_assembly_find_class(_corlib, namespace, name);
48+
if (throw_on_failure && !result)
49+
throw new Error(`Failed to find corlib class ${namespace}.${name}`);
50+
_set_cached_class(_corlib, namespace, name, result);
51+
return result;
52+
}
53+
54+
export function find_class_in_assembly (assembly_name : string, namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoClass {
55+
const assembly = cwraps.mono_wasm_assembly_load(assembly_name);
56+
let result = _find_cached_class(assembly, namespace, name);
57+
if (result !== undefined)
58+
return result;
59+
result = cwraps.mono_wasm_assembly_find_class(assembly, namespace, name);
60+
if (throw_on_failure && !result)
61+
throw new Error(`Failed to find class ${namespace}.${name} in ${assembly_name}`);
62+
_set_cached_class(assembly, namespace, name, result);
63+
return result;
64+
}
65+
66+
export function find_corlib_type (namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoType {
67+
const classPtr = find_corlib_class(namespace, name, throw_on_failure);
68+
if (!classPtr)
69+
return MonoTypeNull;
70+
return cwraps.mono_wasm_class_get_type(classPtr);
71+
}
72+
73+
export function find_type_in_assembly (assembly_name : string, namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoType {
74+
const classPtr = find_class_in_assembly(assembly_name, namespace, name, throw_on_failure);
75+
if (!classPtr)
76+
return MonoTypeNull;
77+
return cwraps.mono_wasm_class_get_type(classPtr);
78+
}

src/mono/wasm/runtime/cs-to-js.ts

Lines changed: 106 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
import { mono_wasm_new_root, WasmRoot } from "./roots";
55
import {
6-
GCHandle, Int32Ptr, JSHandleDisposed, MonoArray,
7-
MonoArrayNull, MonoObject, MonoObjectNull, MonoString
6+
GCHandle, Int32Ptr, JSHandle, JSHandleDisposed, MonoArray,
7+
MonoArrayNull, MonoObject, MonoObjectNull, MonoString, MonoClass,
8+
MonoClassNull, MonoType, MonoTypeNull
89
} from "./types";
910
import { Module, runtimeHelpers } from "./modules";
1011
import { conv_string } from "./strings";
@@ -15,6 +16,49 @@ import { mono_method_get_call_signature, call_method, wrap_error } from "./metho
1516
import { _js_to_mono_obj } from "./js-to-cs";
1617
import { _are_promises_supported, _create_cancelable_promise } from "./cancelable-promise";
1718

19+
// see src/mono/wasm/driver.c MARSHAL_TYPE_xxx and Runtime.cs MarshalType
20+
export enum MarshalType {
21+
NULL = 0,
22+
INT = 1,
23+
FP64 = 2,
24+
STRING = 3,
25+
VT = 4,
26+
DELEGATE = 5,
27+
TASK = 6,
28+
OBJECT = 7,
29+
BOOL = 8,
30+
ENUM = 9,
31+
URI = 22,
32+
SAFEHANDLE = 23,
33+
ARRAY_BYTE = 10,
34+
ARRAY_UBYTE = 11,
35+
ARRAY_UBYTE_C = 12,
36+
ARRAY_SHORT = 13,
37+
ARRAY_USHORT = 14,
38+
ARRAY_INT = 15,
39+
ARRAY_UINT = 16,
40+
ARRAY_FLOAT = 17,
41+
ARRAY_DOUBLE = 18,
42+
FP32 = 24,
43+
UINT32 = 25,
44+
INT64 = 26,
45+
UINT64 = 27,
46+
CHAR = 28,
47+
STRING_INTERNED = 29,
48+
VOID = 30,
49+
ENUM64 = 31,
50+
POINTER = 32
51+
}
52+
53+
// see src/mono/wasm/driver.c MARSHAL_ERROR_xxx and Runtime.cs
54+
export enum MarshalError {
55+
BUFFER_TOO_SMALL = 512,
56+
NULL_CLASS_POINTER = 513,
57+
NULL_TYPE_POINTER = 514,
58+
UNSUPPORTED_TYPE = 515,
59+
FIRST = BUFFER_TOO_SMALL
60+
}
61+
1862
const delegate_invoke_symbol = Symbol.for("wasm delegate_invoke");
1963
const delegate_invoke_signature_symbol = Symbol.for("wasm delegate_invoke_signature");
2064

@@ -38,72 +82,89 @@ function _unbox_cs_owned_root_as_js_object(root: WasmRoot<any>) {
3882
return js_obj;
3983
}
4084

41-
export function _unbox_mono_obj_root_with_known_nonprimitive_type(root: WasmRoot<any>, type: number): any {
42-
if (root.value === undefined)
43-
throw new Error(`Expected a root but got ${root}`);
44-
85+
function _unbox_mono_obj_root_with_known_nonprimitive_type_impl(root: WasmRoot<any>, type: MarshalType, typePtr: MonoType, unbox_buffer: VoidPtr) : any {
4586
//See MARSHAL_TYPE_ defines in driver.c
4687
switch (type) {
47-
case 26: // int64
48-
case 27: // uint64
88+
case MarshalType.INT64:
89+
case MarshalType.UINT64:
4990
// TODO: Fix this once emscripten offers HEAPI64/HEAPU64 or can return them
5091
throw new Error("int64 not available");
51-
case 3: // string
52-
case 29: // interned string
92+
case MarshalType.STRING:
93+
case MarshalType.STRING_INTERNED:
5394
return conv_string(root.value);
54-
case 4: //vts
95+
case MarshalType.VT:
5596
throw new Error("no idea on how to unbox value types");
56-
case 5: // delegate
97+
case MarshalType.DELEGATE:
5798
return _wrap_delegate_root_as_function(root);
58-
case 6: // Task
99+
case MarshalType.TASK:
59100
return _unbox_task_root_as_promise(root);
60-
case 7: // ref type
101+
case MarshalType.OBJECT:
61102
return _unbox_ref_type_root_as_js_object(root);
62-
case 10: // arrays
63-
case 11:
64-
case 12:
65-
case 13:
66-
case 14:
67-
case 15:
68-
case 16:
69-
case 17:
70-
case 18:
103+
case MarshalType.ARRAY_BYTE:
104+
case MarshalType.ARRAY_UBYTE:
105+
case MarshalType.ARRAY_UBYTE_C:
106+
case MarshalType.ARRAY_SHORT:
107+
case MarshalType.ARRAY_USHORT:
108+
case MarshalType.ARRAY_INT:
109+
case MarshalType.ARRAY_UINT:
110+
case MarshalType.ARRAY_FLOAT:
111+
case MarshalType.ARRAY_DOUBLE:
71112
throw new Error("Marshalling of primitive arrays are not supported. Use the corresponding TypedArray instead.");
72-
case 20: // clr .NET DateTime
113+
case <MarshalType>20: // clr .NET DateTime
73114
return new Date(corebindings._get_date_value(root.value));
74-
case 21: // clr .NET DateTimeOffset
115+
case <MarshalType>21: // clr .NET DateTimeOffset
75116
return corebindings._object_to_string(root.value);
76-
case 22: // clr .NET Uri
117+
case MarshalType.URI:
77118
return corebindings._object_to_string(root.value);
78-
case 23: // clr .NET SafeHandle/JSObject
119+
case MarshalType.SAFEHANDLE:
79120
return _unbox_cs_owned_root_as_js_object(root);
80-
case 30:
121+
case MarshalType.VOID:
81122
return undefined;
82123
default:
83-
throw new Error(`no idea on how to unbox object kind ${type} at offset ${root.value} (root address is ${root.get_address()})`);
124+
throw new Error(`no idea on how to unbox object of MarshalType ${type} at offset ${root.value} (root address is ${root.get_address()})`);
125+
}
126+
}
127+
128+
export function _unbox_mono_obj_root_with_known_nonprimitive_type(root: WasmRoot<any>, type: MarshalType, unbox_buffer: VoidPtr) : any {
129+
if (type >= MarshalError.FIRST)
130+
throw new Error(`Got marshaling error ${type} when attempting to unbox object at address ${root.value} (root located at ${root.get_address()})`);
131+
132+
let typePtr = MonoTypeNull;
133+
if ((type === MarshalType.VT) || (type == MarshalType.OBJECT)) {
134+
typePtr = <MonoType><any>Module.HEAPU32[<any>unbox_buffer >>> 2];
135+
if (<number><any>typePtr < 1024)
136+
throw new Error(`Got invalid MonoType ${typePtr} for object at address ${root.value} (root located at ${root.get_address()})`);
84137
}
138+
139+
return _unbox_mono_obj_root_with_known_nonprimitive_type_impl(root, type, typePtr, unbox_buffer);
85140
}
86141

87-
export function _unbox_mono_obj_root(root: WasmRoot<any>): any {
142+
export function _unbox_mono_obj_root(root: WasmRoot<any>) : any {
88143
if (root.value === 0)
89144
return undefined;
90145

91-
const type = cwraps.mono_wasm_try_unbox_primitive_and_get_type(root.value, runtimeHelpers._unbox_buffer);
146+
const unbox_buffer = runtimeHelpers._unbox_buffer;
147+
const type = cwraps.mono_wasm_try_unbox_primitive_and_get_type(root.value, unbox_buffer, runtimeHelpers._unbox_buffer_size);
92148
switch (type) {
93-
case 1: // int
94-
return Module.HEAP32[<any>runtimeHelpers._unbox_buffer / 4];
95-
case 25: // uint32
96-
return Module.HEAPU32[<any>runtimeHelpers._unbox_buffer / 4];
97-
case 24: // float32
98-
return Module.HEAPF32[<any>runtimeHelpers._unbox_buffer / 4];
99-
case 2: // float64
100-
return Module.HEAPF64[<any>runtimeHelpers._unbox_buffer / 8];
101-
case 8: // boolean
102-
return (Module.HEAP32[<any>runtimeHelpers._unbox_buffer / 4]) !== 0;
103-
case 28: // char
104-
return String.fromCharCode(Module.HEAP32[<any>runtimeHelpers._unbox_buffer / 4]);
149+
case MarshalType.INT:
150+
return Module.HEAP32[<any>unbox_buffer >>> 2];
151+
case MarshalType.UINT32:
152+
return Module.HEAPU32[<any>unbox_buffer >>> 2];
153+
case MarshalType.POINTER:
154+
// FIXME: Is this right?
155+
return Module.HEAPU32[<any>unbox_buffer >>> 2];
156+
case MarshalType.FP32:
157+
return Module.HEAPF32[<any>unbox_buffer >>> 2];
158+
case MarshalType.FP64:
159+
return Module.HEAPF64[<any>unbox_buffer >>> 3];
160+
case MarshalType.BOOL:
161+
return (Module.HEAP32[<any>unbox_buffer >>> 2]) !== 0;
162+
case MarshalType.CHAR:
163+
return String.fromCharCode(Module.HEAP32[<any>unbox_buffer >>> 2]);
164+
case MarshalType.NULL:
165+
return null;
105166
default:
106-
return _unbox_mono_obj_root_with_known_nonprimitive_type(root, type);
167+
return _unbox_mono_obj_root_with_known_nonprimitive_type(root, type, unbox_buffer);
107168
}
108169
}
109170

@@ -289,7 +350,7 @@ function _unbox_task_root_as_promise(root: WasmRoot<MonoObject>) {
289350
return result;
290351
}
291352

292-
function _unbox_ref_type_root_as_js_object(root: WasmRoot<MonoObject>) {
353+
export function _unbox_ref_type_root_as_js_object(root: WasmRoot<MonoObject>) {
293354

294355
if (root.value === MonoObjectNull)
295356
return null;

0 commit comments

Comments
 (0)