From ff9a538941152dcb16027129963562ede945296f Mon Sep 17 00:00:00 2001 From: Rodrigo Kumpera Date: Tue, 22 Aug 2017 16:52:56 -0700 Subject: [PATCH] [wasm] Add basic interpreter support for WebAssembly. --- mono/mini/aot-runtime-wasm.c | 326 ++++++++++++++++++++++++++++++++++- mono/mini/interp/interp.c | 4 + mono/mini/interp/interp.h | 8 + 3 files changed, 335 insertions(+), 3 deletions(-) diff --git a/mono/mini/aot-runtime-wasm.c b/mono/mini/aot-runtime-wasm.c index 7025fa8173d..4fb8906941c 100644 --- a/mono/mini/aot-runtime-wasm.c +++ b/mono/mini/aot-runtime-wasm.c @@ -42,11 +42,331 @@ wasm_throw_corlib_exception (void) g_error ("wasm_throw_corlib_exception"); } +static char +type_to_c (MonoType *t) +{ + if (t->byref) + return 'I'; + +handle_enum: + switch (t->type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + return 'I'; + case MONO_TYPE_R4: + return 'F'; + case MONO_TYPE_R8: + return 'D'; + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + return 'L'; + case MONO_TYPE_VOID: + return 'V'; + case MONO_TYPE_VALUETYPE: + if (t->data.klass->enumtype) { + t = mono_class_enum_basetype (t->data.klass); + goto handle_enum; + } + + return 'I'; + case MONO_TYPE_GENERICINST: + if (t->data.klass->valuetype) + return 'S'; + return 'I'; + default: + g_warning ("CANT TRANSLATE %s", mono_type_full_name (t)); + return 'X'; + } +} + +#if SIZEOF_VOID_P == 4 +#define FIDX(x) ((x) * 2) +#else +#define FIDX(x) (x) +#endif + static void -wasm_enter_icall_trampoline (void *target_func, InterpMethodArguments *margs) +wasm_invoke_v (void *target_func, InterpMethodArguments *margs) { - g_error ("wasm_enter_icall_trampoline"); + void (*func)(void) = target_func; + func (); +} + +static void +wasm_invoke_vi (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a) = target_func; + func (margs->iargs [0]); +} + +static void +wasm_invoke_vii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, gpointer b) = target_func; + func (margs->iargs [0], margs->iargs [1]); +} + +static void +wasm_invoke_viii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, gpointer b, gpointer c) = target_func; + func (margs->iargs [0], margs->iargs [1], margs->iargs [2]); +} + +static void +wasm_invoke_viiii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, gpointer b, gpointer c, gpointer d) = target_func; + func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3]); +} + +static void +wasm_invoke_viiiii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e) = target_func; + func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4]); +} + +static void +wasm_invoke_viiiiii (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e, gpointer f) = target_func; + func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4], margs->iargs [5]); +} + +static void +wasm_invoke_i (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(void) = target_func; + int res = func (); + *(int*)margs->retval = res; +} + +static void +wasm_invoke_ii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(gpointer a) = target_func; + int res = func (margs->iargs [0]); + *(int*)margs->retval = res; +} + +static void +wasm_invoke_iii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(gpointer a, gpointer b) = target_func; + int res = func (margs->iargs [0], margs->iargs [1]); + *(int*)margs->retval = res; +} + +static void +wasm_invoke_iiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(gpointer a, gpointer b, gpointer c) = target_func; + int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2]); + *(int*)margs->retval = res; +} + +static void +wasm_invoke_iiiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(gpointer a, gpointer b, gpointer c, gpointer d) = target_func; + int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3]); + *(int*)margs->retval = res; +} + +static void +wasm_invoke_iiiiii (void *target_func, InterpMethodArguments *margs) +{ + int (*func)(gpointer a, gpointer b, gpointer c, gpointer d, gpointer e) = target_func; + int res = func (margs->iargs [0], margs->iargs [1], margs->iargs [2], margs->iargs [3], margs->iargs [4]); + *(int*)margs->retval = res; +} + +typedef union { + gint64 l; + struct { + gint32 lo; + gint32 hi; + } pair; +} interp_pair; + +static void +wasm_invoke_ll (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(gint64 a) = target_func; + + interp_pair p; + p.pair.lo = (gint32)margs->iargs [0]; + p.pair.hi = (gint32)margs->iargs [1]; + + gint64 res = func (p.l); + *(gint64*)margs->retval = res; +} + +static void +wasm_invoke_li (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(gpointer a) = target_func; + gint64 res = func (margs->iargs [0]); + *(gint64*)margs->retval = res; +} + +static void +wasm_invoke_lil (void *target_func, InterpMethodArguments *margs) +{ + gint64 (*func)(gpointer a, gint64 b) = target_func; + + interp_pair p; + p.pair.lo = (gint32)margs->iargs [1]; + p.pair.hi = (gint32)margs->iargs [2]; + + gint64 res = func (margs->iargs [0], p.l); + *(gint64*)margs->retval = res; +} + +static void +wasm_invoke_dd (void *target_func, InterpMethodArguments *margs) +{ + double (*func)(double a) = target_func; + + double res = func (margs->fargs [FIDX (0)]); + *(double*)margs->retval = res; +} + +static void +wasm_invoke_ddd (void *target_func, InterpMethodArguments *margs) +{ + double (*func)(double a, double b) = target_func; + + double res = func (margs->fargs [FIDX (0)], margs->fargs [FIDX (1)]); + *(double*)margs->retval = res; +} + + +static void +wasm_invoke_vif (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, float b) = target_func; + + func (margs->iargs [0], + *(float*)&margs->fargs [FIDX (0)]); +} + +static void +wasm_invoke_viff (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, float b, float c) = target_func; + + func (margs->iargs [0], + *(float*)&margs->fargs [FIDX (0)], + *(float*)&margs->fargs [FIDX (1)]); +} + +static void +wasm_invoke_viffff (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, float b, float c, float d, float e) = target_func; + + func (margs->iargs [0], + *(float*)&margs->fargs [FIDX (0)], + *(float*)&margs->fargs [FIDX (1)], + *(float*)&margs->fargs [FIDX (2)], + *(float*)&margs->fargs [FIDX (3)]); +} + +static void +wasm_invoke_vifffffi (void *target_func, InterpMethodArguments *margs) +{ + void (*func)(gpointer a, float b, float c, float d, float e, float f, int g) = target_func; + + func (margs->iargs [0], + *(float*)&margs->fargs [FIDX (0)], + *(float*)&margs->fargs [FIDX (1)], + *(float*)&margs->fargs [FIDX (2)], + *(float*)&margs->fargs [FIDX (3)], + *(float*)&margs->fargs [FIDX (4)], + *(float*)&margs->iargs [1]); +} + +static void +wasm_enter_icall_trampoline (void *target_func, InterpMethodArguments *margs) +{ + static char cookie [8]; + static int c_count; + + MonoMethodSignature *sig = margs->sig; + + c_count = sig->param_count + sig->hasthis + 1; + cookie [0] = type_to_c (sig->ret); + if (sig->hasthis) + cookie [1] = 'I'; + for (int i = 0; i < sig->param_count; ++i) + cookie [1 + sig->hasthis + i ] = type_to_c (sig->params [i]); + cookie [c_count] = 0; + + if (!strcmp ("V", cookie)) + wasm_invoke_v (target_func, margs); + else if (!strcmp ("VI", cookie)) + wasm_invoke_vi (target_func, margs); + else if (!strcmp ("VII", cookie)) + wasm_invoke_vii (target_func, margs); + else if (!strcmp ("VIII", cookie)) + wasm_invoke_viii (target_func, margs); + else if (!strcmp ("VIIII", cookie)) + wasm_invoke_viiii (target_func, margs); + else if (!strcmp ("VIIIII", cookie)) + wasm_invoke_viiiii (target_func, margs); + else if (!strcmp ("VIIIIII", cookie)) + wasm_invoke_viiiiii (target_func, margs); + else if (!strcmp ("I", cookie)) + wasm_invoke_i (target_func, margs); + else if (!strcmp ("II", cookie)) + wasm_invoke_ii (target_func, margs); + else if (!strcmp ("III", cookie)) + wasm_invoke_iii (target_func, margs); + else if (!strcmp ("IIII", cookie)) + wasm_invoke_iiii (target_func, margs); + else if (!strcmp ("IIIII", cookie)) + wasm_invoke_iiiii (target_func, margs); + else if (!strcmp ("IIIIII", cookie)) + wasm_invoke_iiiiii (target_func, margs); + else if (!strcmp ("LL", cookie)) + wasm_invoke_ll (target_func, margs); + else if (!strcmp ("LI", cookie)) + wasm_invoke_li (target_func, margs); + else if (!strcmp ("LIL", cookie)) + wasm_invoke_lil (target_func, margs); + else if (!strcmp ("DD", cookie)) + wasm_invoke_dd (target_func, margs); + else if (!strcmp ("DDD", cookie)) + wasm_invoke_ddd (target_func, margs); + else if (!strcmp ("VIF", cookie)) + wasm_invoke_vif (target_func, margs); + else if (!strcmp ("VIFF", cookie)) + wasm_invoke_viff (target_func, margs); + else if (!strcmp ("VIFFFF", cookie)) + wasm_invoke_viffff (target_func, margs); + else if (!strcmp ("VIFFFFFI", cookie)) + wasm_invoke_vifffffi (target_func, margs); + else { + printf ("CANNOT HANDLE COOKIE %s\n", cookie); + g_assert (0); + } } gpointer @@ -85,4 +405,4 @@ mono_aot_get_trampoline_full (const char *name, MonoTrampInfo **out_tinfo) return code; } -#endif \ No newline at end of file +#endif diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index fccce6b3411..42b91954fcf 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -795,6 +795,10 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int int i8_align = mono_arm_i8_align (); #endif +#ifdef TARGET_WASM + margs->sig = sig; +#endif + if (sig->hasthis) margs->ilen++; diff --git a/mono/mini/interp/interp.h b/mono/mini/interp/interp.h index 6abf93a6f0a..42198d92193 100644 --- a/mono/mini/interp/interp.h +++ b/mono/mini/interp/interp.h @@ -6,8 +6,13 @@ #define __MONO_MINI_INTERPRETER_H__ #include +#ifdef TARGET_WASM +#define INTERP_ICALL_TRAMP_IARGS 12 +#define INTERP_ICALL_TRAMP_FARGS 12 +#else #define INTERP_ICALL_TRAMP_IARGS 12 #define INTERP_ICALL_TRAMP_FARGS 4 +#endif struct _InterpMethodArguments { size_t ilen; @@ -16,6 +21,9 @@ struct _InterpMethodArguments { double *fargs; gpointer *retval; size_t is_float_ret; +#ifdef TARGET_WASM + MonoMethodSignature *sig; +#endif }; typedef struct _InterpMethodArguments InterpMethodArguments; -- 2.25.1