etmar Maurer <dietmar@ximian.com>
authorDietmar Maurer <dietmar@mono-cvs.ximian.com>
Fri, 7 Dec 2001 12:09:30 +0000 (12:09 -0000)
committerDietmar Maurer <dietmar@mono-cvs.ximian.com>
Fri, 7 Dec 2001 12:09:30 +0000 (12:09 -0000)
* jit.c (mono_allocate_intvar): bug fix.

* emit-x86.c (get_unbox_trampoline): impl.

* jit.c (mono_analyze_stack): impl STOBJ, LEAVE

* x86.brg: raise more exceptions.

svn path=/trunk/mono/; revision=1539

mono/jit/ChangeLog
mono/jit/TODO
mono/jit/emit-x86.c
mono/jit/jit.c
mono/jit/x86.brg

index 42880728f62b70c3cc83d4c46054c4064ad5de4e..0936a60dbe524a62eed00a1f39a214e1d3869f2d 100644 (file)
@@ -1,3 +1,20 @@
+2001-12-07  Dietmar Maurer  <dietmar@ximian.com>
+
+       * jit.c (mono_allocate_intvar): bug fix.
+
+       * emit-x86.c (get_unbox_trampoline): impl.
+
+       * jit.c (mono_analyze_stack): impl STOBJ, LEAVE
+
+2001-12-06  Dietmar Maurer  <dietmar@ximian.com>
+
+       * x86.brg: raise exceptions.
+
+2001-12-05  Dietmar Maurer  <dietmar@ximian.com>
+
+       * x86.brg: impl. CEQ for freg, NEWSTRUCT now allocates valuetypes on
+       the stack. 
+
 2001-12-06  Miguel de Icaza  <miguel@ximian.com>
 
        * jit.c (mono_analyze_stack), x86.brg: Implement CONV.OVF.I1,
index 76a29faad274211f5ed63152dfa4e536d3866f28..c0b1fda61bcafa52fed0bd4749fb1c80188e91d6 100644 (file)
@@ -21,4 +21,5 @@
        Implement CONV_OVF_XXX (constant) variants that emit either
        loads or exceptions (as we can always tell)
        
-       
\ No newline at end of file
+       
+* thread does not work with the jit (mcs/tests/test-19.cs)??
\ No newline at end of file
index b514b634ddd888b50593017a92e1fbeb21ef10a4..9204b85c7f892ba4e847a0b6f9060e447bc643d7 100644 (file)
@@ -30,7 +30,7 @@ enter_method (MonoMethod *method, gpointer ebp)
        MonoClass *class;
        MonoObject *o;
 
