[interp] support stelem for g{,u}int64
[mono.git] / mono / mini / interp / transform.c
index e0dbbd905b4e1d5f2ed88124486ea755d61904f1..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);
@@ -2484,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;
@@ -2615,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 ();
@@ -2679,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 ();
@@ -3167,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));
@@ -3196,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);
 }
 
@@ -3229,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;
@@ -3242,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;
        }