[wasm] Add basic interpreter support for WebAssembly.
[mono.git] / mono / mini / interp / interp.c
index fdbbe262ba4f2bb6d3e0fb1b6617b0a84511abdf..42b91954fcf2c223e6c66a23fd404544ff3cb88b 100644 (file)
@@ -390,8 +390,9 @@ get_virtual_method (InterpMethod *imethod, MonoObject *obj)
 }
 
 static void inline
-stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvoke)
+stackval_from_data (MonoType *type_, stackval *result, char *data, gboolean pinvoke)
 {
+       MonoType *type = mini_native_type_replace_type (type_);
        if (type->byref) {
                switch (type->type) {
                case MONO_TYPE_OBJECT:
@@ -479,8 +480,9 @@ stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvo
 }
 
 static void inline
-stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke)
+stackval_to_data (MonoType *type_, stackval *val, char *data, gboolean pinvoke)
 {
+       MonoType *type = mini_native_type_replace_type (type_);
        if (type->byref) {
                gpointer *p = (gpointer*)data;
                *p = val->data.p;
@@ -793,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++;
 
@@ -2330,6 +2336,9 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign
                MINT_IN_CASE(MINT_NOP)
                        ++ip;
                        MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_NIY)
+                       g_error ("mint_niy: instruction not implemented yet.  This shouldn't happen.");
+                       MINT_IN_BREAK;
                MINT_IN_CASE(MINT_BREAK)
                        ++ip;
                        do_debugger_tramp (mono_debugger_agent_user_break, frame);
@@ -2436,6 +2445,10 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign
                }
                MINT_IN_CASE(MINT_JMP) {
                        InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
+
+                       if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
+                               MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
+
                        if (!new_method->transformed) {
                                frame->ip = ip;
                                frame->ex = mono_interp_transform_method (new_method, context);
@@ -3609,6 +3622,15 @@ array_constructed:
                        ++sp;
                        MINT_IN_BREAK;
                }
+               MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
+                       guint32 token;
+
+                       frame->ip = ip;
+                       token = * (guint16 *)(ip + 1);
+                       ip += 2;
+
+                       MINT_IN_BREAK;
+               }
                MINT_IN_CASE(MINT_CASTCLASS)
                        c = rtm->data_items [*(guint16 *)(ip + 1)];
                        if ((o = sp [-1].data.p)) {
@@ -3954,7 +3976,7 @@ array_constructed:
                        c = rtm->data_items [* (guint16 *)(ip + 1)];
                        guint16 offset = * (guint16 *)(ip + 2);
 
-                       if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
+                       if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype && !(mono_class_is_magic_int (c) || mono_class_is_magic_float (c))) {
                                int size = mono_class_value_size (c, NULL);
                                sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
@@ -4590,6 +4612,15 @@ array_constructed:
        --sp; \
        sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
        ++ip;
+
+#define RELOP_FP(datamem, op, noorder) \
+       --sp; \
+       if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
+               sp [-1].data.i = noorder; \
+       else \
+               sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
+       ++ip;
+
                MINT_IN_CASE(MINT_CEQ_I4)
                        RELOP(i, ==);
                        MINT_IN_BREAK;
@@ -4601,12 +4632,16 @@ array_constructed:
                        RELOP(l, ==);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CEQ_R8)
-                       --sp; 
-                       if (isunordered (sp [-1].data.f, sp [0].data.f))
-                               sp [-1].data.i = 0;
-                       else
-                               sp [-1].data.i = sp [-1].data.f == sp [0].data.f;
-                       ++ip;
+                       RELOP_FP(f, ==, 0);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CNE_I4)
+                       RELOP(i, !=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CNE_I8)
+                       RELOP(l, !=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CNE_R8)
+                       RELOP_FP(f, !=, 0);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CGT_I4)
                        RELOP(i, >);
@@ -4615,12 +4650,16 @@ array_constructed:
                        RELOP(l, >);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CGT_R8)
-                       --sp; 
-                       if (isunordered (sp [-1].data.f, sp [0].data.f))
-                               sp [-1].data.i = 0;
-                       else
-                               sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
-                       ++ip;
+                       RELOP_FP(f, >, 0);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGE_I4)
+                       RELOP(i, >=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGE_I8)
+                       RELOP(l, >=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGE_R8)
+                       RELOP_FP(f, >=, 0);
                        MINT_IN_BREAK;
 
 #define RELOP_CAST(datamem, op, type) \
@@ -4628,6 +4667,13 @@ array_constructed:
        sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
        ++ip;
 