-       printf ("ENTER: %s.%s::%s (", method->klass->name_space,
+       printf ("ENTER: %s.%s::%s\n(", method->klass->name_space,
                method->klass->name, method->name);
 
        ebp += 8;
@@ -51,11 +51,13 @@ enter_method (MonoMethod *method, gpointer ebp)
                        printf ("value:%p, ", *((gpointer *)ebp));
                } else {
                        o = *((MonoObject **)ebp);
+
+                       g_assert (o);
+
                        class = o->klass;
 
                        if (class == mono_defaults.string_class) {
-                               printf ("this:%p[STRING:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
-
+                               printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
                        } else {
                                printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
                        }
@@ -81,12 +83,32 @@ enter_method (MonoMethod *method, gpointer ebp)
                case MONO_TYPE_U:
                        printf ("%d, ", *((int *)(ebp)));
                        break;
-               case MONO_TYPE_STRING:
-                       printf ("[STRING:%s], ", mono_string_to_utf8 (*(MonoString **)(ebp)));
+               case MONO_TYPE_STRING: {
+                       MonoString *s = *((MonoString **)ebp);
+                       if (s) {
+                               g_assert (((MonoObject *)s)->klass == mono_defaults.string_class);
+                               printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
+                       } else 
+                               printf ("[STRING:null], ");
                        break;
-               case MONO_TYPE_PTR:
+               }
                case MONO_TYPE_CLASS:
-               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_OBJECT: {
+                       o = *((MonoObject **)ebp);
+                       if (o) {
+                               class = o->klass;
+                               if (class == mono_defaults.string_class) {
+                                       printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
+                               } else if (class == mono_defaults.int32_class) {
+                                       printf ("[INT32:%p:%d], ", o, *(gint32 *)((gpointer)o + sizeof (MonoObject)));
+                               } else
+                                       printf ("[%s.%s:%p], ", class->name_space, class->name, o);
+                       } else {
+                               printf ("%p, ", *((gpointer *)(ebp)));                          
+                       }
+                       break;
+               }
+               case MONO_TYPE_PTR:
                case MONO_TYPE_FNPTR:
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
@@ -147,9 +169,16 @@ leave_method (MonoMethod *method, int edx, int eax, double test)
        case MONO_TYPE_U:
                printf ("EAX=%d", eax);
                break;
-       case MONO_TYPE_STRING:
-               printf ("[STRING:%s]", mono_string_to_utf8 ((MonoString *)(eax)));
+       case MONO_TYPE_STRING: {
+               MonoString *s = (MonoString *)eax;
+
+               if (s) {
+                       g_assert (((MonoObject *)s)->klass == mono_defaults.string_class);
+                       printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
+               } else 
+                       printf ("[STRING:null], ");
                break;
+       }
        case MONO_TYPE_OBJECT: {
                MonoObject *o = (MonoObject *)eax;
                
@@ -255,6 +284,33 @@ arch_emit_epilogue (MonoFlowGraph *cfg)
        x86_ret (cfg->code);
 }
 
+/*
+ * get_unbox_trampoline:
+ * @m: method pointer
+ *
+ * when value type methods are called through the vtable we need to unbox the
+ * this argument. This method returns a pointer to a trampoline which does
+ * unboxing before calling the method
+ */
+static gpointer
+get_unbox_trampoline (MonoMethod *m)
+{
+       gpointer p = arch_compile_method (m);
+       guint8 *code, *start;
+       int this_pos = 4;
+
+       if (!m->signature->ret->byref && m->signature->ret->type == MONO_TYPE_VALUETYPE)
+               this_pos = 8;
+           
+       start = code = g_malloc (16);
+
+       x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
+       x86_jump_code (code, p);
+       g_assert ((code - start) < 16);
+
+       return start;
+}
+
 /**
  * x86_magic_trampoline:
  * @eax: saved x86 register 
@@ -323,7 +379,10 @@ x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi,
 
        o += disp;
 
-       return *((gpointer *)o) = arch_compile_method (m);
+       if (m->klass->valuetype) {
+               return *((gpointer *)o) = get_unbox_trampoline (m);
+       } else
+               return *((gpointer *)o) = arch_compile_method (m);
 }
 
 /**
@@ -808,6 +867,8 @@ arch_compile_method (MonoMethod *method)
 
                if (mono_jit_dump_forest) {
                        int i;
+                       printf ("FOREST %s.%s:%s\n", method->klass->name_space,
+                               method->klass->name, method->name);
                        for (i = 0; i < cfg->block_count; i++) {
                                printf ("BLOCK %d:\n", i);
                                mono_print_forest (cfg->bblocks [i].forest);
@@ -887,6 +948,7 @@ arch_compile_method (MonoMethod *method)
                        method->klass->name, method->name, method, method->addr);
        }
 
+
        return method->addr;
 }
 
@@ -1013,8 +1075,7 @@ arch_handle_exception (struct sigcontext *ctx, gpointer obj)
                        for (i = 0; i < ji->num_clauses; i++) {
                                MonoJitExceptionInfo *ei = &ji->clauses [i];
 
-                               if (ei->try_start <= ip && ip < (ei->try_end)) { 
-                               
+                               if (ei->try_start <= ip && ip <= (ei->try_end)) { 
                                        /* catch block */
                                        if (ei->flags == 0 && mono_object_isinst (obj, 
                                                mono_class_get (m->klass->image, ei->token_or_filter))) {
index b7339729b612d308580f3e7d098f7dacf93389e5..211914cd118406d03d97c94eda1ba51586d8bfee 100644 (file)
@@ -82,6 +82,16 @@ case CEE_##name: {                                                            \
        break;                                                                \
 }
 
+#define MAKE_CMP(name)                                                        \
+case CEE_##name: {                                                            \
+       ++ip;                                                                 \
+       sp -= 2;                                                              \
+       t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]);             \
+        g_assert (sp [0]->svt == sp [1]->svt);                                \
+       PUSH_TREE (t1, VAL_I32);                                              \
+       break;                                                                \
+}
+
 #define MAKE_SPILLED_BI_ALU(name)                                             \
 case CEE_##name: {                                                            \
        ++ip;                                                                 \
