diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs
index 60e6e4d4df676a..60f694e2b7cf39 100644
--- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs
+++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Runtime.cs
@@ -12,11 +12,11 @@ public static partial class Runtime
private const string TaskGetResultName = "get_Result";
private static readonly MethodInfo _taskGetResultMethodInfo = typeof(Task<>).GetMethod(TaskGetResultName)!;
- //
- // Execute the provided string in the JavaScript context
- //
- // The js.
- // String.
+ ///
+ /// Execute the provided string in the JavaScript context
+ ///
+ /// The js.
+ /// String.
public static string InvokeJS(string str)
{
return Interop.Runtime.InvokeJS(str);
@@ -50,6 +50,52 @@ private struct IntPtrAndHandle
[FieldOffset(0)]
internal RuntimeMethodHandle handle;
+
+ [FieldOffset(0)]
+ internal RuntimeTypeHandle typeHandle;
+ }
+
+ // 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
}
public static string GetCallSignature(IntPtr methodHandle, object objForRuntimeType)
diff --git a/src/mono/wasm/runtime/class-loader.ts b/src/mono/wasm/runtime/class-loader.ts
new file mode 100644
index 00000000000000..63581a8e6b1369
--- /dev/null
+++ b/src/mono/wasm/runtime/class-loader.ts
@@ -0,0 +1,78 @@
+import { MonoAssembly, MonoClass, MonoType, MonoTypeNull, MonoAssemblyNull } from "./types";
+import cwraps from "./cwraps";
+
+const _assembly_cache_by_name = new Map();
+const _class_cache_by_assembly = new Map>>();
+let _corlib : MonoAssembly = MonoAssemblyNull;
+
+export function assembly_load (name : string) : MonoAssembly {
+ if (_assembly_cache_by_name.has(name))
+ return _assembly_cache_by_name.get(name);
+
+ const result = cwraps.mono_wasm_assembly_load(name);
+ _assembly_cache_by_name.set(name, result);
+ return result;
+}
+
+function _find_cached_class (assembly : MonoAssembly, namespace : string, name : string) : MonoClass | undefined {
+ let namespaces = _class_cache_by_assembly.get(assembly);
+ if (!namespaces)
+ _class_cache_by_assembly.set(assembly, namespaces = new Map());
+
+ let classes = namespaces.get(namespace);
+ if (!classes) {
+ classes = new Map();
+ namespaces.set(namespace, classes);
+ }
+
+ return classes.get(name);
+}
+
+function _set_cached_class (assembly : MonoAssembly, namespace : string, name : string, ptr : MonoClass) {
+ const namespaces = _class_cache_by_assembly.get(assembly);
+ if (!namespaces)
+ throw new Error("internal error");
+ const classes = namespaces.get(namespace);
+ if (!classes)
+ throw new Error("internal error");
+ classes.set(name, ptr);
+}
+
+export function find_corlib_class (namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoClass {
+ if (!_corlib)
+ _corlib = cwraps.mono_wasm_get_corlib();
+ let result = _find_cached_class (_corlib, namespace, name);
+ if (result !== undefined)
+ return result;
+ result = cwraps.mono_wasm_assembly_find_class(_corlib, namespace, name);
+ if (throw_on_failure && !result)
+ throw new Error(`Failed to find corlib class ${namespace}.${name}`);
+ _set_cached_class(_corlib, namespace, name, result);
+ return result;
+}
+
+export function find_class_in_assembly (assembly_name : string, namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoClass {
+ const assembly = cwraps.mono_wasm_assembly_load(assembly_name);
+ let result = _find_cached_class(assembly, namespace, name);
+ if (result !== undefined)
+ return result;
+ result = cwraps.mono_wasm_assembly_find_class(assembly, namespace, name);
+ if (throw_on_failure && !result)
+ throw new Error(`Failed to find class ${namespace}.${name} in ${assembly_name}`);
+ _set_cached_class(assembly, namespace, name, result);
+ return result;
+}
+
+export function find_corlib_type (namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoType {
+ const classPtr = find_corlib_class(namespace, name, throw_on_failure);
+ if (!classPtr)
+ return MonoTypeNull;
+ return cwraps.mono_wasm_class_get_type(classPtr);
+}
+
+export function find_type_in_assembly (assembly_name : string, namespace : string, name : string, throw_on_failure? : boolean | undefined) : MonoType {
+ const classPtr = find_class_in_assembly(assembly_name, namespace, name, throw_on_failure);
+ if (!classPtr)
+ return MonoTypeNull;
+ return cwraps.mono_wasm_class_get_type(classPtr);
+}
diff --git a/src/mono/wasm/runtime/cs-to-js.ts b/src/mono/wasm/runtime/cs-to-js.ts
index 749961621cb982..2a81c822c1d018 100644
--- a/src/mono/wasm/runtime/cs-to-js.ts
+++ b/src/mono/wasm/runtime/cs-to-js.ts
@@ -3,8 +3,9 @@
import { mono_wasm_new_root, WasmRoot } from "./roots";
import {
- GCHandle, Int32Ptr, JSHandleDisposed, MonoArray,
- MonoArrayNull, MonoObject, MonoObjectNull, MonoString
+ GCHandle, Int32Ptr, JSHandle, JSHandleDisposed, MonoArray,
+ MonoArrayNull, MonoObject, MonoObjectNull, MonoString, MonoClass,
+ MonoClassNull, MonoType, MonoTypeNull
} from "./types";
import { Module, runtimeHelpers } from "./modules";
import { conv_string } from "./strings";
@@ -15,6 +16,49 @@ import { mono_method_get_call_signature, call_method, wrap_error } from "./metho
import { _js_to_mono_obj } from "./js-to-cs";
import { _are_promises_supported, _create_cancelable_promise } from "./cancelable-promise";
+// see src/mono/wasm/driver.c MARSHAL_TYPE_xxx and Runtime.cs MarshalType
+export enum MarshalType {
+ 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 and Runtime.cs
+export enum MarshalError {
+ BUFFER_TOO_SMALL = 512,
+ NULL_CLASS_POINTER = 513,
+ NULL_TYPE_POINTER = 514,
+ UNSUPPORTED_TYPE = 515,
+ FIRST = BUFFER_TOO_SMALL
+}
+
const delegate_invoke_symbol = Symbol.for("wasm delegate_invoke");
const delegate_invoke_signature_symbol = Symbol.for("wasm delegate_invoke_signature");
@@ -38,72 +82,89 @@ function _unbox_cs_owned_root_as_js_object(root: WasmRoot) {
return js_obj;
}
-export function _unbox_mono_obj_root_with_known_nonprimitive_type(root: WasmRoot, type: number): any {
- if (root.value === undefined)
- throw new Error(`Expected a root but got ${root}`);
-
+function _unbox_mono_obj_root_with_known_nonprimitive_type_impl(root: WasmRoot, type: MarshalType, typePtr: MonoType, unbox_buffer: VoidPtr) : any {
//See MARSHAL_TYPE_ defines in driver.c
switch (type) {
- case 26: // int64
- case 27: // uint64
+ 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 3: // string
- case 29: // interned string
+ case MarshalType.STRING:
+ case MarshalType.STRING_INTERNED:
return conv_string(root.value);
- case 4: //vts
+ case MarshalType.VT:
throw new Error("no idea on how to unbox value types");
- case 5: // delegate
+ case MarshalType.DELEGATE:
return _wrap_delegate_root_as_function(root);
- case 6: // Task
+ case MarshalType.TASK:
return _unbox_task_root_as_promise(root);
- case 7: // ref type
+ case MarshalType.OBJECT:
return _unbox_ref_type_root_as_js_object(root);
- case 10: // arrays
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- case 18:
+ 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("Marshalling of primitive arrays are not supported. Use the corresponding TypedArray instead.");
- case 20: // clr .NET DateTime
+ case 20: // clr .NET DateTime
return new Date(corebindings._get_date_value(root.value));
- case 21: // clr .NET DateTimeOffset
+ case 21: // clr .NET DateTimeOffset
return corebindings._object_to_string(root.value);
- case 22: // clr .NET Uri
+ case MarshalType.URI:
return corebindings._object_to_string(root.value);
- case 23: // clr .NET SafeHandle/JSObject
+ case MarshalType.SAFEHANDLE:
return _unbox_cs_owned_root_as_js_object(root);
- case 30:
+ case MarshalType.VOID:
return undefined;
default:
- throw new Error(`no idea on how to unbox object kind ${type} at offset ${root.value} (root address is ${root.get_address()})`);
+ throw new Error(`no idea on how to unbox object of MarshalType ${type} at offset ${root.value} (root address is ${root.get_address()})`);
+ }
+}
+
+export function _unbox_mono_obj_root_with_known_nonprimitive_type(root: WasmRoot, 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.get_address()})`);
+
+ let typePtr = MonoTypeNull;
+ if ((type === MarshalType.VT) || (type == MarshalType.OBJECT)) {
+ typePtr = Module.HEAPU32[unbox_buffer >>> 2];
+ if (typePtr < 1024)
+ throw new Error(`Got invalid MonoType ${typePtr} for object at address ${root.value} (root located at ${root.get_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 {
+export function _unbox_mono_obj_root(root: WasmRoot) : any {
if (root.value === 0)
return undefined;
- const type = cwraps.mono_wasm_try_unbox_primitive_and_get_type(root.value, runtimeHelpers._unbox_buffer);
+ const unbox_buffer = runtimeHelpers._unbox_buffer;
+ const type = cwraps.mono_wasm_try_unbox_primitive_and_get_type(root.value, unbox_buffer, runtimeHelpers._unbox_buffer_size);
switch (type) {
- case 1: // int
- return Module.HEAP32[runtimeHelpers._unbox_buffer / 4];
- case 25: // uint32
- return Module.HEAPU32[runtimeHelpers._unbox_buffer / 4];
- case 24: // float32
- return Module.HEAPF32[runtimeHelpers._unbox_buffer / 4];
- case 2: // float64
- return Module.HEAPF64[runtimeHelpers._unbox_buffer / 8];
- case 8: // boolean
- return (Module.HEAP32[runtimeHelpers._unbox_buffer / 4]) !== 0;
- case 28: // char
- return String.fromCharCode(Module.HEAP32[runtimeHelpers._unbox_buffer / 4]);
+ case MarshalType.INT:
+ return Module.HEAP32[unbox_buffer >>> 2];
+ case MarshalType.UINT32:
+ return Module.HEAPU32[unbox_buffer >>> 2];
+ case MarshalType.POINTER:
+ // FIXME: Is this right?
+ return Module.HEAPU32[unbox_buffer >>> 2];
+ case MarshalType.FP32:
+ return Module.HEAPF32[unbox_buffer >>> 2];
+ case MarshalType.FP64:
+ return Module.HEAPF64[unbox_buffer >>> 3];
+ case MarshalType.BOOL:
+ return (Module.HEAP32[unbox_buffer >>> 2]) !== 0;
+ case MarshalType.CHAR:
+ return String.fromCharCode(Module.HEAP32[unbox_buffer >>> 2]);
+ case MarshalType.NULL:
+ return null;
default:
- return _unbox_mono_obj_root_with_known_nonprimitive_type(root, type);
+ return _unbox_mono_obj_root_with_known_nonprimitive_type(root, type, unbox_buffer);
}
}
@@ -289,7 +350,7 @@ function _unbox_task_root_as_promise(root: WasmRoot) {
return result;
}
-function _unbox_ref_type_root_as_js_object(root: WasmRoot) {
+export function _unbox_ref_type_root_as_js_object(root: WasmRoot) {
if (root.value === MonoObjectNull)
return null;
diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts
index adda829a587a57..723cb2ecc09260 100644
--- a/src/mono/wasm/runtime/cwraps.ts
+++ b/src/mono/wasm/runtime/cwraps.ts
@@ -1,7 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import { CharPtr, CharPtrPtr, Int32Ptr, MonoArray, MonoAssembly, MonoClass, MonoMethod, MonoObject, MonoString, VoidPtr } from "./types";
+import {
+ CharPtr, CharPtrPtr, Int32Ptr,
+ MonoArray, MonoAssembly, MonoClass,
+ MonoMethod, MonoObject, MonoString,
+ MonoType, VoidPtr
+} from "./types";
import { Module } from "./modules";
const fn_signatures: [ident: string, returnType: string | null, argTypes?: string[], opts?: any][] = [
@@ -25,9 +30,12 @@ const fn_signatures: [ident: string, returnType: string | null, argTypes?: strin
["mono_wasm_exit", null, ["number"]],
// BINDING
+ ["mono_wasm_get_corlib", "number", []],
["mono_wasm_assembly_load", "number", ["string"]],
["mono_wasm_find_corlib_class", "number", ["string", "string"]],
["mono_wasm_assembly_find_class", "number", ["number", "string", "string"]],
+ ["mono_wasm_find_corlib_type", "number", ["string", "string"]],
+ ["mono_wasm_assembly_find_type", "number", ["number", "string", "string"]],
["mono_wasm_assembly_find_method", "number", ["number", "string", "number"]],
["mono_wasm_invoke_method", "number", ["number", "number", "number", "number"]],
["mono_wasm_string_get_utf8", "number", ["number"]],
@@ -38,13 +46,18 @@ const fn_signatures: [ident: string, returnType: string | null, argTypes?: strin
["mono_wasm_obj_array_new", "number", ["number"]],
["mono_wasm_obj_array_set", "void", ["number", "number", "number"]],
["mono_wasm_register_bundled_satellite_assemblies", "void", []],
- ["mono_wasm_try_unbox_primitive_and_get_type", "number", ["number", "number"]],
+ ["mono_wasm_try_unbox_primitive_and_get_type", "number", ["number", "number", "number"]],
["mono_wasm_box_primitive", "number", ["number", "number", "number"]],
["mono_wasm_intern_string", "number", ["number"]],
["mono_wasm_assembly_get_entry_point", "number", ["number"]],
["mono_wasm_get_delegate_invoke", "number", ["number"]],
["mono_wasm_string_array_new", "number", ["number"]],
["mono_wasm_typed_array_new", "number", ["number", "number", "number", "number"]],
+ ["mono_wasm_class_get_type", "number", ["number"]],
+ ["mono_wasm_type_get_class", "number", ["number"]],
+ ["mono_wasm_get_type_name", 'string', ['number']],
+ ["mono_wasm_get_type_aqn", 'string', ['number']],
+ ["mono_wasm_unbox_rooted", "number", ["number"]],
//DOTNET
["mono_wasm_string_from_js", "number", ["string"]],
@@ -77,9 +90,12 @@ export interface t_Cwraps {
mono_wasm_load_runtime(unused: string, debug_level: number): void;
// BINDING
- mono_wasm_assembly_load(name: string): MonoAssembly
- mono_wasm_find_corlib_class(namespace: string, name: string): MonoClass
+ mono_wasm_get_corlib(): MonoAssembly;
+ mono_wasm_assembly_load(name: string): MonoAssembly;
+ mono_wasm_find_corlib_class(namespace: string, name: string): MonoClass;
mono_wasm_assembly_find_class(assembly: MonoAssembly, namespace: string, name: string): MonoClass;
+ mono_wasm_find_corlib_type(namespace: string, name: string): MonoType;
+ mono_wasm_assembly_find_type(assembly: MonoAssembly, namespace: string, name: string): MonoType;
mono_wasm_assembly_find_method(klass: MonoClass, name: string, args: number): MonoMethod;
mono_wasm_invoke_method(method: MonoMethod, this_arg: MonoObject, params: VoidPtr, out_exc: MonoObject): MonoObject;
mono_wasm_string_get_utf8(str: MonoString): CharPtr;
@@ -90,17 +106,22 @@ export interface t_Cwraps {
mono_wasm_obj_array_new(size: number): MonoArray;
mono_wasm_obj_array_set(array: MonoArray, idx: number, obj: MonoObject): void;
mono_wasm_register_bundled_satellite_assemblies(): void;
- mono_wasm_try_unbox_primitive_and_get_type(obj: MonoObject, result: VoidPtr): number;
+ mono_wasm_try_unbox_primitive_and_get_type(obj: MonoObject, buffer: VoidPtr, buffer_size: number): number;
mono_wasm_box_primitive(klass: MonoClass, value: VoidPtr, value_size: number): MonoObject;
- mono_wasm_intern_string(str: MonoString): MonoString
- mono_wasm_assembly_get_entry_point(assembly: MonoAssembly): MonoMethod
- mono_wasm_get_delegate_invoke(delegate: MonoObject): MonoMethod
+ mono_wasm_intern_string(str: MonoString): MonoString;
+ mono_wasm_assembly_get_entry_point(assembly: MonoAssembly): MonoMethod;
+ mono_wasm_get_delegate_invoke(delegate: MonoObject): MonoMethod;
mono_wasm_string_array_new(size: number): MonoArray;
mono_wasm_typed_array_new(arr: VoidPtr, length: number, size: number, type: number): MonoArray;
+ mono_wasm_class_get_type(klass: MonoClass): MonoType;
+ mono_wasm_type_get_class(ty: MonoType): MonoClass;
+ mono_wasm_get_type_name(ty: MonoType): string;
+ mono_wasm_get_type_aqn(ty: MonoType): string;
+ mono_wasm_unbox_rooted(obj: MonoObject): VoidPtr;
//DOTNET
- mono_wasm_string_from_js(str: string): MonoString
-
+ mono_wasm_string_from_js(str: string): MonoString;
+
//INTERNAL
mono_wasm_exit(exit_code: number): number;
mono_wasm_enable_on_demand_gc(enable: number): void;
diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c
index 45186acdbb76b0..e62d6428426249 100644
--- a/src/mono/wasm/runtime/driver.c
+++ b/src/mono/wasm/runtime/driver.c
@@ -38,6 +38,8 @@ extern void* mono_wasm_invoke_js_unmarshalled (MonoString **exceptionMessage, Mo
void mono_wasm_enable_debugging (int);
+int mono_wasm_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType *type);
+
int mono_wasm_register_root (char *start, size_t size, const char *name);
void mono_wasm_deregister_root (char *addr);
@@ -54,6 +56,46 @@ void mono_free (void*);
int32_t mini_parse_debug_option (const char *option);
char *mono_method_get_full_name (MonoMethod *method);
+#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 marshalling
+#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;
@@ -611,10 +653,9 @@ mono_wasm_load_runtime (const char *unused, int debug_level)
EMSCRIPTEN_KEEPALIVE MonoAssembly*
mono_wasm_assembly_load (const char *name)
{
+ assert (name);
MonoImageOpenStatus status;
MonoAssemblyName* aname = mono_assembly_name_new (name);
- if (!name)
- return NULL;
MonoAssembly *res = mono_assembly_load (aname, NULL, &status);
mono_assembly_name_free (aname);
@@ -622,21 +663,23 @@ mono_wasm_assembly_load (const char *name)
return res;
}
-EMSCRIPTEN_KEEPALIVE MonoClass*
-mono_wasm_find_corlib_class (const char *namespace, const char *name)
+EMSCRIPTEN_KEEPALIVE MonoAssembly*
+mono_wasm_get_corlib ()
{
- return mono_class_from_name (mono_get_corlib (), namespace, name);
+ return mono_image_get_assembly (mono_get_corlib());
}
EMSCRIPTEN_KEEPALIVE MonoClass*
mono_wasm_assembly_find_class (MonoAssembly *assembly, const char *namespace, const char *name)
{
+ assert (assembly);
return mono_class_from_name (mono_assembly_get_image (assembly), namespace, name);
}
EMSCRIPTEN_KEEPALIVE MonoMethod*
mono_wasm_assembly_find_method (MonoClass *klass, const char *name, int arguments)
{
+ assert (klass);
return mono_class_get_method_from_name (klass, name, arguments);
}
@@ -649,8 +692,7 @@ mono_wasm_get_delegate_invoke (MonoObject *delegate)
EMSCRIPTEN_KEEPALIVE MonoObject*
mono_wasm_box_primitive (MonoClass *klass, void *value, int value_size)
{
- if (!klass)
- return NULL;
+ assert (klass);
MonoType *type = mono_class_get_type (klass);
int alignment;
@@ -721,6 +763,7 @@ mono_wasm_assembly_get_entry_point (MonoAssembly *assembly)
return method;
MonoClass *klass = mono_method_get_class (method);
+ assert(klass);
char *async_name = malloc (name_length + 2);
snprintf (async_name, name_length + 2, "%s$", name);
@@ -772,6 +815,9 @@ mono_wasm_string_from_utf16 (const mono_unichar2 * chars, int length)
static int
class_is_task (MonoClass *klass)
{
+ if (!klass)
+ return 0;
+
if (!task_class && !resolved_task_class) {
task_class = mono_class_from_name (mono_get_corlib(), "System.Threading.Tasks", "Task");
resolved_task_class = 1;
@@ -792,39 +838,6 @@ MonoClass* mono_get_uri_class(MonoException** exc)
return klass;
}
-#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 marshalling
-#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
-
void mono_wasm_ensure_classes_resolved ()
{
if (!datetime_class && !resolved_datetime_class) {
@@ -855,14 +868,18 @@ mono_wasm_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType
{
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_PTR:
+ return MARSHAL_TYPE_POINTER;
case MONO_TYPE_I1:
case MONO_TYPE_U1:
case MONO_TYPE_I2:
case MONO_TYPE_U2:
case MONO_TYPE_I4:
- case MONO_TYPE_I: // IntPtr
return MARSHAL_TYPE_INT;
case MONO_TYPE_CHAR:
return MARSHAL_TYPE_CHAR;
@@ -880,6 +897,7 @@ mono_wasm_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType
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);
@@ -903,10 +921,14 @@ mono_wasm_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType
default:
return MARSHAL_TYPE_OBJECT;
}
+ } else {
+ return MARSHAL_TYPE_OBJECT;
+ }
}
default:
mono_wasm_ensure_classes_resolved ();
+ if (klass) {
if (klass == datetime_class)
return MARSHAL_TYPE_DATE;
if (klass == datetimeoffset_class)
@@ -917,13 +939,13 @@ mono_wasm_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType
return MARSHAL_TYPE_VOID;
if (mono_class_is_enum (klass))
return MARSHAL_TYPE_ENUM;
- if (!mono_type_is_reference (type)) //vt
+ 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))) {
+ if (safehandle_class && (klass == safehandle_class || mono_class_is_subclass_of(klass, safehandle_class, 0)))
return MARSHAL_TYPE_SAFEHANDLE;
}
@@ -931,6 +953,15 @@ mono_wasm_marshal_type_from_mono_type (int mono_type, MonoClass *klass, MonoType
}
}
+EMSCRIPTEN_KEEPALIVE MonoClass *
+mono_wasm_get_obj_class (MonoObject *obj)
+{
+ if (!obj)
+ return NULL;
+
+ return mono_object_get_class (obj);
+}
+
EMSCRIPTEN_KEEPALIVE int
mono_wasm_get_obj_type (MonoObject *obj)
{
@@ -939,11 +970,15 @@ mono_wasm_get_obj_type (MonoObject *obj)
/* 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;
if ((klass == mono_get_string_class ()) &&
mono_string_instance_is_interned ((MonoString *)obj))
return MARSHAL_TYPE_STRING_INTERNED;
MonoType *type = mono_class_get_type (klass);
+ if (!type)
+ return MARSHAL_ERROR_NULL_TYPE_POINTER;
obj = NULL;
int mono_type = mono_type_get_type (type);
@@ -952,33 +987,59 @@ mono_wasm_get_obj_type (MonoObject *obj)
}
EMSCRIPTEN_KEEPALIVE int
-mono_wasm_try_unbox_primitive_and_get_type (MonoObject *obj, void *result)
+mono_wasm_try_unbox_primitive_and_get_type (MonoObject *obj, void *result, int result_capacity)
{
+ void **resultP = result;
int *resultI = result;
int64_t *resultL = result;
float *resultF = result;
double *resultD = result;
- if (!obj) {
+ if (result_capacity >= sizeof (int64_t))
*resultL = 0;
- return 0;
- }
+ else if (result_capacity >= sizeof (int))
+ *resultI = 0;
+
+ if (!result)
+ return MARSHAL_ERROR_BUFFER_TOO_SMALL;
+
+ if (result_capacity < 16)
+ return MARSHAL_ERROR_BUFFER_TOO_SMALL;
+
+ if (!obj)
+ return MARSHAL_TYPE_NULL;
/* 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;
}
- MonoType *type = mono_class_get_type (klass), *original_type = type;
-
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) {
@@ -1010,24 +1071,58 @@ mono_wasm_try_unbox_primitive_and_get_type (MonoObject *obj, void *result)
case MONO_TYPE_R8:
*resultD = *(double*)mono_object_unbox (obj);
break;
+ case MONO_TYPE_PTR:
+ *resultL = (int64_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 = mono_wasm_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
- *resultL = 0;
+ // 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;
obj = NULL;
- return mono_wasm_marshal_type_from_mono_type (mono_type, klass, original_type);
+ int fallbackResultType = mono_wasm_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)
obj = NULL;
- return mono_wasm_marshal_type_from_mono_type (mono_type, klass, type);
+ int resultType = mono_wasm_marshal_type_from_mono_type (mono_type, klass, type);
+ assert (resultType != MARSHAL_TYPE_VT);
+ return resultType;
}
// FIXME: This function is retained specifically because runtime-test.js uses it
@@ -1159,3 +1254,37 @@ mono_wasm_string_get_data (
*outIsInterned = mono_string_instance_is_interned (string);
return;
}
+
+EMSCRIPTEN_KEEPALIVE MonoType *
+mono_wasm_class_get_type (MonoClass *klass)
+{
+ if (!klass)
+ return NULL;
+ return mono_class_get_type (klass);
+}
+
+EMSCRIPTEN_KEEPALIVE MonoClass *
+mono_wasm_type_get_class (MonoType *type)
+{
+ if (!type)
+ return NULL;
+ return mono_type_get_class (type);
+}
+
+EMSCRIPTEN_KEEPALIVE void *
+mono_wasm_unbox_rooted (MonoObject *obj)
+{
+ if (!obj)
+ return NULL;
+ return mono_object_unbox (obj);
+}
+
+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);
+}
diff --git a/src/mono/wasm/runtime/js-to-cs.ts b/src/mono/wasm/runtime/js-to-cs.ts
index 2e6f0c7a10ec45..e9807e6033affe 100644
--- a/src/mono/wasm/runtime/js-to-cs.ts
+++ b/src/mono/wasm/runtime/js-to-cs.ts
@@ -109,22 +109,22 @@ function _extract_mono_obj(should_add_in_flight: boolean, js_obj: any): MonoObje
}
function _box_js_int(js_obj: number) {
- Module.HEAP32[runtimeHelpers._box_buffer / 4] = js_obj;
+ Module.HEAP32[runtimeHelpers._box_buffer >>> 2] = js_obj;
return cwraps.mono_wasm_box_primitive(runtimeHelpers._class_int32, runtimeHelpers._box_buffer, 4);
}
function _box_js_uint(js_obj: number) {
- Module.HEAPU32[runtimeHelpers._box_buffer / 4] = js_obj;
+ Module.HEAPU32[runtimeHelpers._box_buffer >>> 2] = js_obj;
return cwraps.mono_wasm_box_primitive(runtimeHelpers._class_uint32, runtimeHelpers._box_buffer, 4);
}
function _box_js_double(js_obj: number) {
- Module.HEAPF64[runtimeHelpers._box_buffer / 8] = js_obj;
+ Module.HEAPF64[runtimeHelpers._box_buffer >>> 3] = js_obj;
return cwraps.mono_wasm_box_primitive(runtimeHelpers._class_double, runtimeHelpers._box_buffer, 8);
}
export function _box_js_bool(js_obj: boolean): MonoObject {
- Module.HEAP32[runtimeHelpers._box_buffer / 4] = js_obj ? 1 : 0;
+ Module.HEAP32[runtimeHelpers._box_buffer >>> 2] = js_obj ? 1 : 0;
return cwraps.mono_wasm_box_primitive(runtimeHelpers._class_boolean, runtimeHelpers._box_buffer, 4);
}
diff --git a/src/mono/wasm/runtime/memory.ts b/src/mono/wasm/runtime/memory.ts
new file mode 100644
index 00000000000000..abfe17ae89744b
--- /dev/null
+++ b/src/mono/wasm/runtime/memory.ts
@@ -0,0 +1,30 @@
+import { Module, MONO } from './modules'
+
+let _temp_mallocs : Array | null> = [];
+
+export function temp_malloc (size : number) : VoidPtr {
+ if (!_temp_mallocs || !_temp_mallocs.length)
+ throw new Error("No temp frames have been created at this point");
+
+ const frame = _temp_mallocs[_temp_mallocs.length - 1] || [];
+ const result = Module._malloc(size);
+ frame.push(result);
+ _temp_mallocs[_temp_mallocs.length - 1] = frame;
+ return result;
+}
+
+export function _create_temp_frame () {
+ _temp_mallocs.push(null);
+}
+
+export function _release_temp_frame () {
+ if (!_temp_mallocs.length)
+ throw new Error("No temp frames have been created at this point");
+
+ const frame = _temp_mallocs.pop();
+ if (!frame)
+ return;
+
+ for (let i = 0, l = frame.length; i < l; i++)
+ Module._free(frame[i]);
+}
diff --git a/src/mono/wasm/runtime/method-binding.ts b/src/mono/wasm/runtime/method-binding.ts
index 7d0011d01f0e24..6e48288f81d50e 100644
--- a/src/mono/wasm/runtime/method-binding.ts
+++ b/src/mono/wasm/runtime/method-binding.ts
@@ -1,17 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import { WasmRootBuffer } from "./roots";
-import { MonoClass, MonoMethod, MonoObject, coerceNull, VoidPtrNull, VoidPtr } from "./types";
+import { WasmRoot, WasmRootBuffer, mono_wasm_new_root } from "./roots";
+import { MonoClass, MonoMethod, MonoObject, coerceNull, VoidPtrNull, VoidPtr, MonoType } from "./types";
import { BINDING, MONO, runtimeHelpers } from "./modules";
import { js_to_mono_enum, _js_to_mono_obj, _js_to_mono_uri } from "./js-to-cs";
import { js_string_to_mono_string, js_string_to_mono_string_interned } from "./strings";
+import { MarshalType, _unbox_mono_obj_root_with_known_nonprimitive_type } from "./cs-to-js";
+import { _create_temp_frame } from "./memory";
+import {
+ _get_args_root_buffer_for_method_call, _get_buffer_for_method_call,
+ _handle_exception_for_call, _teardown_after_call
+} from "./method-calls";
import cwraps from "./cwraps";
+import cswraps from "./corebindings";
const primitiveConverters = new Map();
const _signature_converters = new Map();
const _method_descriptions = new Map();
+
+export function _get_type_name (typePtr : MonoType) : string {
+ if (!typePtr)
+ return "";
+ return cwraps.mono_wasm_get_type_name(typePtr);
+}
+
+export function _get_type_aqn (typePtr : MonoType) : string {
+ if (!typePtr)
+ return "";
+ return cwraps.mono_wasm_get_type_aqn(typePtr);
+}
+
+export function _get_class_name (classPtr : MonoClass) : string {
+ if (!classPtr)
+ return "";
+ return cwraps.mono_wasm_get_type_name(cwraps.mono_wasm_class_get_type(classPtr));
+}
+
export function find_method(klass: MonoClass, name: string, n: number): MonoMethod {
const result = cwraps.mono_wasm_assembly_find_method(klass, name, n);
if (result) {
@@ -33,7 +59,7 @@ export function bind_runtime_method(method_name: string, signature: ArgsMarshalS
}
-function _create_named_function(name: string, argumentNames: string[], body: string, closure: any) {
+export function _create_named_function(name: string, argumentNames: string[], body: string, closure: any) {
let result = null;
let closureArgumentList: any[] | null = null;
let closureArgumentNames = null;
@@ -52,7 +78,7 @@ function _create_named_function(name: string, argumentNames: string[], body: str
return result;
}
-function _create_rebindable_named_function(name: string, argumentNames: string[], body: string, closureArgNames: string[] | null) {
+export function _create_rebindable_named_function(name: string, argumentNames: string[], body: string, closureArgNames: string[] | null) {
const strictPrefix = "\"use strict\";\r\n";
let uriPrefix = "", escapedFunctionIdentifier = "";
@@ -139,17 +165,17 @@ function _create_converter_for_marshal_string(args_marshal: ArgsMarshalString):
if (conv.needs_root)
needs_root_buffer = true;
localStep.needs_root = conv.needs_root;
- localStep.key = args_marshal[i];
+ localStep.key = key;
steps.push(localStep);
size += conv.size;
}
return {
- steps: steps, size: size, args_marshal: args_marshal,
- is_result_definitely_unmarshaled: is_result_definitely_unmarshaled,
- is_result_possibly_unmarshaled: is_result_possibly_unmarshaled,
- result_unmarshaled_if_argc: result_unmarshaled_if_argc,
- needs_root_buffer: needs_root_buffer
+ steps, size, args_marshal,
+ is_result_definitely_unmarshaled,
+ is_result_possibly_unmarshaled,
+ result_unmarshaled_if_argc,
+ needs_root_buffer
};
}
@@ -183,14 +209,19 @@ export function _compile_converter_for_marshal_string(args_marshal: ArgsMarshalS
// 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;
- let closure: any = {};
+ const closure: any = {
+ Module,
+ _malloc: Module._malloc,
+ mono_wasm_unbox_rooted: cwraps.mono_wasm_unbox_rooted,
+ };
let indirectLocalOffset = 0;
body.push(
- `if (!buffer) buffer = Module._malloc (${bufferSizeBytes});`,
- `var indirectStart = buffer + ${indirectBaseOffset};`,
- "var indirect32 = (indirectStart / 4) | 0, indirect64 = (indirectStart / 8) | 0;",
- "var buffer32 = (buffer / 4) | 0;",
+ "if (!method) throw new Error('no method provided');",
+ `if (!buffer) buffer = _malloc (${bufferSizeBytes});`,
+ `let indirectStart = buffer + ${indirectBaseOffset};`,
+ "let indirect32 = indirectStart >>> 2, indirect64 = indirectStart >>> 3;",
+ "let buffer32 = buffer >>> 2;",
""
);
@@ -204,13 +235,22 @@ export function _compile_converter_for_marshal_string(args_marshal: ArgsMarshalS
if (step.convert) {
closure[closureKey] = step.convert;
- body.push(`var ${valueKey} = ${closureKey}(${argKey}, method, ${i});`);
+ body.push(`let ${valueKey} = ${closureKey}(${argKey}, method, ${i});`);
} else {
- body.push(`var ${valueKey} = ${argKey};`);
+ body.push(`let ${valueKey} = ${argKey};`);
}
- if (step.needs_root)
+ if (step.needs_root) {
+ body.push("if (!rootBuffer) throw new Error('no root buffer provided');");
body.push(`rootBuffer.set (${i}, ${valueKey});`);
+ }
+
+ // HACK: needs_unbox indicates that we were passed a pointer to a managed object, and either
+ // it was already rooted by our caller or (needs_root = true) by us. Now we can unbox it and
+ // pass the raw address of its boxed value into the callee.
+ // FIXME: I don't think this is GC safe
+ if (step.needs_unbox)
+ body.push (`${valueKey} = mono_wasm_unbox_rooted (${valueKey});`);
if (step.indirect) {
let heapArrayName = null;
@@ -226,7 +266,7 @@ export function _compile_converter_for_marshal_string(args_marshal: ArgsMarshalS
heapArrayName = "HEAPF32";
break;
case "double":
- body.push(`Module.HEAPF64[indirect64 + ${(indirectLocalOffset / 8)}] = ${valueKey};`);
+ body.push(`Module.HEAPF64[indirect64 + ${(indirectLocalOffset >>> 3)}] = ${valueKey};`);
break;
case "i64":
body.push(`Module.setValue (indirectStart + ${indirectLocalOffset}, ${valueKey}, 'i64');`);
@@ -236,7 +276,7 @@ export function _compile_converter_for_marshal_string(args_marshal: ArgsMarshalS
}
if (heapArrayName)
- body.push(`Module.${heapArrayName}[indirect32 + ${(indirectLocalOffset / 4)}] = ${valueKey};`);
+ body.push(`Module.${heapArrayName}[indirect32 + ${(indirectLocalOffset >>> 2)}] = ${valueKey};`);
body.push(`Module.HEAP32[buffer32 + ${i}] = indirectStart + ${indirectLocalOffset};`, "");
indirectLocalOffset += step.size!;
@@ -253,13 +293,14 @@ export function _compile_converter_for_marshal_string(args_marshal: ArgsMarshalS
compiledFunction = _create_named_function("converter_" + converterName, argumentNames, bodyJs, closure);
converter.compiled_function = compiledFunction;
} catch (exc) {
- converter.compiled_function = undefined;
+ converter.compiled_function = null;
console.warn("compiling converter failed for", bodyJs, "with error", exc);
throw exc;
}
+
argumentNames = ["existingBuffer", "rootBuffer", "method", "args"];
- closure = {
+ const variadicClosure = {
converter: compiledFunction
};
body = [
@@ -282,15 +323,15 @@ export function _compile_converter_for_marshal_string(args_marshal: ArgsMarshalS
bodyJs = body.join("\r\n");
try {
- compiledVariadicFunction = _create_named_function("variadic_converter_" + converterName, argumentNames, bodyJs, closure);
+ compiledVariadicFunction = _create_named_function("variadic_converter_" + converterName, argumentNames, bodyJs, variadicClosure);
converter.compiled_variadic_function = compiledVariadicFunction;
} catch (exc) {
- converter.compiled_variadic_function = undefined;
+ converter.compiled_variadic_function = null;
console.warn("compiling converter failed for", bodyJs, "with error", exc);
throw exc;
}
- converter.scratchRootBuffer = undefined;
+ converter.scratchRootBuffer = null;
converter.scratchBuffer = VoidPtrNull;
return converter;
@@ -331,37 +372,67 @@ export function mono_bind_method(method: MonoMethod, this_arg: MonoObject | null
this_arg = coerceNull(this_arg);
let converter: Converter | null = null;
+ if (typeof (args_marshal) === "string") {
+ converter = _compile_converter_for_marshal_string (args_marshal);
+ }
- converter = _compile_converter_for_marshal_string(args_marshal);
-
+ // FIXME
+ const unbox_buffer_size = 8192;
+ const unbox_buffer = Module._malloc(unbox_buffer_size);
+
+ const token: BoundMethodToken = {
+ friendlyName: friendly_name,
+ method,
+ converter,
+ scratchRootBuffer: null,
+ scratchBuffer: VoidPtrNull,
+ scratchResultRoot: mono_wasm_new_root(),
+ scratchExceptionRoot: mono_wasm_new_root()
+ };
const closure: any = {
- library_mono: MONO,
- binding_support: BINDING,
- method: method,
- this_arg: this_arg
+ mono_wasm_new_root,
+ _create_temp_frame,
+ _get_args_root_buffer_for_method_call,
+ _get_buffer_for_method_call,
+ _handle_exception_for_call,
+ _teardown_after_call,
+ mono_wasm_try_unbox_primitive_and_get_type: cwraps.mono_wasm_try_unbox_primitive_and_get_type,
+ _unbox_mono_obj_root_with_known_nonprimitive_type,
+ invoke_method: cwraps.mono_wasm_invoke_method,
+ method,
+ this_arg,
+ token,
+ unbox_buffer,
+ unbox_buffer_size
};
- const converterKey = "converter_" + converter.name;
-
+ const converterKey = converter ? "converter_" + converter.name : "";
if (converter)
closure[converterKey] = converter;
const argumentNames = [];
const body = [
- "var resultRoot = library_mono.mono_wasm_new_root (), exceptionRoot = library_mono.mono_wasm_new_root ();",
+ "_create_temp_frame();",
+ "let resultRoot = token.scratchResultRoot, exceptionRoot = token.scratchExceptionRoot;",
+ "token.scratchResultRoot = null;",
+ "token.scratchExceptionRoot = null;",
+ "if (resultRoot === null)",
+ " resultRoot = mono_wasm_new_root ();",
+ "if (exceptionRoot === null)",
+ " exceptionRoot = mono_wasm_new_root ();",
""
];
if (converter) {
body.push(
- `var argsRootBuffer = binding_support._get_args_root_buffer_for_method_call (${converterKey});`,
- `var scratchBuffer = binding_support._get_buffer_for_method_call (${converterKey});`,
- `var buffer = ${converterKey}.compiled_function (`,
+ `let argsRootBuffer = _get_args_root_buffer_for_method_call(${converterKey}, token);`,
+ `let scratchBuffer = _get_buffer_for_method_call(${converterKey}, token);`,
+ `let buffer = ${converterKey}.compiled_function(`,
" scratchBuffer, argsRootBuffer, method,"
);
for (let i = 0; i < converter.steps.length; i++) {
- const argName = "arg" + i;
+ let argName = "arg" + i;
argumentNames.push(argName);
body.push(
" " + argName +
@@ -376,15 +447,15 @@ export function mono_bind_method(method: MonoMethod, this_arg: MonoObject | null
body.push(");");
} else {
- body.push("var argsRootBuffer = null, buffer = 0;");
+ body.push("let argsRootBuffer = null, buffer = 0;");
}
- if (converter.is_result_definitely_unmarshaled) {
- body.push("var is_result_marshaled = false;");
- } else if (converter.is_result_possibly_unmarshaled) {
- body.push(`var is_result_marshaled = arguments.length !== ${converter.result_unmarshaled_if_argc};`);
+ 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("var is_result_marshaled = true;");
+ 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
@@ -398,53 +469,70 @@ export function mono_bind_method(method: MonoMethod, this_arg: MonoObject | null
// The end result is that bound method invocations don't always allocate, so no more nursery GCs. Yay! -kg
body.push(
"",
- "resultRoot.value = binding_support.invoke_method (method, this_arg, buffer, exceptionRoot.get_address ());",
- `binding_support._handle_exception_for_call (${converterKey}, buffer, resultRoot, exceptionRoot, argsRootBuffer);`,
+ "resultRoot.value = invoke_method (method, this_arg, buffer, exceptionRoot.get_address ());",
+ `_handle_exception_for_call (${converterKey}, token, buffer, resultRoot, exceptionRoot, argsRootBuffer);`,
"",
- "var result = undefined;",
- "if (!is_result_marshaled) ",
- " result = resultRoot.value;",
- "else if (resultRoot.value !== 0) {",
+ "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 && (resultPtr !== 0)) {",
// 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).
- " var resultType = binding_support.mono_wasm_try_unbox_primitive_and_get_type (resultRoot.value, buffer);",
+ " let resultType = mono_wasm_try_unbox_primitive_and_get_type (resultPtr, unbox_buffer, unbox_buffer_size);",
" switch (resultType) {",
- " case 1:", // int
- " result = Module.HEAP32[buffer / 4]; break;",
- " case 25:", // uint32
- " result = Module.HEAPU32[buffer / 4]; break;",
- " case 24:", // float32
- " result = Module.HEAPF32[buffer / 4]; break;",
- " case 2:", // float64
- " result = Module.HEAPF64[buffer / 8]; break;",
- " case 8:", // boolean
- " result = (Module.HEAP32[buffer / 4]) !== 0; break;",
- " case 28:", // char
- " result = String.fromCharCode(Module.HEAP32[buffer / 4]); break;",
+ ` case ${MarshalType.INT}:`,
+ " result = Module.HEAP32[unbox_buffer >>> 2]; break;",
+ ` case ${MarshalType.POINTER}:`, // FIXME: Is this right?
+ ` case ${MarshalType.UINT32}:`,
+ " result = Module.HEAPU32[unbox_buffer >>> 2]; break;",
+ ` case ${MarshalType.FP32}:`,
+ " result = Module.HEAPF32[unbox_buffer >>> 2]; break;",
+ ` case ${MarshalType.FP64}:`,
+ " result = Module.HEAPF64[unbox_buffer >>> 3]; break;",
+ ` case ${MarshalType.BOOL}:`,
+ " result = (Module.HEAP32[unbox_buffer >>> 2]) !== 0; break;",
+ ` case ${MarshalType.CHAR}:`,
+ " result = String.fromCharCode(Module.HEAP32[unbox_buffer >>> 2]); break;",
" default:",
- " result = binding_support._unbox_mono_obj_root_with_known_nonprimitive_type (resultRoot, resultType); break;",
+ " result = _unbox_mono_obj_root_with_known_nonprimitive_type (resultRoot, resultType, unbox_buffer); break;",
" }",
- "}",
- "",
- `binding_support._teardown_after_call (${converterKey}, buffer, resultRoot, exceptionRoot, argsRootBuffer);`,
- "return result;"
+ "}"
);
-
- const bodyJs = body.join("\r\n");
+ } else {
+ throw new Error("No converter");
+ }
if (friendly_name) {
- const escapeRE = /[^A-Za-z0-9_]/g;
+ const escapeRE = /[^A-Za-z0-9_\$]/g;
friendly_name = friendly_name.replace(escapeRE, "_");
}
- let displayName = "managed_" + (friendly_name || method);
+ let displayName = friendly_name || ("clr_" + method);
if (this_arg)
- displayName += "_with_this_" + this_arg;
+ displayName += "_this" + this_arg;
- return _create_named_function(displayName, argumentNames, bodyJs, closure);
+ body.push(
+ `_teardown_after_call (${converterKey}, token, buffer, resultRoot, exceptionRoot, argsRootBuffer);`,
+ "return result;"
+ );
+
+ let bodyJs = body.join ("\r\n");
+
+ let result = _create_named_function(displayName, argumentNames, bodyJs, closure);
+
+ return result;
}
declare const enum ArgsMarshal {
@@ -479,6 +567,7 @@ export type Converter = {
steps: {
convert?: boolean | Function;
needs_root?: boolean;
+ needs_unbox?: boolean;
indirect?: ConverterStepIndirects;
size?: number;
}[];
@@ -488,11 +577,25 @@ export type Converter = {
is_result_possibly_unmarshaled?: boolean;
result_unmarshaled_if_argc?: number;
needs_root_buffer?: boolean;
+ key?: string;
name?: string;
needs_root?: boolean;
- compiled_variadic_function?: Function;
- compiled_function?: Function;
- scratchRootBuffer?: WasmRootBuffer;
+ needs_unbox?: boolean;
+ compiled_variadic_function?: Function | null;
+ compiled_function?: Function | null;
+ scratchRootBuffer?: WasmRootBuffer | null;
scratchBuffer?: VoidPtr;
has_warned_about_signature?: boolean;
+ convert?: Function | null;
+ method?: MonoMethod | null;
+}
+
+export type BoundMethodToken = {
+ friendlyName: string;
+ method: MonoMethod;
+ converter: Converter | null;
+ scratchRootBuffer: WasmRootBuffer | null;
+ scratchBuffer: VoidPtr;
+ scratchResultRoot: WasmRoot;
+ scratchExceptionRoot: WasmRoot;
}
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/method-calls.ts b/src/mono/wasm/runtime/method-calls.ts
index 3847bc09c1a059..f3b5b223e05a69 100644
--- a/src/mono/wasm/runtime/method-calls.ts
+++ b/src/mono/wasm/runtime/method-calls.ts
@@ -2,15 +2,25 @@
// The .NET Foundation licenses this file to you under the MIT license.
import { mono_wasm_new_root, mono_wasm_new_root_buffer, WasmRoot, WasmRootBuffer } from "./roots";
-import { JSHandle, MonoArray, MonoMethod, MonoObject, MonoObjectNull, MonoString, coerceNull as coerceNull, VoidPtrNull, VoidPtr, Int32Ptr } from "./types";
+import {
+ JSHandle, MonoArray, MonoMethod, MonoObject,
+ MonoObjectNull, MonoString, coerceNull as coerceNull,
+ VoidPtr, VoidPtrNull, Int32Ptr
+} from "./types";
import { Module, runtimeHelpers } from "./modules";
import { _mono_array_root_to_js_array, _unbox_mono_obj_root } from "./cs-to-js";
import { get_js_obj, mono_wasm_get_jsobj_from_js_handle } from "./gc-handles";
import { js_array_to_mono_array, _box_js_bool, _js_to_mono_obj } from "./js-to-cs";
-import { ArgsMarshalString, mono_bind_method, Converter, _compile_converter_for_marshal_string, _decide_if_result_is_marshaled, find_method } from "./method-binding";
+import {
+ ArgsMarshalString, mono_bind_method,
+ Converter, _compile_converter_for_marshal_string,
+ _decide_if_result_is_marshaled, find_method,
+ BoundMethodToken
+} from "./method-binding";
import { conv_string, js_string_to_mono_string } from "./strings";
import cwraps from "./cwraps";
import { bindings_lazy_init } from "./startup";
+import { _create_temp_frame, _release_temp_frame } from "./memory";
function _verify_args_for_method_call(args_marshal: ArgsMarshalString, args: any) {
const has_args = args && (typeof args === "object") && args.length > 0;
@@ -26,43 +36,61 @@ function _verify_args_for_method_call(args_marshal: ArgsMarshalString, args: any
return has_args_marshal && has_args;
}
-export function _get_buffer_for_method_call(converter: Converter): VoidPtr | undefined {
+export function _get_buffer_for_method_call(converter: Converter, token: BoundMethodToken | null) : VoidPtr | undefined {
if (!converter)
return VoidPtrNull;
- const result = converter.scratchBuffer;
- converter.scratchBuffer = VoidPtrNull;
+ let result = VoidPtrNull;
+ if (token !== null) {
+ result = token.scratchBuffer || VoidPtrNull;
+ token.scratchBuffer = VoidPtrNull;
+ } else {
+ result = converter.scratchBuffer || VoidPtrNull;
+ converter.scratchBuffer = VoidPtrNull;
+ }
return result;
}
-export function _get_args_root_buffer_for_method_call(converter: Converter): WasmRootBuffer | undefined {
+export function _get_args_root_buffer_for_method_call(converter: Converter, token: BoundMethodToken | null) : WasmRootBuffer | undefined {
if (!converter)
return undefined;
if (!converter.needs_root_buffer)
return undefined;
- let result;
- if (converter.scratchRootBuffer) {
- result = converter.scratchRootBuffer;
- converter.scratchRootBuffer = undefined;
+ let result = null;
+ if (token !== null) {
+ result = token.scratchRootBuffer;
+ token.scratchRootBuffer = null;
} else {
+ result = converter.scratchRootBuffer;
+ converter.scratchRootBuffer = null;
+ }
+
+ if (result === null) {
// TODO: Expand the converter's heap allocation and then use
// mono_wasm_new_root_buffer_from_pointer instead. Not that important
// at present because the scratch buffer will be reused unless we are
// recursing through a re-entrant call
- result = mono_wasm_new_root_buffer(converter.steps.length, converter.name);
+ result = mono_wasm_new_root_buffer (converter.steps.length);
+ // FIXME
(result).converter = converter;
}
+
return result;
}
-function _release_args_root_buffer_from_method_call(converter?: Converter, argsRootBuffer?: WasmRootBuffer) {
+function _release_args_root_buffer_from_method_call(
+ converter?: Converter, token?: BoundMethodToken | null, argsRootBuffer?: WasmRootBuffer
+) {
if (!argsRootBuffer || !converter)
return;
// Store the arguments root buffer for re-use in later calls
- if (!converter.scratchRootBuffer) {
+ if (token && (token.scratchRootBuffer === null)) {
+ argsRootBuffer.clear ();
+ token.scratchRootBuffer = argsRootBuffer;
+ } else if (!converter.scratchRootBuffer) {
argsRootBuffer.clear();
converter.scratchRootBuffer = argsRootBuffer;
} else {
@@ -70,11 +98,15 @@ function _release_args_root_buffer_from_method_call(converter?: Converter, argsR
}
}
-function _release_buffer_from_method_call(converter: Converter | undefined, buffer?: VoidPtr) {
+function _release_buffer_from_method_call(
+ converter: Converter | undefined, token?: BoundMethodToken | null, buffer?: VoidPtr
+) {
if (!converter || !buffer)
return;
- if (!converter.scratchBuffer)
+ if (token && !token.scratchBuffer)
+ token.scratchBuffer = buffer;
+ else if (!converter.scratchBuffer)
converter.scratchBuffer = coerceNull(buffer);
else if (buffer)
Module._free(buffer);
@@ -122,59 +154,88 @@ export function call_method(method: MonoMethod, this_arg: MonoObject | undefined
let buffer = VoidPtrNull, converter = undefined, argsRootBuffer = undefined;
let is_result_marshaled = true;
+ // TODO: Only do this if the signature needs marshalling
+ _create_temp_frame();
+
// check if the method signature needs argument mashalling
if (needs_converter) {
converter = _compile_converter_for_marshal_string(args_marshal);
is_result_marshaled = _decide_if_result_is_marshaled(converter, args.length);
- argsRootBuffer = _get_args_root_buffer_for_method_call(converter);
+ argsRootBuffer = _get_args_root_buffer_for_method_call(converter, null);
- const scratchBuffer = _get_buffer_for_method_call(converter);
+ const scratchBuffer = _get_buffer_for_method_call(converter, null);
buffer = converter.compiled_variadic_function!(scratchBuffer, argsRootBuffer, method, args);
}
- return _call_method_with_converted_args(method, this_arg!, converter, buffer, is_result_marshaled, argsRootBuffer);
+ return _call_method_with_converted_args(method, this_arg!, converter, null, buffer, is_result_marshaled, argsRootBuffer);
}
-export function _handle_exception_for_call(converter: Converter | undefined, buffer: VoidPtr, resultRoot: WasmRoot, exceptionRoot: WasmRoot, argsRootBuffer?: WasmRootBuffer
-): void {
+export function _handle_exception_for_call(
+ converter: Converter | undefined, token: BoundMethodToken | null,
+ buffer: VoidPtr, resultRoot: WasmRoot,
+ exceptionRoot: WasmRoot, argsRootBuffer?: WasmRootBuffer
+) : void {
const exc = _convert_exception_for_method_call(resultRoot.value, exceptionRoot.value);
if (!exc)
return;
- _teardown_after_call(converter, buffer, resultRoot, exceptionRoot, argsRootBuffer);
+ _teardown_after_call(converter, token, buffer, resultRoot, exceptionRoot, argsRootBuffer);
throw exc;
}
-function _handle_exception_and_produce_result_for_call(converter: Converter | undefined, buffer: VoidPtr, resultRoot: WasmRoot, exceptionRoot: WasmRoot, argsRootBuffer: WasmRootBuffer | undefined, is_result_marshaled: boolean
-): any {
- _handle_exception_for_call(converter, buffer, resultRoot, exceptionRoot, argsRootBuffer);
+function _handle_exception_and_produce_result_for_call(
+ converter: Converter | undefined, token: BoundMethodToken | null,
+ buffer: VoidPtr, resultRoot: WasmRoot,
+ exceptionRoot: WasmRoot, argsRootBuffer: WasmRootBuffer | undefined,
+ is_result_marshaled: boolean
+) : any {
+ _handle_exception_for_call(converter, token, buffer, resultRoot, exceptionRoot, argsRootBuffer);
let result: any = resultRoot.value;
if (is_result_marshaled)
result = _unbox_mono_obj_root(resultRoot);
- _teardown_after_call(converter, buffer, resultRoot, exceptionRoot, argsRootBuffer);
+ _teardown_after_call(converter, token, buffer, resultRoot, exceptionRoot, argsRootBuffer);
return result;
}
-export function _teardown_after_call(converter: Converter | undefined, buffer: VoidPtr, resultRoot: WasmRoot, exceptionRoot: WasmRoot, argsRootBuffer?: WasmRootBuffer): void {
- _release_args_root_buffer_from_method_call(converter, argsRootBuffer);
- _release_buffer_from_method_call(converter, buffer);
-
- if (resultRoot)
- resultRoot.release();
- if (exceptionRoot)
- exceptionRoot.release();
+export function _teardown_after_call(
+ converter: Converter | undefined, token: BoundMethodToken | null,
+ buffer: VoidPtr, resultRoot: WasmRoot,
+ exceptionRoot: WasmRoot, argsRootBuffer?: WasmRootBuffer
+) : void {
+ _release_temp_frame();
+ _release_args_root_buffer_from_method_call(converter, token, argsRootBuffer);
+ _release_buffer_from_method_call(converter, token, buffer);
+
+ if (resultRoot) {
+ resultRoot.value = 0;
+ if ((token !== null) && (token.scratchResultRoot === null))
+ token.scratchResultRoot = resultRoot;
+ else
+ resultRoot.release ();
+ }
+ if (exceptionRoot) {
+ exceptionRoot.value = 0;
+ if ((token !== null) && (token.scratchExceptionRoot === null))
+ token.scratchExceptionRoot = exceptionRoot;
+ else
+ exceptionRoot.release ();
+ }
}
-function _call_method_with_converted_args(method: MonoMethod, this_arg: MonoObject, converter: Converter | undefined, buffer: VoidPtr, is_result_marshaled: boolean, argsRootBuffer?: WasmRootBuffer) {
+function _call_method_with_converted_args(
+ method: MonoMethod, this_arg: MonoObject, converter: Converter | undefined,
+ token: BoundMethodToken | null, buffer: VoidPtr,
+ is_result_marshaled: boolean, argsRootBuffer?: WasmRootBuffer
+) : any {
const resultRoot = mono_wasm_new_root(), exceptionRoot = mono_wasm_new_root();
resultRoot.value = cwraps.mono_wasm_invoke_method(method, this_arg, buffer, exceptionRoot.get_address());
- return _handle_exception_and_produce_result_for_call(converter, buffer, resultRoot, exceptionRoot, argsRootBuffer, is_result_marshaled);
+ return _handle_exception_and_produce_result_for_call(converter, token, buffer, resultRoot, exceptionRoot, argsRootBuffer, is_result_marshaled);
}
export function call_static_method(fqn: string, args: any[], signature: ArgsMarshalString): any {
diff --git a/src/mono/wasm/runtime/roots.ts b/src/mono/wasm/runtime/roots.ts
index f7ef2817ef0d2d..6d16379d914604 100644
--- a/src/mono/wasm/runtime/roots.ts
+++ b/src/mono/wasm/runtime/roots.ts
@@ -125,7 +125,7 @@ export function mono_wasm_release_roots(...args: WasmRoot[]): void {
function _zero_region(byteOffset: VoidPtr, sizeBytes: number) {
if (((byteOffset % 4) === 0) && ((sizeBytes % 4) === 0))
- Module.HEAP32.fill(0, byteOffset / 4, sizeBytes / 4);
+ Module.HEAP32.fill(0, byteOffset >>> 2, sizeBytes >>> 2);
else
Module.HEAP8.fill(0, byteOffset, sizeBytes);
}
@@ -170,7 +170,7 @@ export class WasmRootBuffer {
const capacityBytes = capacity * 4;
this.__offset = offset;
- this.__offset32 = (offset / 4) | 0;
+ this.__offset32 = offset >>> 2;
this.__count = capacity;
this.length = capacity;
this.__handle = cwraps.mono_wasm_register_root(offset, capacityBytes, name || "noname");
@@ -278,6 +278,9 @@ export class WasmRoot {
}
release(): void {
+ if (!this.__buffer)
+ throw new Error("No buffer");
+
const maxPooledInstances = 128;
if (_scratch_root_free_instances.length > maxPooledInstances) {
_mono_wasm_release_scratch_index(this.__index);
diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts
index 821b197e9f8b21..9f09f750013377 100644
--- a/src/mono/wasm/runtime/startup.ts
+++ b/src/mono/wasm/runtime/startup.ts
@@ -11,6 +11,7 @@ import { mono_wasm_init_aot_profiler, mono_wasm_init_coverage_profiler } from ".
import { mono_wasm_load_bytes_into_heap } from "./buffers";
import { bind_runtime_method, get_method, _create_primitive_converters } from "./method-binding";
import { conv_string } from "./strings";
+import { find_corlib_class } from "./class-loader";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function mono_wasm_invoke_js_blazor(exceptionMessage: Int32Ptr, callInfo: any, arg0: any, arg1: any, arg2: any): void | number {
@@ -347,12 +348,14 @@ export function bindings_lazy_init(): void {
(Float32Array.prototype)[wasm_type_symbol] = 17;
(Float64Array.prototype)[wasm_type_symbol] = 18;
- runtimeHelpers._box_buffer = Module._malloc(16);
- runtimeHelpers._unbox_buffer = Module._malloc(16);
- runtimeHelpers._class_int32 = cwraps.mono_wasm_find_corlib_class("System", "Int32");
- runtimeHelpers._class_uint32 = cwraps.mono_wasm_find_corlib_class("System", "UInt32");
- runtimeHelpers._class_double = cwraps.mono_wasm_find_corlib_class("System", "Double");
- runtimeHelpers._class_boolean = cwraps.mono_wasm_find_corlib_class("System", "Boolean");
+ runtimeHelpers._box_buffer_size = 65536;
+ runtimeHelpers._unbox_buffer_size = 65536;
+ runtimeHelpers._box_buffer = Module._malloc(runtimeHelpers._box_buffer_size);
+ runtimeHelpers._unbox_buffer = Module._malloc(runtimeHelpers._unbox_buffer_size);
+ runtimeHelpers._class_int32 = find_corlib_class("System", "Int32");
+ runtimeHelpers._class_uint32 = find_corlib_class("System", "UInt32");
+ runtimeHelpers._class_double = find_corlib_class("System", "Double");
+ runtimeHelpers._class_boolean = find_corlib_class("System", "Boolean");
runtimeHelpers.bind_runtime_method = bind_runtime_method;
const bindingAssembly = INTERNAL.BINDING_ASM;
@@ -417,9 +420,9 @@ function _load_assets_and_runtime(args: MonoConfig) {
if (ctx.pending_count === 0) {
try {
_finalize_startup(args, ctx);
- } catch (exc: any) {
+ } catch (exc : any) {
console.error("Unhandled exception in _finalize_startup", exc);
- console.log(exc.stack);
+ console.error(exc.stack);
throw exc;
}
}
diff --git a/src/mono/wasm/runtime/strings.ts b/src/mono/wasm/runtime/strings.ts
index 0977591fdbab41..18871e42599f65 100644
--- a/src/mono/wasm/runtime/strings.ts
+++ b/src/mono/wasm/runtime/strings.ts
@@ -31,9 +31,9 @@ export class StringDecoder {
cwraps.mono_wasm_string_get_data(mono_string, ppChars, pLengthBytes, pIsInterned);
let result = mono_wasm_empty_string;
- const lengthBytes = Module.HEAP32[pLengthBytes / 4],
- pChars = Module.HEAP32[ppChars / 4],
- isInterned = Module.HEAP32[pIsInterned / 4];
+ const lengthBytes = Module.HEAP32[pLengthBytes >>> 2],
+ pChars = Module.HEAP32[ppChars >>> 2],
+ isInterned = Module.HEAP32[pIsInterned >>> 2];
if (pLengthBytes && pChars) {
if (
@@ -186,9 +186,9 @@ export function js_string_to_mono_string(string: string): MonoString | null {
return js_string_to_mono_string_new(string);
}
-function js_string_to_mono_string_new(string: string) {
+export function js_string_to_mono_string_new(string: string) : MonoString {
const buffer = Module._malloc((string.length + 1) * 2);
- const buffer16 = (buffer / 2) | 0;
+ const buffer16 = (buffer >>> 1) | 0;
for (let i = 0; i < string.length; i++)
Module.HEAP16[buffer16 + i] = string.charCodeAt(i);
Module.HEAP16[buffer16 + string.length] = 0;
diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts
index 34a6584ccc02ef..cf9c65ee6b0ec9 100644
--- a/src/mono/wasm/runtime/types.ts
+++ b/src/mono/wasm/runtime/types.ts
@@ -44,7 +44,10 @@ export interface MonoString extends MonoObject {
export interface MonoClass extends MonoObject {
__brand: "MonoClass"
}
-export interface MonoMethod extends ManagedPointer {
+export interface MonoType extends ManagedPointer{
+ __brand: "MonoType"
+}
+export interface MonoMethod extends ManagedPointer{
__brand: "MonoMethod"
}
export interface MonoArray extends MonoObject {
@@ -58,6 +61,7 @@ export const MonoObjectNull: MonoObject = 0;
export const MonoArrayNull: MonoArray = 0;
export const MonoAssemblyNull: MonoAssembly = 0;
export const MonoClassNull: MonoClass = 0;
+export const MonoTypeNull: MonoType = 0;
export const MonoStringNull: MonoString = 0;
export const JSHandleDisposed: JSHandle = -1;
export const JSHandleNull: JSHandle = 0;
@@ -137,6 +141,9 @@ export type RuntimeHelpers = {
wasm_runtime_class: MonoClass;
bind_runtime_method: typeof bind_runtime_method;
+ _box_buffer_size: number;
+ _unbox_buffer_size: number;
+
_box_buffer: VoidPtr;
_unbox_buffer: VoidPtr;
_class_int32: MonoClass;