[interp] support stelem for g{,u}int64
[mono.git] / mono / mini / interp / transform.c
index cc75a0acb7d73674877ca682bea85cc7a16f98ed..02f08681544190f321d7b80d526a97261d1c7acf 100644 (file)
@@ -784,11 +784,6 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
                        for (i = csignature->param_count - 1; i >= 0; --i)
                                store_arg (td, i + csignature->hasthis);
 
-                       if (csignature->hasthis) {
-                               g_error ("STTHIS removal");
-                               // ADD_CODE(td, MINT_STTHIS);
-                               --td->sp;
-                       }
                        ADD_CODE(td, MINT_BR_S);
                        offset = body_start_offset - ((td->new_ip - 1) - td->new_code);
                        ADD_CODE(td, offset);
@@ -934,7 +929,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        td.new_ip = td.new_code;
        td.last_new_ip = NULL;
 
-       td.stack = g_malloc0(header->max_stack * sizeof(td.stack[0]));
+       td.stack = g_malloc0 ((header->max_stack + 1) * sizeof (td.stack [0]));
        td.sp = td.stack;
        td.max_stack_height = 0;
 
@@ -1368,28 +1363,35 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        unsigned short *next_new_ip;
                        ++td.ip;
                        n = read32 (td.ip);
-                       ADD_CODE(&td, MINT_SWITCH);
-                       ADD_CODE(&td, * (unsigned short *)(&n));
-                       ADD_CODE(&td, * ((unsigned short *)&n + 1));
+                       ADD_CODE (&td, MINT_SWITCH);
+                       WRITE32 (&td, &n);
                        td.ip += 4;
                        next_ip = td.ip + n * 4;
                        next_new_ip = td.new_ip + n * 2;
+                       --td.sp;
+                       int stack_height = td.sp - td.stack;
                        for (i = 0; i < n; i++) {
                                offset = read32 (td.ip);
                                target = next_ip - td.il_code + offset;
-                               if (offset < 0)
+                               if (offset < 0) {
+#if DEBUG_INTERP
+                                       if (stack_height > 0 && stack_height != td.stack_height [target])
+                                               g_warning ("SWITCH with back branch and non-empty stack");
+#endif
                                        target = td.in_offsets [target] - (next_new_ip - td.new_code);
-                               else {
+                               } else {
+                                       td.stack_height [target] = stack_height;
+                                       td.vt_stack_size [target] = td.vt_sp;
+                                       if (stack_height > 0)
+                                               td.stack_state [target] = g_memdup (td.stack, stack_height * sizeof (td.stack [0]));
                                        int prev = td.forward_refs [target];
                                        td.forward_refs [td.ip - td.il_code] = prev;
                                        td.forward_refs [target] = td.ip - td.il_code;
                                        td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code);
                                }
-                               ADD_CODE(&td, * (unsigned short *)(&target));
-                               ADD_CODE(&td, * ((unsigned short *)&target + 1));
+                               WRITE32 (&td, &target);
                                td.ip += 4;
                        }
-                       --td.sp;
                        break;
                }
                case CEE_LDIND_I1:
@@ -1957,7 +1959,10 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        klass = mono_class_get_full (image, token, generic_context);
 
                        if (mini_type_is_reference (&klass->byval_arg)) {
-                               g_error ("unbox_any: generic class is reference type");
+                               ADD_CODE (&td, MINT_CASTCLASS);
+                               ADD_CODE (&td, get_data_item_index (&td, klass));
+                               SET_TYPE (td.sp - 1, stack_type [mt], klass);
+                               td.ip += 5;
                        } else if (mono_class_is_nullable (klass)) {
                                MonoMethod *target_method = mono_class_get_method_from_name (klass, "Unbox", 1);
                                /* td.ip is incremented by interp_transform_call */
@@ -1997,7 +2002,12 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                ADD_CODE (&td, MINT_LDSFLDA);
                                ADD_CODE (&td, get_data_item_index (&td, field));
                        } else {
-                               ADD_CODE (&td, MINT_LDFLDA);
+                               if ((td.sp - 1)->type == STACK_TYPE_O) {
+                                       ADD_CODE (&td, MINT_LDFLDA);
+                               } else {
+                                       g_assert ((td.sp -1)->type == STACK_TYPE_MP);
+                                       ADD_CODE (&td, MINT_LDFLDA_UNSAFE);
+                               }
                                ADD_CODE (&td, klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
                        }
                        td.ip += 5;
@@ -2177,6 +2187,8 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                ADD_CODE(&td, MINT_CONV_OVF_I8_UN_R8);
                                break;
                        case STACK_TYPE_I8:
+                               if (*td.ip == CEE_CONV_OVF_I8_UN)
+                                       ADD_CODE (&td, MINT_CONV_OVF_I8_U8);
                                break;
                        case STACK_TYPE_I4:
                                ADD_CODE(&td, MINT_CONV_I8_U4);
@@ -2219,7 +2231,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
 
                        break;
                }