@@ -749,16 +759,26 @@ mono_get_val_sizes (MonoValueType type, int *size, int *align)
 static int
 mono_allocate_intvar (MonoFlowGraph *cfg, int slot, MonoValueType type)
 {
-       int size, align, vnum;
+       int size, align, vnum, pos;
        
        g_assert (type != VAL_UNKNOWN);
 
-       if ((vnum = cfg->intvars [type - 1 + slot * VAL_DOUBLE]))
-               return vnum;
+       /* take care if you modify MonoValueType */
+       g_assert (VAL_DOUBLE == 4);
+
+       /* fixme: machine dependant */ 
+       if (type == VAL_POINTER)
+               type = VAL_I32; /* VAL_I32 and VAL_POINTER share the same slot */
 
+       pos = type - 1 + slot * VAL_DOUBLE;
+
+       if ((vnum = cfg->intvars [pos]))                
+               return vnum;
        mono_get_val_sizes (type, &size, &align);
 
-       return cfg->intvars[type - 1 + slot * VAL_DOUBLE] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
+       cfg->intvars[pos] = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, type);
+
+       return cfg->intvars[pos];
 }
 
 static int
@@ -785,19 +805,9 @@ inline static MBTree *
 ctree_create_load (MonoFlowGraph *cfg, MonoType *type, MBTree *addr, MonoValueType *svt, gboolean arg)
 {
        MonoMemPool *mp = cfg->mp;
-       int ldind, size, align, vnum;
+       int ldind;
        MBTree *t;
 
-       if (!type->byref && type->type == MONO_TYPE_VALUETYPE && 
-           !type->data.klass->enumtype) {
-               size = mono_type_size (type, &align);
-
-               vnum = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
-               t = mono_ctree_new (mp, MB_TERM_LDIND_OBJ, addr, NULL);
-               t->data.i = vnum;
-               return t;
-       }
-
        if (arg)
                ldind = map_ldarg_type (type, svt);
        else
@@ -833,11 +843,9 @@ ctree_create_store (MonoFlowGraph *cfg, MonoType *type, MBTree *addr,
 
        t = mono_ctree_new (mp, stind, addr, s);
 
-       if (type->type == MONO_TYPE_VALUETYPE) {
-               guint32 align;
-               t->data.i = mono_class_value_size (type->data.klass, &align);
-       }
-
+       if (!type->byref && type->type == MONO_TYPE_VALUETYPE)  
+               t->data.i = mono_class_value_size (type->data.klass, NULL);
+       
        return t;
 }
 
@@ -931,7 +939,7 @@ mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **dup)
 {
        MonoMemPool *mp = cfg->mp;
        MBTree *t;
-       int vnum;
+       int vnum = 0;
 
        switch (s->op) {
        case MB_TERM_STIND_I1:
@@ -1247,6 +1255,7 @@ mono_analyze_flow (MonoFlowGraph *cfg)
                case CEE_LDFLDA:
                case CEE_STSFLD: 
                case CEE_STFLD:
+               case CEE_STOBJ:
                case CEE_LDELEMA:
                case CEE_NEWOBJ:
                case CEE_CPOBJ:
@@ -1636,7 +1645,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                for (i = 0; i < cfg->block_count; i++) {
                        bb = &cfg->bblocks [i];
                        
-                       //printf ("BBS %d %05x %05x %d %d %d\n", i, bb->cli_addr, bb->cli_addr + bb->length, bb->reached, bb->finished, superblock_end);
+                       //printf ("BBS %d %05x %05x %d %d %d %s\n", i, bb->cli_addr, bb->cli_addr + bb->length, bb->reached, bb->finished, superblock_end, method->name);
                        
                        if (!bb->reached && !superblock_end) {
                                MonoBBlock *sbb = &cfg->bblocks [i - 1];
@@ -1754,6 +1763,26 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        PUSH_TREE (t1, svt);
                        break;
                }
+               case CEE_STOBJ: {
+                       guint32 token;
+                       MonoClass *c;
+                       int size;
+
+                       ++ip;
+                       token = read32 (ip);
+                       ip += 4;
+                       sp -= 2;
+
+                       c = mono_class_get (image, token);
+                       g_assert (c->valuetype);
+
+                       size = mono_class_value_size (c, NULL);
+                       
+                       t1 = mono_ctree_new (mp, MB_TERM_STIND_OBJ, sp [0], sp [1]);
+                       t1->data.i = size;
+                       ADD_TREE (t1, cli_addr);
+                       break;
+               }
                case CEE_LDSTR: {
                        MonoObject *o;
                        guint32 index;
@@ -2055,12 +2084,14 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
                                this->data.m = cm;
                        } else {                                
-                               if (cm->klass->valuetype)
+                               if (cm->klass->valuetype) {
                                        this = mono_ctree_new_leaf (mp, MB_TERM_NEWSTRUCT);
-                               else
+                                       this->data.i =  mono_class_value_size (cm->klass, NULL);
+                               } else {
                                        this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
+                                       this->data.klass = cm->klass;
+                               }
 
-                               this->data.klass = cm->klass;
                                this->svt = VAL_POINTER;
 
                                t1 = mono_store_tree (cfg, -1, this, &this);
@@ -2071,8 +2102,9 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        for (i = csig->param_count - 1; i >= 0; i--) {
                                MonoType *type = cm->signature->params [i];
                                t1 = mono_ctree_new (mp, map_arg_type (type, FALSE), arg_sp [i], NULL); 
-                               ADD_TREE (t1, cli_addr);
                                size = mono_type_size (type, &align);
+                               t1->data.i = size;
+                               ADD_TREE (t1, cli_addr);
                                args_size += (size + 3) & ~3;
                        }
 
@@ -2168,8 +2200,9 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        for (i = nargs - 1; i >= 0; i--) {
                                MonoType *type = cm->signature->params [i];
                                t1 = mono_ctree_new (mp, map_arg_type (type, pinvoke), arg_sp [i], NULL);
-                               ADD_TREE (t1, cli_addr);
                                size = mono_type_size (type, &align);
+                               t1->data.i = size;
+                               ADD_TREE (t1, cli_addr);
                                args_size += (size + 3) & ~3;
 
                                // fixme: align value type arguments  to 8 byte boundary on the stack
@@ -2505,12 +2538,17 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        PUSH_TREE (t1, sp [0]->svt);
                        break;
                }
+               case CEE_BR: 
                case CEE_BR_S: {
                        gint32 target;
+                       int br_s = (*ip == CEE_BR_S);
 
                        ++ip;
-                       target = cli_addr + 2 + (signed char) *ip;
+                       if (br_s)
+                               target = cli_addr + 2 + (signed char) *ip;
+                       else
+                               target = cli_addr + 5 + (gint32) read32(ip);
+
                        g_assert (target >= 0 && target <= header->code_size);
                        g_assert (bcinfo [target].is_block_start);
                        tbb = &cfg->bblocks [bcinfo [target].block_id];
@@ -2520,38 +2558,27 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
                        t1->data.p = tbb;
                        ADD_TREE (t1, cli_addr);
-                       ++ip;
-
-                       superblock_end = TRUE;
-                       break;
-               }
-               case CEE_BR: {
-                       gint32 target;
-
-                       ++ip;
-                       target = cli_addr + 5 + (gint32) read32(ip);
 
-                       g_assert (target >= 0 && target <= header->code_size);
-                       g_assert (bcinfo [target].is_block_start);
-                       tbb = &cfg->bblocks [bcinfo [target].block_id];
-                       create_outstack (cfg, bb, stack, sp - stack);
-                       mark_reached (cfg, tbb, bb->outstack, bb->outdepth);
-                     
-                       t1 = mono_ctree_new_leaf (mp, MB_TERM_BR);
-                       t1->data.p = tbb;
-                       ADD_TREE (t1, cli_addr);
-                       ip += 4;
+                       if (br_s)
+                               ++ip;
+                       else
+                               ip += 4;
 
                        superblock_end = TRUE;
                        break;
                }
+               case CEE_LEAVE:
                case CEE_LEAVE_S: {
                        gint32 target;
                        MonoBBlock *hb;
+                       int leave_s = (*ip == CEE_LEAVE_S);
 
                        ++ip;
-                       target = cli_addr + 2 + (signed char) *ip;
+                       if (leave_s)
+                               target = cli_addr + 2 + (signed char) *ip;
+                       else
+                               target = cli_addr + 5 + (gint32) read32(ip);
+
                        g_assert (target >= 0 && target <= header->code_size);
                        g_assert (bcinfo [target].is_block_start);
                        tbb = &cfg->bblocks [bcinfo [target].block_id];
@@ -2571,7 +2598,10 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        t1->data.p = tbb;
                        ADD_TREE (t1, cli_addr);
                        
-                       ++ip;
+                       if (leave_s)
+                               ++ip;
+                       else
+                               ip += 4;
 
                        superblock_end = TRUE;
                        break;
@@ -2640,13 +2670,21 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        break;
                }
                case CEE_RET: {
+                       MonoType *ret = signature->ret;
+
                        ip++;
 
-                       if (signature->ret->type != MONO_TYPE_VOID) {
+                       if (ret->type != MONO_TYPE_VOID) {
                                --sp;
-                               t1 = mono_ctree_new (mp, MB_TERM_RETV, *sp, NULL);
+                               if (!ret->byref && ret->type == MONO_TYPE_VALUETYPE) {
+                                       int align;
+                                       t1 = mono_ctree_new (mp, MB_TERM_RET_OBJ, *sp, NULL);
+                                       t1->data.i = mono_class_value_size (ret->data.klass, &align);
+                               } else {
+                                       t1 = mono_ctree_new (mp, MB_TERM_RET, *sp, NULL);
+                               }
                        } else {
-                               t1 = mono_ctree_new_leaf (mp, MB_TERM_RET);
+                               t1 = mono_ctree_new_leaf (mp, MB_TERM_RET_VOID);
                        }
 
                        t1->last_instr = (ip == end);
@@ -2706,6 +2744,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                case CEE_STARG_S: {
                        ++ip;
                        --sp;
+
                        t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                        t1->data.i = ARG_POS (*ip);
                        t1 = ctree_create_store (cfg, ARG_TYPE (*ip), t1, *sp, TRUE);
@@ -2882,8 +2921,8 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        ++ip;                   
                        switch (*ip) {
                                
-                       MAKE_BI_ALU (CEQ)
-                       MAKE_BI_ALU (CLT)
+                       MAKE_CMP (CEQ)
+                       MAKE_CMP (CLT)
 
                        case CEE_RETHROW: {
                                ++ip;
@@ -2958,9 +2997,9 @@ mono_analyze_stack (MonoFlowGraph *cfg)
        }               
 
         if ((depth = sp - stack)) {
-               create_outstack (cfg, bb, stack, sp - stack);
+               //printf ("DEPTH %d %d\n",  depth, sp [0]->op);
                //mono_print_forest (forest);
-               //printf ("DEPTH %d %d\n", depth, sp [0]->op);
+               create_outstack (cfg, bb, stack, sp - stack);
        }
 
                                } else 
@@ -3065,6 +3104,9 @@ mono_jit_exec (MonoAssembly *assembly, int argc, char *argv[])
        } else {
                res = mfunc ();
        }
+
+       if (method->signature->ret->type == MONO_TYPE_VOID)
+               res = 0;
        
        return res;
 }
@@ -3137,7 +3179,8 @@ mono_jit_abort (MonoObject *obj)
                        trace = mono_string_to_utf8 (str);
        }                               
        
-       g_warning ("unhandled exception \"%s\"", message);
+       g_warning ("unhandled exception %s.%s: \"%s\"", obj->klass->name_space, 
+                  obj->klass->name, message);
        
        if (trace) {
                g_printerr (trace);
index 4b2f7b3ca10cce91ee0a31707f6a5cbb5e76ff3a..8b1dfb657bec9c21a979c28c82a69af84c1eae4b 100644 (file)
@@ -152,7 +152,7 @@ x86_pop_reg (s->code, X86_EAX);
 %term LDIND_U4 LDIND_OBJ
 %term STIND_I1 STIND_I2 STIND_I4 STIND_I8 STIND_R4 STIND_R8 STIND_OBJ
 %term ADDR_L ADDR_G ARG_I4 ARG_I8 ARG_R4 ARG_R8 ARG_OBJ ARG_STRING CALL_I4 CALL_I8 CALL_R8 CALL_VOID
-%term BREAK SWITCH BR RET RETV ENDFINALLY
+%term BREAK SWITCH BR RET_VOID RET RET_OBJ ENDFINALLY
 %term ADD SUB MUL DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT
 %term BLT BLT_UN BEQ BNE_UN BRTRUE BRFALSE BGE BGE_UN BLE BLE_UN BGT BGT_UN 
 %term CEQ CLT
@@ -399,7 +399,7 @@ reg: LDIND_I4 (addr) {
                break;          
        }
 
-       
+
        PRINT_REG ("LDIND_I4", tree->reg1);
 }
 
@@ -860,34 +860,45 @@ reg: NEWOBJ {
 }
 
 reg: NEWSTRUCT {
-       MonoClass *klass = tree->data.klass;
-
-       if (tree->reg1 != X86_EAX)
-               x86_push_reg (s->code, X86_EAX);
-       x86_push_reg (s->code, X86_ECX);
-       x86_push_reg (s->code, X86_EDX);
-
-       g_assert (klass->valuetype);
-       g_assert (klass->inited);
+       int size = tree->data.i;        
+       int sa;
+       
+       g_assert (size > 0);
 
-       x86_push_imm (s->code, (klass->instance_size - sizeof (MonoObject)));
-       x86_call_code (s->code, mono_object_allocate);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+       sa = size + 3;
+       sa &= ~3;
 
-       x86_pop_reg (s->code, X86_EDX);
-       x86_pop_reg (s->code, X86_ECX);
-       if (tree->reg1 != X86_EAX) {
-               x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
-               x86_pop_reg (s->code, X86_EAX);
-       }
+       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
+       x86_mov_reg_reg (s->code, tree->reg1, X86_ESP, 4);
 }
 
 reg: UNBOX (reg) {
-       // fixme: add type check
+       guint8 *start = s->code, *l1, *l2, *l3, *le;
+       int i;
 
-       if (tree->reg1 != tree->left->reg1)
-               x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
-       x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, sizeof (MonoObject));
+       tree->is_jump = TRUE;
+       l1 = l2 = l3 = le = NULL;
+
+       for (i = 0; i < 2; i++) {
+               s->code = start;
+
+               if (tree->reg1 != tree->left->reg1)
+                       x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
+
+               x86_alu_reg_imm (s->code, X86_CMP, tree->reg1, 0);
+               x86_branch8 (s->code, X86_CC_NE, l2 - l1, FALSE);
+               l1 = s->code;
+               x86_mov_reg_imm (s->code, X86_ECX, get_exception_null_reference ());
+               x86_call_code (s->code, get_throw_exception ());
+               l2 = s->code;
+               x86_alu_membase_imm (s->code, X86_CMP, tree->reg1, 0, ((int)(tree->data.klass)));
+               x86_branch8 (s->code, X86_CC_EQ, le - l3, FALSE);
+               l3 = s->code;
+               x86_mov_reg_imm (s->code, X86_ECX, get_exception_invalid_cast ());
+               x86_call_code (s->code, get_throw_exception ());
+               le = s->code;
+               x86_alu_reg_imm (s->code, X86_ADD, tree->reg1, sizeof (MonoObject));
+       }
 }
 
 reg: CASTCLASS (reg) {
@@ -1274,7 +1285,7 @@ stmt: BREAK {
        x86_breakpoint (s->code);
 }
 
-stmt: RETV (reg) {
+stmt: RET (reg) {
        if (tree->left->reg1 != X86_EAX)
                x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
 
@@ -1284,7 +1295,7 @@ stmt: RETV (reg) {
        }
 }
 
-stmt: RET {
+stmt: RET_VOID {
        if (!tree->last_instr) {
                tree->is_jump = 1;
                x86_jump32 (s->code, s->epilog - 5);
@@ -1900,7 +1911,7 @@ lreg: CALL_I8 (this, LDIND_I4 (ADDR_G)) {
        g_assert (tree->reg2 == X86_EDX);
 }
 
-stmt: RETV (lreg) {
+stmt: RET (lreg) {
        if (tree->left->reg1 != X86_EAX) {
                if (tree->left->reg2 != X86_EAX) {
                        x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);
@@ -2131,6 +2142,23 @@ reg: CONV_I4 (freg) {
        x86_pop_reg (s->code, tree->reg1);
 }
 
+reg: CEQ (freg, freg) {
+       int treg = tree->reg1;
+       
+       if (treg != X86_EAX)
+               x86_push_reg (s->code, X86_EAX); // save EAX
+               
+       x86_fcompp (s->code);
+       x86_fnstsw (s->code);
+       x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4500);
+       x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x4000);
+       x86_set_reg (s->code, X86_CC_EQ, tree->reg1, TRUE);
+       x86_widen_reg (s->code, treg, treg, FALSE, FALSE);
+
+       if (treg != X86_EAX)
+               x86_pop_reg (s->code, X86_EAX); // save EAX
+}
+
 freg: CONV_R8 (freg) {
        /* nothing to do */
 }
@@ -2400,7 +2428,7 @@ freg: CALL_R8 (this, VFUNC_ADDR) {
                x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 }
 
-stmt: RETV (freg) {
+stmt: RET (freg) {
 
        if (!tree->last_instr) {
                tree->is_jump = 1;
@@ -2410,21 +2438,9 @@ stmt: RETV (freg) {
 
 # support for value types
 
-stmt: STIND_OBJ (reg, LDIND_OBJ (reg)) {
-       x86_push_reg (s->code, X86_EAX);
-       x86_push_reg (s->code, X86_EDX);
-       x86_push_reg (s->code, X86_ECX);
-
-       g_assert (tree->data.i > 0);
-       x86_push_imm (s->code, tree->data.i);
-       x86_push_reg (s->code, tree->right->left->reg1);
-       x86_push_reg (s->code, tree->left->reg1);
-       x86_call_code (s->code, MEMCOPY);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
-
-       x86_pop_reg (s->code, X86_ECX);
-       x86_pop_reg (s->code, X86_EDX);
-       x86_pop_reg (s->code, X86_EAX);
+reg: LDIND_OBJ (reg) {
+       if (tree->left->reg1 != tree->reg1)
+               x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
 }
 
 stmt: STIND_OBJ (reg, reg) {
@@ -2448,10 +2464,12 @@ stmt: ARG_OBJ (CONST_I4) {
        x86_push_imm (s->code, tree->left->data.i);     
 }
 
-stmt: ARG_OBJ (LDIND_OBJ (reg)) {
-       int size = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).size;
+stmt: ARG_OBJ (reg) {
+       int size = tree->data.i;
        int sa;
        
+       g_assert (size > 0);
+
        sa = size + 3;
        sa &= ~3;
 
@@ -2463,7 +2481,7 @@ stmt: ARG_OBJ (LDIND_OBJ (reg)) {
        x86_push_reg (s->code, X86_ECX);
 
        x86_push_imm (s->code, size);
-       x86_push_reg (s->code, tree->left->left->reg1);
+       x86_push_reg (s->code, tree->left->reg1);
        x86_lea_membase (s->code, X86_EAX, X86_ESP, 5*4);
        x86_push_reg (s->code, X86_EAX);
 
@@ -2475,11 +2493,11 @@ stmt: ARG_OBJ (LDIND_OBJ (reg)) {
        x86_pop_reg (s->code, X86_EAX);
 }
 
-stmt: RETV (LDIND_OBJ (reg)) {
-       int size = g_array_index (s->varinfo, MonoVarInfo, tree->left->data.i).size;
+stmt: RET_OBJ (reg) {
+       int size = tree->data.i;
 
        x86_push_imm (s->code, size);
-       x86_push_reg (s->code, tree->left->left->reg1);
+       x86_push_reg (s->code, tree->left->reg1);
        x86_push_membase (s->code, X86_EBP, 8);
 
        x86_call_code (s->code, MEMCOPY);