1 #include <emscripten.h>
9 #include <mono/metadata/assembly.h>
10 #include <mono/metadata/tokentype.h>
11 #include <mono/utils/mono-logger.h>
12 #include <mono/utils/mono-dl-fallback.h>
13 #include <mono/jit/jit.h>
16 #include "pinvoke-table.h"
18 #include "pinvoke-tables-default.h"
22 void core_initialize_internals ();
25 // Blazor specific custom routines - see dotnet_support.js for backing code
26 extern void* mono_wasm_invoke_js_marshalled (MonoString
**exceptionMessage
, void *asyncHandleLongPtr
, MonoString
*funcName
, MonoString
*argsJson
);
27 extern void* mono_wasm_invoke_js_unmarshalled (MonoString
**exceptionMessage
, MonoString
*funcName
, void* arg0
, void* arg1
, void* arg2
);
29 void mono_wasm_enable_debugging (void);
31 void mono_ee_interp_init (const char *opts
);
32 void mono_marshal_ilgen_init (void);
33 void mono_method_builder_ilgen_init (void);
34 void mono_sgen_mono_ilgen_init (void);
35 void mono_icall_table_init (void);
36 void mono_aot_register_module (void **aot_info
);
37 char *monoeg_g_getenv(const char *variable
);
38 int monoeg_g_setenv(const char *variable
, const char *value
, int overwrite
);
39 void mono_free (void*);
41 static MonoClass
* datetime_class
;
42 static MonoClass
* datetimeoffset_class
;
44 int mono_wasm_enable_gc
;
46 /* Not part of public headers */
47 #define MONO_ICALL_TABLE_CALLBACKS_VERSION 2
51 void* (*lookup
) (MonoMethod
*method
, char *classname
, char *methodname
, char *sigstart
, int32_t *uses_handles
);
52 const char* (*lookup_icall_symbol
) (void* func
);
53 } MonoIcallTableCallbacks
;
56 mono_install_icall_table_callbacks (const MonoIcallTableCallbacks
*cb
);
58 int mono_regression_test_step (int verbose_level
, char *image
, char *method_name
);
59 void mono_trace_init (void);
61 #define g_new(type, size) ((type *) malloc (sizeof (type) * (size)))
62 #define g_new0(type, size) ((type *) calloc (sizeof (type), (size)))
65 m_strdup (const char *str
)
70 const size_t len
= strlen (str
) + 1;
71 return memcpy (g_new (char, len
), str
, len
);
74 static MonoDomain
*root_domain
;
77 mono_wasm_invoke_js (MonoString
*str
, int *is_exception
)
82 char *native_val
= mono_string_to_utf8 (str
);
83 mono_unichar2
*native_res
= (mono_unichar2
*)EM_ASM_INT ({
84 var str
= UTF8ToString ($
0);
87 if (res
=== null
|| res
== undefined
)
89 res
= res
.toString ();
90 setValue ($
1, 0, "i32");
93 setValue ($
1, 1, "i32");
94 if (res
=== null
|| res
=== undefined
)
95 res
= "unknown exception";
97 var buff
= Module
._malloc((res
.length
+ 1) * 2);
98 stringToUTF16 (res
, buff
, (res
.length
+ 1) * 2);
100 }, (int)native_val
, is_exception
);
102 mono_free (native_val
);
104 if (native_res
== NULL
)
107 MonoString
*res
= mono_string_from_utf16 (native_res
);
113 wasm_logger (const char *log_domain
, const char *log_level
, const char *message
, mono_bool fatal
, void *user_data
)
117 var err
= new Error();
118 console
.log ("Stacktrace: \n");
119 console
.log (err
.stack
);
122 fprintf (stderr
, "%s", message
);
126 fprintf (stdout
, "%s\n", message
);
131 #include "driver-gen.c"
134 typedef struct WasmAssembly_ WasmAssembly
;
136 struct WasmAssembly_
{
137 MonoBundledAssembly assembly
;
141 static WasmAssembly
*assemblies
;
142 static int assembly_count
;
144 EMSCRIPTEN_KEEPALIVE
void
145 mono_wasm_add_assembly (const char *name
, const unsigned char *data
, unsigned int size
)
147 int len
= strlen (name
);
148 if (!strcasecmp (".pdb", &name
[len
- 4])) {
149 char *new_name
= m_strdup (name
);
150 //FIXME handle debugging assemblies with .exe extension
151 strcpy (&new_name
[len
- 3], "dll");
152 mono_register_symfile_for_assembly (new_name
, data
, size
);
155 WasmAssembly
*entry
= g_new0 (WasmAssembly
, 1);
156 entry
->assembly
.name
= m_strdup (name
);
157 entry
->assembly
.data
= data
;
158 entry
->assembly
.size
= size
;
159 entry
->next
= assemblies
;
164 EMSCRIPTEN_KEEPALIVE
void
165 mono_wasm_setenv (const char *name
, const char *value
)
167 monoeg_g_setenv (strdup (name
), strdup (value
), 1);
171 wasm_dl_load (const char *name
, int flags
, char **err
, void *user_data
)
173 for (int i
= 0; i
< sizeof (pinvoke_tables
) / sizeof (void*); ++i
) {
174 if (!strcmp (name
, pinvoke_names
[i
]))
175 return pinvoke_tables
[i
];
178 #if WASM_SUPPORTS_DLOPEN
179 return dlopen(name
, flags
);
186 wasm_dl_is_pinvoke_tables (void* handle
) {
187 for (int i
= 0; i
< sizeof (pinvoke_tables
) / sizeof (void*); ++i
) {
188 if (pinvoke_tables
[i
] == handle
) {
196 wasm_dl_symbol (void *handle
, const char *name
, char **err
, void *user_data
)
198 #if WASM_SUPPORTS_DLOPEN
199 if (!wasm_dl_is_pinvoke_tables (handle
)) {
200 return dlsym (handle
, name
);
204 PinvokeImport
*table
= (PinvokeImport
*)handle
;
205 for (int i
= 0; table
[i
].name
; ++i
) {
206 if (!strcmp (table
[i
].name
, name
))
207 return table
[i
].func
;
212 #if !defined(ENABLE_AOT) || defined(EE_MODE_LLVMONLY_INTERP)
213 #define NEED_INTERP 1
215 // FIXME: llvm+interp mode needs this to call icalls
216 #define NEED_NORMAL_ICALL_TABLES 1
222 #include "icall-table.h"
225 compare_int (const void *k1
, const void *k2
)
227 return *(int*)k1
- *(int*)k2
;
231 icall_table_lookup (MonoMethod
*method
, char *classname
, char *methodname
, char *sigstart
, int32_t *uses_handles
)
233 uint32_t token
= mono_method_get_token (method
);
235 assert ((token
& MONO_TOKEN_METHOD_DEF
) == MONO_TOKEN_METHOD_DEF
);
236 uint32_t token_idx
= token
- MONO_TOKEN_METHOD_DEF
;
239 int indexes_size
= 0;
240 uint8_t *handles
= NULL
;
245 const char *image_name
= mono_image_get_name (mono_class_get_image (mono_method_get_class (method
)));
247 #ifdef ICALL_TABLE_mscorlib
248 if (!strcmp (image_name
, "mscorlib")) {
249 indexes
= mscorlib_icall_indexes
;
250 indexes_size
= sizeof (mscorlib_icall_indexes
) / 4;
251 handles
= mscorlib_icall_handles
;
252 funcs
= mscorlib_icall_funcs
;
253 assert (sizeof (mscorlib_icall_indexes
[0]) == 4);
255 #ifdef ICALL_TABLE_System
256 if (!strcmp (image_name
, "System")) {
257 indexes
= System_icall_indexes
;
258 indexes_size
= sizeof (System_icall_indexes
) / 4;
259 handles
= System_icall_handles
;
260 funcs
= System_icall_funcs
;
265 void *p
= bsearch (&token_idx
, indexes
, indexes_size
, 4, compare_int
);
268 printf ("wasm: Unable to lookup icall: %s\n", mono_method_get_name (method
));
272 uint32_t idx
= (int*)p
- indexes
;
273 *uses_handles
= handles
[idx
];
275 //printf ("ICALL: %s %x %d %d\n", methodname, token, idx, (int)(funcs [idx]));
282 icall_table_lookup_symbol (void *func
)
290 void mono_initialize_internals ()
292 mono_add_internal_call ("WebAssembly.Runtime::InvokeJS", mono_wasm_invoke_js
);
294 // Blazor specific custom routines - see dotnet_support.js for backing code
295 mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSMarshalled", mono_wasm_invoke_js_marshalled
);
296 mono_add_internal_call ("WebAssembly.JSInterop.InternalCalls::InvokeJSUnmarshalled", mono_wasm_invoke_js_unmarshalled
);
299 core_initialize_internals();
304 EMSCRIPTEN_KEEPALIVE
void
305 mono_wasm_load_runtime (const char *managed_path
, int enable_debugging
)
307 monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0);
308 monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0);
310 mono_dl_fallback_register (wasm_dl_load
, wasm_dl_symbol
, NULL
, NULL
);
313 // Defined in driver-gen.c
314 register_aot_modules ();
315 #ifdef EE_MODE_LLVMONLY_INTERP
316 mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY_INTERP
);
318 mono_jit_set_aot_mode (MONO_AOT_MODE_LLVMONLY
);
321 mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_LLVMONLY
);
322 if (enable_debugging
)
323 mono_wasm_enable_debugging ();
327 /* Link in our own linked icall table */
328 static const MonoIcallTableCallbacks mono_icall_table_callbacks
=
330 MONO_ICALL_TABLE_CALLBACKS_VERSION
,
332 icall_table_lookup_symbol
334 mono_install_icall_table_callbacks (&mono_icall_table_callbacks
);
337 #ifdef NEED_NORMAL_ICALL_TABLES
338 mono_icall_table_init ();
341 mono_ee_interp_init ("");
342 mono_marshal_ilgen_init ();
343 mono_method_builder_ilgen_init ();
344 mono_sgen_mono_ilgen_init ();
347 if (assembly_count
) {
348 MonoBundledAssembly
**bundle_array
= g_new0 (MonoBundledAssembly
*, assembly_count
+ 1);
349 WasmAssembly
*cur
= assemblies
;
352 bundle_array
[i
] = &cur
->assembly
;
356 mono_register_bundled_assemblies ((const MonoBundledAssembly
**)bundle_array
);
360 mono_trace_set_log_handler (wasm_logger
, NULL
);
361 root_domain
= mono_jit_init_version ("mono", "v4.0.30319");
363 mono_initialize_internals();
366 EMSCRIPTEN_KEEPALIVE MonoAssembly
*
367 mono_wasm_assembly_load (const char *name
)
369 MonoImageOpenStatus status
;
370 MonoAssemblyName
* aname
= mono_assembly_name_new (name
);
374 MonoAssembly
*res
= mono_assembly_load (aname
, NULL
, &status
);
375 mono_assembly_name_free (aname
);
380 EMSCRIPTEN_KEEPALIVE MonoClass
*
381 mono_wasm_assembly_find_class (MonoAssembly
*assembly
, const char *namespace, const char *name
)
383 return mono_class_from_name (mono_assembly_get_image (assembly
), namespace, name
);
386 EMSCRIPTEN_KEEPALIVE MonoMethod
*
387 mono_wasm_assembly_find_method (MonoClass
*klass
, const char *name
, int arguments
)
389 return mono_class_get_method_from_name (klass
, name
, arguments
);
392 EMSCRIPTEN_KEEPALIVE MonoObject
*
393 mono_wasm_invoke_method (MonoMethod
*method
, MonoObject
*this_arg
, void *params
[], int* got_exception
)
395 MonoObject
*exc
= NULL
;
396 MonoObject
*res
= mono_runtime_invoke (method
, this_arg
, params
, &exc
);
402 MonoObject
*exc2
= NULL
;
403 res
= (MonoObject
*)mono_object_to_string (exc
, &exc2
);
405 res
= (MonoObject
*) mono_string_new (root_domain
, "Exception Double Fault");
409 MonoMethodSignature
*sig
= mono_method_signature (method
);
410 MonoType
*type
= mono_signature_get_return_type (sig
);
411 // If the method return type is void return null
412 // This gets around a memory access crash when the result return a value when
413 // a void method is invoked.
414 if (mono_type_get_type (type
) == MONO_TYPE_VOID
)
420 EMSCRIPTEN_KEEPALIVE MonoMethod
*
421 mono_wasm_assembly_get_entry_point (MonoAssembly
*assembly
)
426 image
= mono_assembly_get_image (assembly
);
427 uint32_t entry
= mono_image_get_entry_point (image
);
431 return mono_get_method (image
, entry
, NULL
);
434 EMSCRIPTEN_KEEPALIVE
char *
435 mono_wasm_string_get_utf8 (MonoString
*str
)
437 return mono_string_to_utf8 (str
); //XXX JS is responsible for freeing this
440 EMSCRIPTEN_KEEPALIVE MonoString
*
441 mono_wasm_string_from_js (const char *str
)
443 return mono_string_new (root_domain
, str
);
447 class_is_task (MonoClass
*klass
)
449 if (!strcmp ("System.Threading.Tasks", mono_class_get_namespace (klass
)) &&
450 (!strcmp ("Task", mono_class_get_name (klass
)) || !strcmp ("Task`1", mono_class_get_name (klass
))))
456 #define MARSHAL_TYPE_INT 1
457 #define MARSHAL_TYPE_FP 2
458 #define MARSHAL_TYPE_STRING 3
459 #define MARSHAL_TYPE_VT 4
460 #define MARSHAL_TYPE_DELEGATE 5
461 #define MARSHAL_TYPE_TASK 6
462 #define MARSHAL_TYPE_OBJECT 7
463 #define MARSHAL_TYPE_BOOL 8
464 #define MARSHAL_TYPE_ENUM 9
465 #define MARSHAL_TYPE_DATE 20
466 #define MARSHAL_TYPE_DATEOFFSET 21
468 // typed array marshalling
469 #define MARSHAL_ARRAY_BYTE 11
470 #define MARSHAL_ARRAY_UBYTE 12
471 #define MARSHAL_ARRAY_SHORT 13
472 #define MARSHAL_ARRAY_USHORT 14
473 #define MARSHAL_ARRAY_INT 15
474 #define MARSHAL_ARRAY_UINT 16
475 #define MARSHAL_ARRAY_FLOAT 17
476 #define MARSHAL_ARRAY_DOUBLE 18
478 EMSCRIPTEN_KEEPALIVE
int
479 mono_wasm_get_obj_type (MonoObject
*obj
)
485 datetime_class
= mono_class_from_name (mono_get_corlib(), "System", "DateTime");
486 if (!datetimeoffset_class
)
487 datetimeoffset_class
= mono_class_from_name (mono_get_corlib(), "System", "DateTimeOffset");
489 MonoClass
*klass
= mono_object_get_class (obj
);
490 MonoType
*type
= mono_class_get_type (klass
);
492 switch (mono_type_get_type (type
)) {
493 // case MONO_TYPE_CHAR: prob should be done not as a number?
494 case MONO_TYPE_BOOLEAN
:
495 return MARSHAL_TYPE_BOOL
;
504 case MONO_TYPE_I
: // IntPtr
505 return MARSHAL_TYPE_INT
;
508 return MARSHAL_TYPE_FP
;
509 case MONO_TYPE_STRING
:
510 return MARSHAL_TYPE_STRING
;
511 case MONO_TYPE_SZARRAY
: { // simple zero based one-dim-array
512 MonoClass
*eklass
= mono_class_get_element_class(klass
);
513 MonoType
*etype
= mono_class_get_type (eklass
);
515 switch (mono_type_get_type (etype
)) {
517 return MARSHAL_ARRAY_UBYTE
;
519 return MARSHAL_ARRAY_BYTE
;
521 return MARSHAL_ARRAY_USHORT
;
523 return MARSHAL_ARRAY_SHORT
;
525 return MARSHAL_ARRAY_UINT
;
527 return MARSHAL_ARRAY_INT
;
529 return MARSHAL_ARRAY_FLOAT
;
531 return MARSHAL_ARRAY_DOUBLE
;
533 return MARSHAL_TYPE_OBJECT
;
537 if (klass
== datetime_class
)
538 return MARSHAL_TYPE_DATE
;
539 if (klass
== datetimeoffset_class
)
540 return MARSHAL_TYPE_DATEOFFSET
;
541 if (mono_class_is_enum (klass
))
542 return MARSHAL_TYPE_ENUM
;
543 if (!mono_type_is_reference (type
)) //vt
544 return MARSHAL_TYPE_VT
;
545 if (mono_class_is_delegate (klass
))
546 return MARSHAL_TYPE_DELEGATE
;
547 if (class_is_task(klass
))
548 return MARSHAL_TYPE_TASK
;
550 return MARSHAL_TYPE_OBJECT
;
554 EMSCRIPTEN_KEEPALIVE
int
555 mono_unbox_int (MonoObject
*obj
)
559 MonoType
*type
= mono_class_get_type (mono_object_get_class(obj
));
561 void *ptr
= mono_object_unbox (obj
);
562 switch (mono_type_get_type (type
)) {
564 case MONO_TYPE_BOOLEAN
:
565 return *(signed char*)ptr
;
567 return *(unsigned char*)ptr
;
571 return *(unsigned short*)ptr
;
576 return *(unsigned int*)ptr
;
577 // WASM doesn't support returning longs to JS
578 // case MONO_TYPE_I8:
579 // case MONO_TYPE_U8:
581 printf ("Invalid type %d to mono_unbox_int\n", mono_type_get_type (type
));
586 EMSCRIPTEN_KEEPALIVE
double
587 mono_wasm_unbox_float (MonoObject
*obj
)
591 MonoType
*type
= mono_class_get_type (mono_object_get_class(obj
));
593 void *ptr
= mono_object_unbox (obj
);
594 switch (mono_type_get_type (type
)) {
598 return *(double*)ptr
;
600 printf ("Invalid type %d to mono_wasm_unbox_float\n", mono_type_get_type (type
));
605 EMSCRIPTEN_KEEPALIVE
int
606 mono_wasm_array_length (MonoArray
*array
)
608 return mono_array_length (array
);
611 EMSCRIPTEN_KEEPALIVE MonoObject
*
612 mono_wasm_array_get (MonoArray
*array
, int idx
)
614 return mono_array_get (array
, MonoObject
*, idx
);
617 EMSCRIPTEN_KEEPALIVE MonoArray
*
618 mono_wasm_obj_array_new (int size
)
620 return mono_array_new (root_domain
, mono_get_object_class (), size
);
623 EMSCRIPTEN_KEEPALIVE
void
624 mono_wasm_obj_array_set (MonoArray
*array
, int idx
, MonoObject
*obj
)
626 mono_array_setref (array
, idx
, obj
);
629 EMSCRIPTEN_KEEPALIVE MonoArray
*
630 mono_wasm_string_array_new (int size
)
632 return mono_array_new (root_domain
, mono_get_string_class (), size
);
635 EMSCRIPTEN_KEEPALIVE
int
636 mono_wasm_exec_regression (int verbose_level
, char *image
)
638 return mono_regression_test_step (verbose_level
, image
, NULL
) ? 0 : 1;
641 EMSCRIPTEN_KEEPALIVE
int
642 mono_wasm_exit (int exit_code
)
647 EMSCRIPTEN_KEEPALIVE
void
648 mono_wasm_set_main_args (int argc
, char* argv
[])
650 mono_runtime_set_main_args (argc
, argv
);
653 EMSCRIPTEN_KEEPALIVE
int
654 mono_wasm_strdup (const char *s
)
656 return (int)strdup (s
);
659 EMSCRIPTEN_KEEPALIVE
void
660 mono_wasm_parse_runtime_options (int argc
, char* argv
[])
662 mono_jit_parse_options (argc
, argv
);
665 EMSCRIPTEN_KEEPALIVE
void
666 mono_wasm_enable_on_demand_gc (void)
668 mono_wasm_enable_gc
= 1;