+               MINT_IN_CASE(MINT_CGE_UN_I4)
+                       RELOP_CAST(l, >=, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CGE_UN_I8)
+                       RELOP_CAST(l, >=, guint64);
+                       MINT_IN_BREAK;
+
                MINT_IN_CASE(MINT_CGT_UN_I4)
                        RELOP_CAST(i, >, guint32);
                        MINT_IN_BREAK;
@@ -4635,12 +4681,7 @@ array_constructed:
                        RELOP_CAST(l, >, guint64);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CGT_UN_R8)
-                       --sp; 
-                       if (isunordered (sp [-1].data.f, sp [0].data.f))
-                               sp [-1].data.i = 1;
-                       else
-                               sp [-1].data.i = sp [-1].data.f > sp [0].data.f;
-                       ++ip;
+                       RELOP_FP(f, >, 1);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CLT_I4)
                        RELOP(i, <);
@@ -4649,12 +4690,7 @@ array_constructed:
                        RELOP(l, <);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CLT_R8)
-                       --sp; 
-                       if (isunordered (sp [-1].data.f, sp [0].data.f))
-                               sp [-1].data.i = 0;
-                       else
-                               sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
-                       ++ip;
+                       RELOP_FP(f, <, 0);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CLT_UN_I4)
                        RELOP_CAST(i, <, guint32);
@@ -4663,13 +4699,28 @@ array_constructed:
                        RELOP_CAST(l, <, guint64);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CLT_UN_R8)
-                       --sp; 
-                       if (isunordered (sp [-1].data.f, sp [0].data.f))
-                               sp [-1].data.i = 1;
-                       else
-                               sp [-1].data.i = sp [-1].data.f < sp [0].data.f;
-                       ++ip;
+                       RELOP_FP(f, <, 1);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLE_I4)
+                       RELOP(i, <=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLE_I8)
+                       RELOP(l, <=);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLE_UN_I4)
+                       RELOP_CAST(l, <=, guint32);
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLE_UN_I8)
+                       RELOP_CAST(l, <=, guint64);
                        MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CLE_R8)
+                       RELOP_FP(f, <=, 0);
+                       MINT_IN_BREAK;
+
+#undef RELOP
+#undef RELOP_FP
+#undef RELOP_CAST
+
                MINT_IN_CASE(MINT_LDFTN) {
                        sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
                        ++sp;
@@ -4769,7 +4820,7 @@ array_constructed:
                        if (MONO_PROFILER_ENABLED (method_enter)) {
                                MonoProfilerCallContext *prof_ctx = NULL;
 
-                               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT) {
+                               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
                                        prof_ctx = g_new0 (MonoProfilerCallContext, 1);
                                        prof_ctx->interp_frame = frame;
                                        prof_ctx->method = frame->imethod->method;
@@ -5140,35 +5191,34 @@ die_on_ex:
        }
 exit_frame:
 
-       if (!frame->ex) {
-               if (MONO_PROFILER_ENABLED (method_leave) && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE) {
-                       MonoProfilerCallContext *prof_ctx = NULL;
-
-                       if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT) {
-                               prof_ctx = g_new0 (MonoProfilerCallContext, 1);
-                               prof_ctx->interp_frame = frame;
-                               prof_ctx->method = frame->imethod->method;
-
-                               MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
-
-                               switch (rtype->type) {
-                               case MONO_TYPE_VOID:
-                                       break;
-                               case MONO_TYPE_VALUETYPE:
-                                       prof_ctx->return_value = frame->retval->data.p;
-                                       break;
-                               default:
-                                       prof_ctx->return_value = frame->retval;
-                                       break;
-                               }
-                       }
+       if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
+           frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
+               MonoProfilerCallContext *prof_ctx = NULL;
+
+               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
+                       prof_ctx = g_new0 (MonoProfilerCallContext, 1);
+                       prof_ctx->interp_frame = frame;
+                       prof_ctx->method = frame->imethod->method;
 
-                       MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
+                       MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
 
-                       g_free (prof_ctx);
+                       switch (rtype->type) {
+                       case MONO_TYPE_VOID:
+                               break;
+                       case MONO_TYPE_VALUETYPE:
+                               prof_ctx->return_value = frame->retval->data.p;
+                               break;
+                       default:
+                               prof_ctx->return_value = frame->retval;
+                               break;
+                       }
                }
-       } else
-               MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, (MonoObject *) frame->ex));
+
+               MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
+
+               g_free (prof_ctx);
+       } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
+               MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
 
        DEBUG_LEAVE ();
 }