1 #include <emscripten.h>
8 #include <mono/metadata/assembly.h>
9 #include <mono/metadata/tokentype.h>
10 #include <mono/utils/mono-logger.h>
11 #include <mono/utils/mono-dl-fallback.h>
12 #include <mono/jit/jit.h>
15 #include "pinvoke-table.h"
17 #include "pinvoke-tables-default.h"
21 void core_initialize_internals ();
24 // Blazor specific custom routines - see dotnet_support.js for backing code
25 extern void* mono_wasm_invoke_js_marshalled (MonoString
**exceptionMessage
, void *asyncHandleLongPtr
, MonoString
*funcName
, MonoString
*argsJson
);
26 extern void* mono_wasm_invoke_js_unmarshalled (MonoString
**exceptionMessage
, MonoString
*funcName
, void* arg0
, void* arg1
, void* arg2
);
28 void mono_wasm_enable_debugging (void);
30 void mono_ee_interp_init (const char *opts
);
31 void mono_marshal_ilgen_init (void);
32 void mono_method_builder_ilgen_init (void);
33 void mono_sgen_mono_ilgen_init (void);
34 void mono_icall_table_init (void);
35 void mono_aot_register_module (void **aot_info
);
36 char *monoeg_g_getenv(const char *variable
);
37 int monoeg_g_setenv(const char *variable
, const char *value
, int overwrite
);
38 void mono_free (void*);
40 /* Not part of public headers */
41 #define MONO_ICALL_TABLE_CALLBACKS_VERSION 2
45 void* (*lookup
) (MonoMethod
*method
, char *classname
, char *methodname
, char *sigstart
, int32_t *uses_handles
);
46 const char* (*lookup_icall_symbol
) (void* func
);
47 } MonoIcallTableCallbacks
;
50 mono_install_icall_table_callbacks (MonoIcallTableCallbacks
*cb
);
52 int mono_regression_test_step (int verbose_level
, char *image
, char *method_name
);
53 void mono_trace_init (void);
56 m_strdup (const char *str
)
61 int len
= strlen (str
) + 1;
62 char *res
= malloc (len
);
63 memcpy (res
, str
, len
);
67 static MonoDomain
*root_domain
;
70 mono_wasm_invoke_js (MonoString
*str
, int *is_exception
)
75 char *native_val
= mono_string_to_utf8 (str
);
76 mono_unichar2
*native_res
= (mono_unichar2
*)EM_ASM_INT ({
77 var str
= UTF8ToString ($
0);
80 if (res
=== null
|| res
== undefined
)
82 res
= res
.toString ();
83 setValue ($
1, 0, "i32");
86 setValue ($
1, 1, "i32");
87 if (res
=== null
|| res
=== undefined
)
88 res
= "unknown exception";
90 var buff
= Module
._malloc((res
.length
+ 1) * 2);
91 stringToUTF16 (res
, buff
, (res
.length
+ 1) * 2);
93 }, (int)native_val
, is_exception
);
95 mono_free (native_val
);
97 if (native_res
== NULL
)
100 MonoString
*res
= mono_string_from_utf16 (native_res
);
106 wasm_logger (const char *log_domain
, const char *log_level
, const char *message
, mono_bool fatal
, void *user_data
)
110 var err
= new Error();
111 console
.log ("Stacktrace: \n");
112 console
.log (err
.stack
);
115 fprintf (stderr
, "%s", message
);
119 fprintf (stdout
, "%s\n", message
);
124 #include "driver-gen.c"
127 typedef struct WasmAssembly_ WasmAssembly
;
129 struct WasmAssembly_
{
130 MonoBundledAssembly assembly
;
134 static WasmAssembly
*assemblies
;
135 static int assembly_count
;
137 EMSCRIPTEN_KEEPALIVE
void
138 mono_wasm_add_assembly (const char *name
, const unsigned char *data
, unsigned int size
)
140 int len
= strlen (name
);
141 if (!strcasecmp (".pdb", &name
[len
- 4])) {
142 char *new_name
= m_strdup (name
);
143 //FIXME handle debugging assemblies with .exe extension
144 strcpy (&new_name
[len
- 3], "dll");
145 mono_register_symfile_for_assembly (new_name
, data
, size
);
148 WasmAssembly
*entry
= (WasmAssembly
*)malloc(sizeof (MonoBundledAssembly
));
149 entry
->assembly
.name
= m_strdup (name
);
150 entry
->assembly
.data
= data
;
151 entry
->assembly
.size
= size
;
152 entry
->next
= assemblies
;
157 EMSCRIPTEN_KEEPALIVE
void
158 mono_wasm_setenv (const char *name
, const char *value
)
160 monoeg_g_setenv (strdup (name
), strdup (value
), 1);
164 wasm_dl_load (const char *name
, int flags
, char **err
, void *user_data
)
166 for (int i
= 0; i
< sizeof (pinvoke_tables
) / sizeof (void*); ++i
) {
167 if (!strcmp (name
, pinvoke_names
[i
]))
168 return pinvoke_tables
[i
];
174 wasm_dl_symbol (void *handle
, const char *name
, char **err
, void *user_data
)
176 PinvokeImport
*table
= (PinvokeImport
*)handle
;
177 for (int i
= 0; table
[i
].name
; ++i
) {
178 if (!strcmp (table
[i
].name
, name
))
179 return table
[i
].func
;
184 #if !defined(ENABLE_AOT) || defined(EE_MODE_LLVMONLY_INTERP)
185 #define NEED_INTERP 1
187 // FIXME: llvm+interp mode needs this to call icalls
188 #define NEED_NORMAL_ICALL_TABLES 1
194 #include "icall-table.h"
197 compare_int (const void *k1
, const void *k2
)
199 return *(int*)k1
- *(int*)k2
;
203 icall_table_lookup (MonoMethod
*method
, char *classname
, char *methodname
, char *sigstart
, int32_t *uses_handles
)
205 uint32_t token
= mono_method_get_token (method
);
207 assert ((token
& MONO_TOKEN_METHOD_DEF
) == MONO_TOKEN_METHOD_DEF
);
208 uint32_t token_idx
= token
- MONO_TOKEN_METHOD_DEF
;
211 int indexes_size
= 0;
212 uint8_t *handles
= NULL
;
217 const char *image_name
= mono_image_get_name (mono_class_get_image (mono_method_get_class (method
)));
219 #ifdef ICALL_TABLE_mscorlib
220 if (!strcmp (image_name
, "mscorlib")) {
221 indexes
= mscorlib_icall_indexes
;
222 indexes_size
= sizeof (mscorlib_icall_indexes
) / 4;
223 handles
= mscorlib_icall_handles
;
224 funcs
= mscorlib_icall_funcs
;
225 assert (sizeof (mscorlib_icall_indexes
[0]) == 4);
227 #ifdef ICALL_TABLE_System
228 if (!strcmp (image_name
, "System")) {
229 indexes
= System_icall_indexes
;
230 indexes_size
= sizeof (System_icall_indexes
) / 4;
231 handles
= System_icall_handles
;
232 funcs
= System_icall_funcs
;
237 void *p
= bsearch (&token_idx
, indexes
, indexes_size
, 4, compare_int
);
240 printf ("wasm: Unable to lookup icall: %s\n", mono_method_get_name (method
));
244 uint32_t idx
= (int*)p
- indexes
;
245 *uses_handles
= handles
[idx
];
247 //printf ("ICALL: %s %x %d %d\n", methodname, token, idx, (int)(funcs [idx]));
254 icall_table_lookup_symbol (void *func
)
262 void mono_initialize_internals ()
264 mono_add_internal_call ("WebAssembly.Runtime::InvokeJS", mono_wasm_invoke_js
);
266 // Blazor specific custom routines - see dotnet_support.js for backing code
267 mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSMarshalled", mono_wasm_invoke_js_marshalled
);
268 mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSUnmarshalled", mono_wasm_invoke_js_unmarshalled
);
271 core_initialize_internals();
276 EMSCRIPTEN_KEEPALIVE
void
277 mono_wasm_load_runtime (const char *managed_path
, int enable_debugging
)
279 monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0);
280 monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0);
282 mono_dl_fallback_register (wasm_dl_load
, wasm_dl_symbol
, NULL
, NULL
);
285 // Defined in driver-gen.c
286 register_aot_modules ();
287 #ifdef EE_MODE_LLVMONLY_INTERP
288 mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY_INTERP
);
290 mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY
);
293 mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_LLVMONLY
);
294 if (enable_debugging
)
295 mono_wasm_enable_debugging ();
299 /* Link in our own linked icall table */
300 MonoIcallTableCallbacks cb
;
301 memset (&cb
, 0, sizeof (MonoIcallTableCallbacks
));
302 cb
.version
= MONO_ICALL_TABLE_CALLBACKS_VERSION
;
303 cb
.lookup
= icall_table_lookup
;
304 cb
.lookup_icall_symbol
= icall_table_lookup_symbol
;
306 mono_install_icall_table_callbacks (&cb
);
309 #ifdef NEED_NORMAL_ICALL_TABLES
310 mono_icall_table_init ();
313 mono_ee_interp_init ("");
314 mono_marshal_ilgen_init ();
315 mono_method_builder_ilgen_init ();
316 mono_sgen_mono_ilgen_init ();
319 if (assembly_count
) {
320 MonoBundledAssembly
**bundle_array
= (MonoBundledAssembly
**)calloc (1, sizeof (MonoBundledAssembly
*) * (assembly_count
+ 1));
321 WasmAssembly
*cur
= assemblies
;
322 bundle_array
[assembly_count
] = NULL
;
325 bundle_array
[i
] = &cur
->assembly
;
329 mono_register_bundled_assemblies ((const MonoBundledAssembly
**)bundle_array
);
333 mono_trace_set_log_handler (wasm_logger
, NULL
);
334 root_domain
= mono_jit_init_version ("mono", "v4.0.30319");
336 mono_initialize_internals();
339 EMSCRIPTEN_KEEPALIVE MonoAssembly
*
340 mono_wasm_assembly_load (const char *name
)
342 MonoImageOpenStatus status
;
343 MonoAssemblyName
* aname
= mono_assembly_name_new (name
);
347 MonoAssembly
*res
= mono_assembly_load (aname
, NULL
, &status
);
348 mono_assembly_name_free (aname
);
353 EMSCRIPTEN_KEEPALIVE MonoClass
*
354 mono_wasm_assembly_find_class (MonoAssembly
*assembly
, const char *namespace, const char *name
)
356 return mono_class_from_name (mono_assembly_get_image (assembly
), namespace, name
);
359 EMSCRIPTEN_KEEPALIVE MonoMethod
*
360 mono_wasm_assembly_find_method (MonoClass
*klass
, const char *name
, int arguments
)
362 return mono_class_get_method_from_name (klass
, name
, arguments
);
365 EMSCRIPTEN_KEEPALIVE MonoObject
*
366 mono_wasm_invoke_method (MonoMethod
*method
, MonoObject
*this_arg
, void *params
[], int* got_exception
)
368 MonoObject
*exc
= NULL
;
369 MonoObject
*res
= mono_runtime_invoke (method
, this_arg
, params
, &exc
);
375 MonoObject
*exc2
= NULL
;
376 res
= (MonoObject
*)mono_object_to_string (exc
, &exc2
);
378 res
= (MonoObject
*) mono_string_new (root_domain
, "Exception Double Fault");
382 MonoMethodSignature
*sig
= mono_method_signature (method
);
383 MonoType
*type
= mono_signature_get_return_type (sig
);
384 // If the method return type is void return null
385 // This gets around a memory access crash when the result return a value when
386 // a void method is invoked.
387 if (mono_type_get_type (type
) == MONO_TYPE_VOID
)
393 EMSCRIPTEN_KEEPALIVE MonoMethod
*
394 mono_wasm_assembly_get_entry_point (MonoAssembly
*assembly
)
399 image
= mono_assembly_get_image (assembly
);
400 uint32_t entry
= mono_image_get_entry_point (image
);
404 return mono_get_method (image
, entry
, NULL
);
407 EMSCRIPTEN_KEEPALIVE
char *
408 mono_wasm_string_get_utf8 (MonoString
*str
)
410 return mono_string_to_utf8 (str
); //XXX JS is responsible for freeing this
413 EMSCRIPTEN_KEEPALIVE MonoString
*
414 mono_wasm_string_from_js (const char *str
)
416 return mono_string_new (root_domain
, str
);
420 class_is_task (MonoClass
*klass
)
422 if (!strcmp ("System.Threading.Tasks", mono_class_get_namespace (klass
)) &&
423 (!strcmp ("Task", mono_class_get_name (klass
)) || !strcmp ("Task`1", mono_class_get_name (klass
))))
429 #define MARSHAL_TYPE_INT 1
430 #define MARSHAL_TYPE_FP 2
431 #define MARSHAL_TYPE_STRING 3
432 #define MARSHAL_TYPE_VT 4
433 #define MARSHAL_TYPE_DELEGATE 5
434 #define MARSHAL_TYPE_TASK 6
435 #define MARSHAL_TYPE_OBJECT 7
436 #define MARSHAL_TYPE_BOOL 8
437 #define MARSHAL_TYPE_ENUM 9
439 // typed array marshalling
440 #define MARSHAL_ARRAY_BYTE 11
441 #define MARSHAL_ARRAY_UBYTE 12
442 #define MARSHAL_ARRAY_SHORT 13
443 #define MARSHAL_ARRAY_USHORT 14
444 #define MARSHAL_ARRAY_INT 15
445 #define MARSHAL_ARRAY_UINT 16
446 #define MARSHAL_ARRAY_FLOAT 17
447 #define MARSHAL_ARRAY_DOUBLE 18
449 EMSCRIPTEN_KEEPALIVE
int
450 mono_wasm_get_obj_type (MonoObject
*obj
)
454 MonoClass
*klass
= mono_object_get_class (obj
);
455 MonoType
*type
= mono_class_get_type (klass
);
457 switch (mono_type_get_type (type
)) {
458 // case MONO_TYPE_CHAR: prob should be done not as a number?
459 case MONO_TYPE_BOOLEAN
:
460 return MARSHAL_TYPE_BOOL
;
469 return MARSHAL_TYPE_INT
;
472 return MARSHAL_TYPE_FP
;
473 case MONO_TYPE_STRING
:
474 return MARSHAL_TYPE_STRING
;
475 case MONO_TYPE_SZARRAY
: { // simple zero based one-dim-array
476 MonoClass
*eklass
= mono_class_get_element_class(klass
);
477 MonoType
*etype
= mono_class_get_type (eklass
);
479 switch (mono_type_get_type (etype
)) {
481 return MARSHAL_ARRAY_UBYTE
;
483 return MARSHAL_ARRAY_BYTE
;
485 return MARSHAL_ARRAY_USHORT
;
487 return MARSHAL_ARRAY_SHORT
;
489 return MARSHAL_ARRAY_UINT
;
491 return MARSHAL_ARRAY_INT
;
493 return MARSHAL_ARRAY_FLOAT
;
495 return MARSHAL_ARRAY_DOUBLE
;
497 return MARSHAL_TYPE_OBJECT
;
501 if (mono_class_is_enum (klass
))
502 return MARSHAL_TYPE_ENUM
;
503 if (!mono_type_is_reference (type
)) //vt
504 return MARSHAL_TYPE_VT
;
505 if (mono_class_is_delegate (klass
))
506 return MARSHAL_TYPE_DELEGATE
;
507 if (class_is_task(klass
))
508 return MARSHAL_TYPE_TASK
;
510 return MARSHAL_TYPE_OBJECT
;
514 EMSCRIPTEN_KEEPALIVE
int
515 mono_unbox_int (MonoObject
*obj
)
519 MonoType
*type
= mono_class_get_type (mono_object_get_class(obj
));
521 void *ptr
= mono_object_unbox (obj
);
522 switch (mono_type_get_type (type
)) {
524 case MONO_TYPE_BOOLEAN
:
525 return *(signed char*)ptr
;
527 return *(unsigned char*)ptr
;
531 return *(unsigned short*)ptr
;
535 return *(unsigned int*)ptr
;
536 // WASM doesn't support returning longs to JS
537 // case MONO_TYPE_I8:
538 // case MONO_TYPE_U8:
540 printf ("Invalid type %d to mono_unbox_int\n", mono_type_get_type (type
));
545 EMSCRIPTEN_KEEPALIVE
double
546 mono_wasm_unbox_float (MonoObject
*obj
)
550 MonoType
*type
= mono_class_get_type (mono_object_get_class(obj
));
552 void *ptr
= mono_object_unbox (obj
);
553 switch (mono_type_get_type (type
)) {
557 return *(double*)ptr
;
559 printf ("Invalid type %d to mono_wasm_unbox_float\n", mono_type_get_type (type
));
564 EMSCRIPTEN_KEEPALIVE
int
565 mono_wasm_array_length (MonoArray
*array
)
567 return mono_array_length (array
);
570 EMSCRIPTEN_KEEPALIVE MonoObject
*
571 mono_wasm_array_get (MonoArray
*array
, int idx
)
573 return mono_array_get (array
, MonoObject
*, idx
);
576 EMSCRIPTEN_KEEPALIVE MonoArray
*
577 mono_wasm_obj_array_new (int size
)
579 return mono_array_new (root_domain
, mono_get_object_class (), size
);
582 EMSCRIPTEN_KEEPALIVE
void
583 mono_wasm_obj_array_set (MonoArray
*array
, int idx
, MonoObject
*obj
)
585 mono_array_setref (array
, idx
, obj
);
588 EMSCRIPTEN_KEEPALIVE MonoArray
*
589 mono_wasm_string_array_new (int size
)
591 return mono_array_new (root_domain
, mono_get_string_class (), size
);
594 EMSCRIPTEN_KEEPALIVE
int
595 mono_wasm_exec_regression (int verbose_level
, char *image
)
597 return mono_regression_test_step (verbose_level
, image
, NULL
) ? 0 : 1;
600 EMSCRIPTEN_KEEPALIVE
int
601 mono_wasm_exit (int exit_code
)
606 EMSCRIPTEN_KEEPALIVE
void
607 mono_wasm_set_main_args (int argc
, char* argv
[])
609 mono_runtime_set_main_args (argc
, argv
);
612 EMSCRIPTEN_KEEPALIVE
int
613 mono_wasm_strdup (const char *s
)
615 return (int)strdup (s
);