-               case CEE_NEWARR:
+               case CEE_NEWARR: {
                        CHECK_STACK (&td, 1);
                        token = read32 (td.ip + 1);
 
@@ -2228,11 +2240,21 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        else
                                klass = mono_class_get_full (image, token, generic_context);
 
-                       ADD_CODE(&td, MINT_NEWARR);
-                       ADD_CODE(&td, get_data_item_index (&td, klass));
-                       SET_TYPE(td.sp - 1, STACK_TYPE_O, klass);
+                       unsigned char lentype = (td.sp - 1)->type;
+                       if (lentype == STACK_TYPE_I8) {
+                               /* mimic mini behaviour */
+                               ADD_CODE (&td, MINT_CONV_OVF_U4_I8);
+                       } else {
+                               g_assert (lentype == STACK_TYPE_I4);
+                               ADD_CODE (&td, MINT_CONV_OVF_U4_I4);
+                       }
+                       SET_SIMPLE_TYPE (td.sp - 1, STACK_TYPE_I4);
+                       ADD_CODE (&td, MINT_NEWARR);
+                       ADD_CODE (&td, get_data_item_index (&td, klass));
+                       SET_TYPE (td.sp - 1, STACK_TYPE_O, klass);
                        td.ip += 5;
                        break;
+               }
                case CEE_LDLEN:
                        CHECK_STACK (&td, 1);
                        SIMPLE_OP (td, MINT_LDLEN);
@@ -2474,9 +2496,15 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        token = read32 (td.ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
                        switch (mint_type (&klass->byval_arg)) {
+                               case MINT_TYPE_U1:
+                                       SIMPLE_OP (td, MINT_STELEM_U1);
+                                       break;
                                case MINT_TYPE_I4:
                                        SIMPLE_OP (td, MINT_STELEM_I4);
                                        break;
+                               case MINT_TYPE_I8:
+                                       SIMPLE_OP (td, MINT_STELEM_I8);
+                                       break;
                                case MINT_TYPE_O:
                                        SIMPLE_OP (td, MINT_STELEM_REF);
                                        break;
@@ -2605,7 +2633,10 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                        ADD_CODE(&td, MINT_CONV_OVF_I4_U4);
                                break;
                        case STACK_TYPE_I8:
-                               ADD_CODE(&td, MINT_CONV_OVF_I4_I8);
+                               if (*td.ip == CEE_CONV_OVF_I4_UN)
+                                       ADD_CODE (&td, MINT_CONV_OVF_I4_U8);
+                               else
+                                       ADD_CODE (&td, MINT_CONV_OVF_I4_I8);
                                break;
                        default:
                                g_assert_not_reached ();
@@ -2669,6 +2700,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                ADD_CODE(&td, MINT_CONV_OVF_U8_I4);
                                break;
                        case STACK_TYPE_I8:
+                               ADD_CODE (&td, MINT_CONV_OVF_U8_I8);
                                break;
                        default:
                                g_assert_not_reached ();
@@ -2688,14 +2720,16 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        } else {
                                handle = mono_ldtoken (image, token, &klass, generic_context);
                        }
-                       mt = mint_type(&klass->byval_arg);
+                       mt = mint_type (&klass->byval_arg);
                        g_assert (mt == MINT_TYPE_VT);
                        size = mono_class_value_size (klass, NULL);
                        g_assert (size == sizeof(gpointer));
-                       PUSH_VT(&td, sizeof(gpointer));
-                       ADD_CODE(&td, MINT_LDTOKEN);
-                       ADD_CODE(&td, get_data_item_index (&td, handle));
-                       PUSH_SIMPLE_TYPE(&td, stack_type [mt]);
+                       PUSH_VT (&td, sizeof(gpointer));
+                       ADD_CODE (&td, MINT_LDTOKEN);
+                       ADD_CODE (&td, get_data_item_index (&td, handle));
+
+                       SET_TYPE (td.sp, stack_type [mt], klass);
+                       td.sp++;
                        td.ip += 5;
                        break;
                }
@@ -3108,19 +3142,19 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                gint32 size;
                                token = read32 (td.ip + 1);
                                td.ip += 5;
-                               if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
+                               if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
                                        int align;
                                        MonoType *type = mono_type_create_from_typespec (image, token);
                                        size = mono_type_size (type, &align);
                                } else {
-                                       guint32 align;
+                                       int align;
                                        MonoClass *szclass = mono_class_get_full (image, token, generic_context);
                                        mono_class_init (szclass);
 #if 0
                                        if (!szclass->valuetype)
                                                THROW_EX (mono_exception_from_name (mono_defaults.corlib, "System", "InvalidProgramException"), ip - 5);
 #endif
-                                       size = mono_class_value_size (szclass, &align);
+                                       size = mono_type_size (&szclass->byval_arg, &align);
                                } 
                                ADD_CODE(&td, MINT_LDC_I4);
                                WRITE32(&td, &size);
@@ -3155,6 +3189,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        printf("\n");
                }
        }
+       g_assert (td.max_stack_height <= (header->max_stack + 1));
 
        rtm->clauses = mono_mempool_alloc (domain->mp, header->num_clauses * sizeof(MonoExceptionClause));
        memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause));
@@ -3184,6 +3219,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        g_free (td.stack_height);
        g_free (td.vt_stack_size);
        g_free (td.data_items);
+       g_free (td.stack);
        g_hash_table_destroy (td.data_hash);
 }
 
@@ -3217,9 +3253,11 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont
        // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
        method_class_vt = mono_class_vtable (domain, runtime_method->method->klass);
        if (!method_class_vt->initialized) {
+               MonoError error;
                jmp_buf env;
                MonoInvocation *last_env_frame = context->env_frame;
                jmp_buf *old_env = context->current_env;
+               error_init (&error);
 
                if (setjmp(env)) {
                        MonoException *failed = context->env_frame->ex;
@@ -3230,7 +3268,10 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont
                }
                context->env_frame = context->current_frame;
                context->current_env = &env;
-               mono_runtime_class_init (method_class_vt);
+               mono_runtime_class_init_full (method_class_vt, &error);
+               if (!mono_error_ok (&error)) {
+                       return mono_error_convert_to_exception (&error);
+               }
                context->env_frame = last_env_frame;
                context->current_env = old_env;
        }