[wasm] Add basic interpreter support for WebAssembly.
authorRodrigo Kumpera <kumpera@gmail.com>
Tue, 22 Aug 2017 23:52:56 +0000 (16:52 -0700)
committerRodrigo Kumpera <kumpera@gmail.com>
Wed, 23 Aug 2017 23:05:01 +0000 (16:05 -0700)
mono/mini/aot-runtime-wasm.c
mono/mini/interp/interp.c
mono/mini/interp/interp.h

index 7025fa8173d5fce3b5f093902ea78f4588913d23..4fb8906941cb2debcb65916bc9beb051db1101a0 100644 (file)
@@ -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
index fccce6b3411211e47139f783249bb0032de10225..42b91954fcf2c223e6c66a23fd404544ff3cb88b 100644 (file)
@@ -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++;
 
index 6abf93a6f0a38c900820258f6b73859f2b35d048..42198d92193fa81bec29b67d47c4d6325364fd62 100644 (file)
@@ -6,8 +6,13 @@
 #define __MONO_MINI_INTERPRETER_H__
 #include <mono/mini/mini.h>
 
+#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;