[netcore] Implement missing Bmi1/Bmi2 intrinsics (#16919)
[mono-project.git] / mono / mini / mini-wasm.c
blob6840bec69aacd7162198e492ef356aa9f05db156
1 #include "mini.h"
2 #include "mini-runtime.h"
3 #include <mono/metadata/mono-debug.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/loader-internals.h>
7 #include <mono/metadata/icall-internals.h>
8 #include <mono/metadata/seq-points-data.h>
9 #include <mono/mini/aot-runtime.h>
10 #include <mono/mini/seq-points.h>
12 //XXX This is dirty, extend ee.h to support extracting info from MonoInterpFrameHandle
13 #include <mono/mini/interp/interp-internals.h>
15 #ifndef DISABLE_JIT
17 #include "ir-emit.h"
18 #include "cpu-wasm.h"
20 //FIXME figure out if we need to distingush between i,l,f,d types
21 typedef enum {
22 ArgOnStack,
23 ArgValuetypeAddrOnStack,
24 ArgGsharedVTOnStack,
25 ArgValuetypeAddrInIReg,
26 ArgInvalid,
27 } ArgStorage;
29 typedef struct {
30 ArgStorage storage : 8;
31 } ArgInfo;
33 struct CallInfo {
34 int nargs;
35 gboolean gsharedvt;
37 ArgInfo ret;
38 ArgInfo args [1];
41 static ArgStorage
42 get_storage (MonoType *type, gboolean is_return)
44 switch (type->type) {
45 case MONO_TYPE_I1:
46 case MONO_TYPE_U1:
47 case MONO_TYPE_I2:
48 case MONO_TYPE_U2:
49 case MONO_TYPE_I4:
50 case MONO_TYPE_U4:
51 case MONO_TYPE_I:
52 case MONO_TYPE_U:
53 case MONO_TYPE_PTR:
54 case MONO_TYPE_FNPTR:
55 case MONO_TYPE_OBJECT:
56 return ArgOnStack;
58 case MONO_TYPE_U8:
59 case MONO_TYPE_I8:
60 return ArgOnStack;
62 case MONO_TYPE_R4:
63 return ArgOnStack;
65 case MONO_TYPE_R8:
66 return ArgOnStack;
68 case MONO_TYPE_GENERICINST:
69 if (!mono_type_generic_inst_is_valuetype (type))
70 return ArgOnStack;
72 if (mini_is_gsharedvt_type (type)) {
73 return ArgGsharedVTOnStack;
75 /* fall through */
76 case MONO_TYPE_VALUETYPE:
77 case MONO_TYPE_TYPEDBYREF: {
78 return is_return ? ArgValuetypeAddrInIReg : ArgValuetypeAddrOnStack;
79 break;
81 case MONO_TYPE_VAR:
82 case MONO_TYPE_MVAR:
83 g_assert (mini_is_gsharedvt_type (type));
84 return ArgGsharedVTOnStack;
85 break;
86 case MONO_TYPE_VOID:
87 g_assert (is_return);
88 break;
89 default:
90 g_error ("Can't handle as return value 0x%x", type->type);
92 return ArgInvalid;
95 static CallInfo*
96 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
98 int n = sig->hasthis + sig->param_count;
99 CallInfo *cinfo;
101 if (mp)
102 cinfo = (CallInfo *)mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
103 else
104 cinfo = (CallInfo *)g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
106 cinfo->nargs = n;
107 cinfo->gsharedvt = mini_is_gsharedvt_variable_signature (sig);
109 /* return value */
110 cinfo->ret.storage = get_storage (mini_get_underlying_type (sig->ret), TRUE);
112 if (sig->hasthis)
113 cinfo->args [0].storage = ArgOnStack;
115 // not supported
116 g_assert (sig->call_convention != MONO_CALL_VARARG);
118 int i;
119 for (i = 0; i < sig->param_count; ++i)
120 cinfo->args [i + sig->hasthis].storage = get_storage (mini_get_underlying_type (sig->params [i]), FALSE);
122 return cinfo;
125 gboolean
126 mono_arch_have_fast_tls (void)
128 return FALSE;
131 guint32
132 mono_arch_get_patch_offset (guint8 *code)
134 g_error ("mono_arch_get_patch_offset");
135 return 0;
137 gpointer
138 mono_arch_ip_from_context (void *sigctx)
140 g_error ("mono_arch_ip_from_context");
143 gboolean
144 mono_arch_is_inst_imm (int opcode, int imm_opcode, gint64 imm)
146 return TRUE;
149 void
150 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
154 gboolean
155 mono_arch_opcode_supported (int opcode)
157 return FALSE;
160 void
161 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
163 g_error ("mono_arch_output_basic_block");
166 void
167 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
171 void
172 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
176 guint32
177 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
179 return 0;
182 GList *
183 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
185 g_error ("mono_arch_get_allocatable_int_vars");
188 GList *
189 mono_arch_get_global_int_regs (MonoCompile *cfg)
191 g_error ("mono_arch_get_global_int_regs");
194 void
195 mono_arch_allocate_vars (MonoCompile *cfg)
197 g_error ("mono_arch_allocate_vars");
200 void
201 mono_arch_create_vars (MonoCompile *cfg)
203 MonoMethodSignature *sig;
204 CallInfo *cinfo;
205 MonoType *sig_ret;
207 sig = mono_method_signature_internal (cfg->method);
209 if (!cfg->arch.cinfo)
210 cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
211 cinfo = (CallInfo *)cfg->arch.cinfo;
213 // if (cinfo->ret.storage == ArgValuetypeInReg)
214 // cfg->ret_var_is_local = TRUE;
216 sig_ret = mini_get_underlying_type (sig->ret);
217 if (cinfo->ret.storage == ArgValuetypeAddrInIReg || cinfo->ret.storage == ArgGsharedVTOnStack) {
218 cfg->vret_addr = mono_compile_create_var (cfg, mono_get_int_type (), OP_ARG);
219 if (G_UNLIKELY (cfg->verbose_level > 1)) {
220 printf ("vret_addr = ");
221 mono_print_ins (cfg->vret_addr);
225 if (cfg->gen_sdb_seq_points)
226 g_error ("gen_sdb_seq_points not supported");
228 if (cfg->method->save_lmf)
229 cfg->create_lmf_var = TRUE;
231 if (cfg->method->save_lmf)
232 cfg->lmf_ir = TRUE;
235 void
236 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
238 g_error ("mono_arch_emit_call");
241 void
242 mono_arch_emit_epilog (MonoCompile *cfg)
244 g_error ("mono_arch_emit_epilog");
247 void
248 mono_arch_emit_exceptions (MonoCompile *cfg)
250 g_error ("mono_arch_emit_exceptions");
253 MonoInst*
254 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
256 return NULL;
259 void
260 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
262 g_error ("mono_arch_emit_outarg_vt");
265 guint8 *
266 mono_arch_emit_prolog (MonoCompile *cfg)
268 g_error ("mono_arch_emit_prolog");
271 void
272 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
274 MonoType *ret = mini_get_underlying_type (mono_method_signature_internal (method)->ret);
276 if (!ret->byref) {
277 if (ret->type == MONO_TYPE_R4) {
278 MONO_EMIT_NEW_UNALU (cfg, cfg->r4fp ? OP_RMOVE : OP_FMOVE, cfg->ret->dreg, val->dreg);
279 return;
280 } else if (ret->type == MONO_TYPE_R8) {
281 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
282 return;
283 } else if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
284 MONO_EMIT_NEW_UNALU (cfg, OP_LMOVE, cfg->ret->dreg, val->dreg);
285 return;
288 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
291 void
292 mono_arch_flush_icache (guint8 *code, gint size)
296 LLVMCallInfo*
297 mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
299 int i, n;
300 CallInfo *cinfo;
301 LLVMCallInfo *linfo;
303 cinfo = get_call_info (cfg->mempool, sig);
304 n = cinfo->nargs;
306 linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
308 if (mini_type_is_vtype (sig->ret)) {
309 /* Vtype returned using a hidden argument */
310 linfo->ret.storage = LLVMArgVtypeRetAddr;
311 // linfo->vret_arg_index = cinfo->vret_arg_index;
312 } else {
313 if (sig->ret->type != MONO_TYPE_VOID)
314 linfo->ret.storage = LLVMArgNormal;
317 for (i = 0; i < n; ++i) {
318 ArgInfo *ainfo = &cinfo->args[i];
320 switch (ainfo->storage) {
321 case ArgOnStack:
322 linfo->args [i].storage = LLVMArgNormal;
323 break;
324 case ArgValuetypeAddrOnStack:
325 linfo->args [i].storage = LLVMArgVtypeByRef;
326 break;
327 case ArgGsharedVTOnStack:
328 linfo->args [i].storage = LLVMArgGsharedvtVariable;
329 break;
330 case ArgValuetypeAddrInIReg:
331 g_error ("this is only valid for sig->ret");
332 break;
336 return linfo;
339 gboolean
340 mono_arch_tailcall_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig, gboolean virtual_)
342 return FALSE;
345 #endif // DISABLE_JIT
347 const char*
348 mono_arch_fregname (int reg)
350 return "freg0";
353 const char*
354 mono_arch_regname (int reg)
356 return "r0";
360 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
362 g_error ("mono_arch_get_argument_info");
365 GSList*
366 mono_arch_get_delegate_invoke_impls (void)
368 g_error ("mono_arch_get_delegate_invoke_impls");
371 gpointer
372 mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli)
374 g_error ("mono_arch_get_gsharedvt_call_info");
375 return NULL;
378 gpointer
379 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
381 g_error ("mono_arch_get_delegate_invoke_impl");
384 #ifdef HOST_WASM
386 #include <emscripten.h>
388 //functions exported to be used by JS
389 G_BEGIN_DECLS
390 EMSCRIPTEN_KEEPALIVE void mono_set_timeout_exec (int id);
392 //JS functions imported that we use
393 extern void mono_set_timeout (int t, int d);
394 G_END_DECLS
396 #endif // HOST_WASM
398 gpointer
399 mono_arch_get_this_arg_from_call (host_mgreg_t *regs, guint8 *code)
401 g_error ("mono_arch_get_this_arg_from_call");
404 gpointer
405 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
407 g_error ("mono_arch_get_delegate_virtual_invoke_impl");
411 void
412 mono_arch_cpu_init (void)
414 // printf ("mono_arch_cpu_init\n");
417 void
418 mono_arch_finish_init (void)
420 // printf ("mono_arch_finish_init\n");
423 void
424 mono_arch_init (void)
426 // printf ("mono_arch_init\n");
429 void
430 mono_arch_cleanup (void)
434 void
435 mono_arch_register_lowlevel_calls (void)
439 void
440 mono_arch_flush_register_windows (void)
444 MonoMethod*
445 mono_arch_find_imt_method (host_mgreg_t *regs, guint8 *code)
447 g_error ("mono_arch_find_static_call_vtable");
448 return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
451 MonoVTable*
452 mono_arch_find_static_call_vtable (host_mgreg_t *regs, guint8 *code)
454 g_error ("mono_arch_find_static_call_vtable");
455 return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
458 gpointer
459 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count, gpointer fail_tramp)
461 g_error ("mono_arch_build_imt_trampoline");
464 guint32
465 mono_arch_cpu_enumerate_simd_versions (void)
467 return 0;
470 guint32
471 mono_arch_cpu_optimizations (guint32 *exclude_mask)
473 /* No arch specific passes yet */
474 *exclude_mask = 0;
475 return 0;
478 host_mgreg_t
479 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
481 g_error ("mono_arch_context_get_int_reg");
482 return 0;
485 #ifdef HOST_WASM
487 void
488 mono_runtime_setup_stat_profiler (void)
490 g_error ("mono_runtime_setup_stat_profiler");
494 void
495 mono_runtime_shutdown_stat_profiler (void)
497 g_error ("mono_runtime_shutdown_stat_profiler");
501 gboolean
502 MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal)
504 g_error ("mono_chain_signal");
506 return FALSE;
509 void
510 mono_runtime_install_handlers (void)
514 void
515 mono_runtime_cleanup_handlers (void)
519 void
520 mono_init_native_crash_info (void)
522 return;
525 void
526 mono_cleanup_native_crash_info (void)
528 return;
531 gboolean
532 mono_thread_state_init_from_handle (MonoThreadUnwindState *tctx, MonoThreadInfo *info, void *sigctx)
534 g_error ("WASM systems don't support mono_thread_state_init_from_handle");
535 return FALSE;
538 EMSCRIPTEN_KEEPALIVE void
539 mono_set_timeout_exec (int id)
541 ERROR_DECL (error);
542 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System.Threading", "WasmRuntime");
543 g_assert (klass);
545 MonoMethod *method = mono_class_get_method_from_name_checked (klass, "TimeoutCallback", -1, 0, error);
546 mono_error_assert_ok (error);
547 g_assert (method);
549 gpointer params[1] = { &id };
550 MonoObject *exc = NULL;
552 mono_runtime_try_invoke (method, NULL, params, &exc, error);
554 //YES we swallow exceptions cuz there's nothing much we can do from here.
555 //FIXME Maybe call the unhandled exception function?
556 if (!is_ok (error)) {
557 printf ("timeout callback failed due to %s\n", mono_error_get_message (error));
558 mono_error_cleanup (error);
561 if (exc) {
562 char *type_name = mono_type_get_full_name (mono_object_class (exc));
563 printf ("timeout callback threw a %s\n", type_name);
564 g_free (type_name);
568 #endif
570 void
571 mono_wasm_set_timeout (int timeout, int id)
573 #ifdef HOST_WASM
574 mono_set_timeout (timeout, id);
575 #endif
578 void
579 mono_arch_register_icall (void)
581 mono_add_internal_call_internal ("System.Threading.WasmRuntime::SetTimeout", mono_wasm_set_timeout);
584 void
585 mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
587 g_error ("mono_arch_patch_code_new");
590 #ifdef HOST_WASM
593 The following functions don't belong here, but are due to laziness.
595 gboolean mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize);
597 G_BEGIN_DECLS
599 void * getgrnam (const char *name);
600 void * getgrgid (gid_t gid);
601 int inotify_init (void);
602 int inotify_rm_watch (int fd, int wd);
603 int inotify_add_watch (int fd, const char *pathname, uint32_t mask);
604 int sem_timedwait (sem_t *sem, const struct timespec *abs_timeout);
606 G_END_DECLS
608 //w32file-wasm.c
609 gboolean
610 mono_w32file_get_file_system_type (const gunichar2 *path, gunichar2 *fsbuffer, gint fsbuffersize)
612 glong len;
613 gboolean status = FALSE;
615 gunichar2 *ret = g_utf8_to_utf16 ("memfs", -1, NULL, &len, NULL);
616 if (ret != NULL && len < fsbuffersize) {
617 memcpy (fsbuffer, ret, len * sizeof (gunichar2));
618 fsbuffer [len] = 0;
619 status = TRUE;
621 if (ret != NULL)
622 g_free (ret);
624 return status;
627 G_BEGIN_DECLS
629 //llvm builtin's that we should not have used in the first place
631 #include <sys/types.h>
632 #include <pwd.h>
633 #include <uuid/uuid.h>
635 #ifndef __EMSCRIPTEN_PTHREADS__
636 int pthread_getschedparam (pthread_t thread, int *policy, struct sched_param *param)
638 g_error ("pthread_getschedparam");
639 return 0;
641 #endif
644 pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
646 return 0;
650 pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
652 return 0;
657 sigsuspend(const sigset_t *sigmask)
659 g_error ("sigsuspend");
660 return 0;
664 getdtablesize (void)
666 return 256; //random constant that is the fd limit
669 void *
670 getgrnam (const char *name)
672 return NULL;
675 void *
676 getgrgid (gid_t gid)
678 return NULL;
682 inotify_init (void)
684 g_error ("inotify_init");
688 inotify_rm_watch (int fd, int wd)
690 g_error ("inotify_rm_watch");
691 return 0;
695 inotify_add_watch (int fd, const char *pathname, uint32_t mask)
697 g_error ("inotify_add_watch");
698 return 0;
701 #ifndef __EMSCRIPTEN_PTHREADS__
703 sem_timedwait (sem_t *sem, const struct timespec *abs_timeout)
705 g_error ("sem_timedwait");
706 return 0;
708 #endif
710 ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
712 ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
714 g_error ("sendfile");
715 return 0;
719 getpwnam_r (const char *name, struct passwd *pwd, char *buffer, size_t bufsize,
720 struct passwd **result)
722 g_error ("getpwnam_r");
723 return 0;
727 getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
728 struct passwd **result)
730 g_error ("getpwuid_r");
731 return 0;
734 G_END_DECLS
736 #endif // HOST_WASM
738 gpointer
739 mono_arch_load_function (MonoJitICallId jit_icall_id)
741 return NULL;