2002-07-24 Tim Coleman <tim@timcoleman.com>
[mono.git] / mono / jit / x86.brg
index d90151b0bdc43e9dce31229ad0edbaf7bfac7550..0d419bc1a17afd0e5804fe85318ce94bf38add7b 100644 (file)
@@ -24,6 +24,7 @@
 #include <mono/metadata/object.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/appdomain.h>
+#include <mono/metadata/marshal.h>
 #include <mono/arch/x86/x86-codegen.h>
 
 #include "regset.h"
@@ -41,6 +42,9 @@ enum {
 };
 #undef OPDEF
 
+/* alignment of activation frames */
+#define MONO_FRAME_ALIGNMENT 4
+
 void print_lmf (void);
 
 #define MBTREE_TYPE  MBTree
@@ -90,9 +94,10 @@ struct _MBTree {
                MonoClass *klass;
                MonoClassField *field;
                X86AddressInfo ainfo;
-               MonoJitCallInfo ci;
                MonoJitFieldInfo fi;
                MonoJitBranchInfo bi;
+               MonoJitCallInfo call_info;        
+               MonoJitArgumentInfo arg_info;     
        } data;
 };
 
@@ -105,6 +110,10 @@ guint64  mono_lldiv_un      (guint64 a, guint64 b);
 guint64  mono_llrem_un      (guint64 a, guint64 b);
 gpointer mono_ldsflda       (MonoClass *klass, int offset);
 
+gpointer mono_ldvirtftn     (MonoObject *this, int slot);
+gpointer mono_ldintftn      (MonoObject *this, int slot);
+gpointer mono_ldftn         (MonoMethod *method);
+
 void mono_emit_fast_iconv(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
 void mono_emit_fast_iconv_i8(MBCGEN_TYPE* s, MBTREE_TYPE* tree);
 
@@ -150,10 +159,11 @@ x86_pop_reg (s->code, X86_ECX); \
 x86_pop_reg (s->code, X86_EDX); \
 x86_pop_reg (s->code, X86_EAX);
 
-#ifdef DEBUG
-#define MEMCOPY debug_memcpy
-void *MEMCOPY (void *dest, const void *src, size_t n);
+void *
+debug_memcopy (void *dest, const void *src, size_t n);
 
+#ifdef DEBUG
+#define MEMCOPY debug_memcopy
 #define PRINT_REG(text,reg) REAL_PRINT_REG(text,reg)
 #else
 
@@ -185,6 +195,36 @@ void *MEMCOPY (void *dest, const void *src, size_t n);
                x86_call_code (s->code, 0);                    \
        } while (0); 
 
+#define X86_ARG_PAD(pad) do {                                               \
+       if (pad) {                                                          \
+               if (pad == 4)                                               \
+                       x86_push_reg (s->code, X86_EAX);                    \
+               else                                                        \
+                       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, pad);   \
+       }                                                                   \
+} while (0)
+
+#define X86_CALL_END    do {                                       \
+        int size = tree->data.call_info.frame_size;                \
+        if (size)                                                  \
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, size); \
+} while (0)
+
+#define X86_CALL_BEGIN  do {                                                     \
+        int pad = tree->data.call_info.pad;                                      \
+        X86_ARG_PAD (pad);                                                       \
+       if (tree->left->op != MB_TERM_NOP) {                                     \
+               mono_assert (lreg >= 0);                                         \
+               x86_push_reg (s->code, lreg);                                    \
+               x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);              \
+       }                                                                        \
+       if (tree->data.call_info.vtype_num) {                                    \
+               int offset = VARINFO (s, tree->data.call_info.vtype_num).offset; \
+               x86_lea_membase (s->code, treg, X86_EBP, offset);                \
+               x86_push_reg (s->code, treg);                                    \
+       }                                                                        \
+} while (0)
+
 /* we use this macro to move one lreg to another - source and
    destination may overlap, but the register allocator has to
    make sure that ((d1 < d2) && (s1 < s2))
@@ -212,17 +252,18 @@ void *MEMCOPY (void *dest, const void *src, size_t n);
 # terminal definitions
 #
 
-# constatnts
+# constants
 %term CONST_I4 CONST_I8 CONST_R4 CONST_R8
 %term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_I8 LDIND_R4 LDIND_R8 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_VOID RET RET_OBJ ENDFINALLY
+%term ADDR_L ADDR_G ARG_I4 ARG_I8 ARG_R4 ARG_R8 ARG_OBJ CALL_I4 CALL_I8 CALL_R8 CALL_VOID
+%term BREAK SWITCH BR RET_VOID RET RET_OBJ ENDFINALLY ENDFILTER JMP
 %term ADD ADD_OVF ADD_OVF_UN SUB SUB_OVF SUB_OVF_UN MUL MUL_OVF MUL_OVF_UN 
-%term DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT
+%term DIV DIV_UN REM REM_UN AND OR XOR SHL SHR SHR_UN NEG NOT CKFINITE
 %term COMPARE CBRANCH BRTRUE BRFALSE CSET
 %term CONV_I4 CONV_I1 CONV_I2 CONV_I8 CONV_U1 CONV_U2 CONV_U4 CONV_U8 CONV_R4 CONV_R8 CONV_R_UN
-%term INTF_ADDR VFUNC_ADDR NOP NEWARR NEWARR_SPEC NEWOBJ NEWOBJ_SPEC NEWSTRUCT CPBLK CPSRC POP INITOBJ
+%term INTF_ADDR VFUNC_ADDR NOP NEWARR NEWARR_SPEC NEWOBJ NEWOBJ_SPEC
+%term INITBLK CPBLK CPSRC POP INITOBJ LOCALLOC
 %term ISINST CASTCLASS UNBOX
 %term CONV_OVF_I1 CONV_OVF_U1 CONV_OVF_I2 CONV_OVF_U2 CONV_OVF_U4 CONV_OVF_U8 CONV_OVF_I4
 %term CONV_OVF_I4_UN CONV_OVF_U1_UN CONV_OVF_U2_UN
@@ -231,6 +272,10 @@ void *MEMCOPY (void *dest, const void *src, size_t n);
 %term LDLEN LDELEMA LDFTN LDVIRTFTN LDSTR LDSFLDA
 %term REMOTE_LDFLDA REMOTE_STIND_I1 REMOTE_STIND_I2 REMOTE_STIND_I4
 %term REMOTE_STIND_I8 REMOTE_STIND_R4 REMOTE_STIND_R8 REMOTE_STIND_OBJ
+%term SIN COS SQRT
+
+%term FUNC1 PROC2 PROC3 FREE OBJADDR VTADDR
+
 #
 # we start at stmt
 #
@@ -335,16 +380,12 @@ addr: ADD (index, base) {
 # we pass exception in ECX to catch handler
 reg: EXCEPTION {
        int offset = VARINFO (s, tree->data.i).offset;
-       int reg = VARINFO (s, tree->data.i).reg;
 
        if (tree->reg1 != X86_ECX)
                x86_mov_reg_reg (s->code, tree->reg1, X86_ECX, 4);
        
        /* store it so that we can RETHROW it later */
-       if (reg < 0)
-               x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
-       else
-               x86_mov_reg_reg (s->code, reg, tree->reg1, 4);
+       x86_mov_membase_reg (s->code, X86_EBP, offset, tree->reg1, 4);
 }
 
 stmt: THROW (reg) {
@@ -357,14 +398,10 @@ stmt: THROW (reg) {
 }
 
 stmt: RETHROW {
-       int off = VARINFO (s, tree->data.i).offset;
-       int reg = VARINFO (s, tree->data.i).reg;
+       int offset = VARINFO (s, tree->data.i).offset;
        gpointer target;
 
-       if (reg < 0)
-               x86_push_membase (s->code, X86_EBP, off);
-       else
-               x86_push_reg (s->code, reg);
+       x86_push_membase (s->code, X86_EBP, offset);
 
        target = arch_get_throw_exception ();
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, target);
@@ -372,11 +409,27 @@ stmt: RETHROW {
 }
 
 stmt: HANDLER {
+       /* save ESP (used by ENDFINALLY) */
+       x86_mov_membase_reg (s->code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_BB, tree->data.bb);
        x86_call_imm (s->code, 0); 
 }
 
 stmt: ENDFINALLY {
+       /* restore ESP - which can be modified when we allocate value types
+        * in the finally handler */
+       x86_mov_reg_membase (s->code, X86_ESP, X86_EBP, mono_exc_esp_offset, 4);
+       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
+       x86_ret (s->code);
+}
+
+stmt: ENDFILTER (reg) {
+       /* restore ESP - which can be modified when we allocate value types
+        * in the filter */
+       x86_mov_reg_membase (s->code, X86_ESP, X86_EBP, mono_exc_esp_offset, 4);
+       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
+       if (tree->left->reg1 != X86_EAX)
+               x86_mov_reg_reg (s->code, X86_EAX, tree->left->reg1, 4);             
        x86_ret (s->code);
 }
 
@@ -949,7 +1002,6 @@ reg: CONV_U2 (reg) {
        x86_widen_reg (s->code, tree->reg1, tree->left->reg1, FALSE, TRUE);
 }
 
-# warning: this chain rule requires a register
 reg: CONST_I4 1 {
        x86_mov_reg_imm (s->code, tree->reg1, tree->data.i);
 }
@@ -1630,7 +1682,7 @@ reg: NEWARR (reg) {
        x86_push_imm (s->code, tree->data.p);
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_wrapper);
        x86_call_code (s->code, 0);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
 
        x86_pop_reg (s->code, X86_EDX);
        x86_pop_reg (s->code, X86_ECX);
@@ -1652,7 +1704,7 @@ reg: NEWARR_SPEC (reg) {
        x86_push_imm (s->code, tree->data.p);
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_array_new_specific);
        x86_call_code (s->code, 0);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer) + 4);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
 
        x86_pop_reg (s->code, X86_EDX);
        x86_pop_reg (s->code, X86_ECX);
@@ -1673,7 +1725,7 @@ reg: NEWOBJ {
        x86_push_imm (s->code, tree->data.klass);
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_wrapper);
        x86_call_code (s->code, 0);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
 
        x86_pop_reg (s->code, X86_EDX);
        x86_pop_reg (s->code, X86_ECX);
@@ -1693,7 +1745,7 @@ reg: NEWOBJ_SPEC {
        x86_push_imm (s->code, tree->data.p);
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_object_new_specific);
        x86_call_code (s->code, 0);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
 
        x86_pop_reg (s->code, X86_EDX);
        x86_pop_reg (s->code, X86_ECX);
@@ -1704,16 +1756,104 @@ reg: NEWOBJ_SPEC {
        PRINT_REG ("NEWOBJ_SPEC", tree->reg1);
 }
 
-reg: NEWSTRUCT {
-       int size = tree->data.i;        
-       int sa;
-       
-       mono_assert (size > 0);
+reg: OBJADDR (reg) {
+       if (tree->left->reg1 != tree->reg1)
+               x86_mov_reg_reg (s->code, tree->reg1, tree->left->reg1, 4);
+}
 
-       sa = size + 3;
-       sa &= ~3;
+reg: VTADDR (ADDR_L) {
+       int offset = VARINFO (s, tree->left->data.i).offset;
+
+       x86_lea_membase (s->code, tree->reg1, X86_EBP, offset);
+}
+
+stmt: FREE (reg) {
+       x86_push_reg (s->code, tree->left->reg1);
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, g_free);
+       x86_call_code (s->code, 0);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
+}
+
+stmt: PROC2 (reg, reg) {
+       x86_push_reg (s->code, tree->right->reg1);
+       x86_push_reg (s->code, tree->left->reg1);
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
+       x86_call_code (s->code, 0);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
+}
+
+stmt: PROC3 (reg, CPSRC (reg, reg)) {
+       x86_push_reg (s->code, tree->right->right->reg1);
+       x86_push_reg (s->code, tree->right->left->reg1);
+       x86_push_reg (s->code, tree->left->reg1);
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
+       x86_call_code (s->code, 0);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+}
+
+reg: FUNC1 (reg) {
+       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);
+
+       x86_push_reg (s->code, tree->left->reg1);
+
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
+       x86_call_code (s->code, 0);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
+
+       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);
+       }
+}
+
+
+reg: LOCALLOC (reg) {
+       int offset = 0;
+       /* size must be aligned to MONO_FRAME_ALIGNMENT bytes */
+       x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, MONO_FRAME_ALIGNMENT - 1);
+       x86_alu_reg_imm (s->code, X86_AND, tree->left->reg1, ~(MONO_FRAME_ALIGNMENT - 1));
+
+       /* allocate space on stack */
+       x86_alu_reg_reg (s->code, X86_SUB, X86_ESP, tree->left->reg1);
+
+       if (tree->data.i) {
+               /* initialize with zero */
+               if (tree->reg1 != X86_EAX && tree->left->reg1 != X86_EAX) {
+                       x86_push_reg (s->code, X86_EAX);
+                       offset += 4;
+               }
+               if (tree->reg1 != X86_ECX && tree->left->reg1 != X86_ECX) {
+                       x86_push_reg (s->code, X86_ECX);
+                       offset += 4;
+               }
+               if (tree->reg1 != X86_EDI && tree->left->reg1 != X86_EDI) {
+                       x86_push_reg (s->code, X86_EDI);
+                       offset += 4;
+               }
+               
+               x86_shift_reg_imm (s->code, X86_SHR, tree->left->reg1, 2);
+               if (tree->left->reg1 != X86_ECX)
+                       x86_mov_reg_imm (s->code, X86_ECX, tree->left->reg1);
+               x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
+                               
+               x86_lea_membase (s->code, X86_EDI, X86_ESP, offset);
+               x86_cld (s->code);
+               x86_prefix (s->code, X86_REP_PREFIX);
+               x86_stosl (s->code);
+               
+               if (tree->reg1 != X86_EDI && tree->left->reg1 != X86_EDI)
+                       x86_pop_reg (s->code, X86_EDI);
+               if (tree->reg1 != X86_ECX && tree->left->reg1 != X86_ECX)
+                       x86_pop_reg (s->code, X86_ECX);
+               if (tree->reg1 != X86_EAX && tree->left->reg1 != X86_EAX)
+                       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);
 }
 
@@ -1868,7 +2008,8 @@ reg: ISINST (reg) {
 stmt: INITOBJ (reg) {
        int i, j;
 
-       i = tree->data.i;
+       if (!(i = tree->data.i))
+               return;
 
        if (i == 1 || i == 2 || i == 4) {
                x86_mov_membase_imm (s->code, tree->left->reg1, 0, 0, i);
@@ -1878,21 +2019,17 @@ stmt: INITOBJ (reg) {
        i = tree->data.i / 4;
        j = tree->data.i % 4;
 
-       x86_push_reg (s->code, X86_EAX);
-       
        if (tree->left->reg1 != X86_EDI) {
                x86_push_reg (s->code, X86_EDI);
                x86_mov_reg_reg (s->code, X86_EDI, tree->left->reg1, 4);
        }
 
        if (i) {
-               x86_push_reg (s->code, X86_ECX);
                x86_alu_reg_reg (s->code, X86_XOR, X86_EAX, X86_EAX);
                x86_mov_reg_imm (s->code, X86_ECX, i);
                x86_cld (s->code);
                x86_prefix (s->code, X86_REP_PREFIX);
                x86_stosl (s->code);
-               x86_pop_reg (s->code, X86_ECX);
 
                for (i = 0; i < j; i++)
                        x86_stosb (s->code);
@@ -1907,21 +2044,448 @@ stmt: INITOBJ (reg) {
 
        if (tree->left->reg1 != X86_EDI)
                x86_pop_reg (s->code, X86_EDI);
+}
+
+stmt: CPBLK (reg, CPSRC (reg, CONST_I4)) {
+       int dest_reg = tree->left->reg1;
+       int source_reg = tree->right->left->reg1;
+       int count = tree->right->right->data.i;
+       int sreg = dest_reg != X86_EAX ? X86_EAX : X86_EDX;
+       int spill_pos = 0, dest_offset = 0, source_offset = 0;
+       int save_esi = FALSE, save_edi = FALSE;
+
+       // TODO: handle unaligned. prefix
+
+       switch (count) {
+       case 0:
+               break;
+       case 1:
+               x86_mov_reg_membase (s->code, sreg, source_reg, 0, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 1);
+               break;
+       case 2:
+               x86_mov_reg_membase (s->code, sreg, source_reg, 0, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 2);
+               break;
+       case 3:
+               x86_mov_reg_membase (s->code, sreg, source_reg, 0, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 2);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 2, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 2, sreg, 1);
+               break;
+       case 4:
+               x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+               break;
+       case 5:
+               x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 4, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 1);
+               break;
+       case 6:
+               x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 4, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 2);
+               break;
+       case 7:
+               x86_mov_reg_membase (s->code, sreg, source_reg, 0, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 0, sreg, 4);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 4, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 4, sreg, 2);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 6, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 6, sreg, 1);
+               break;
+       case 8:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               break;
+       case 9:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 8, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 1);
+               break;
+       case 10:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 8, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 2);
+               break;
+       case 11:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 8, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 2);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 10, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 10, sreg, 1);
+               break;
+       case 12:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+               break;
+       case 13:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 12, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 1);
+               break;
+       case 14:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 12, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 2);
+               break;
+       case 15:
+               x86_fild_membase (s->code, source_reg, 0, TRUE);
+               x86_fist_pop_membase (s->code, dest_reg, 0, TRUE);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 8, 4);
+               x86_mov_membase_reg (s->code, dest_reg, 8, sreg, 4);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 12, 2);
+               x86_mov_membase_reg (s->code, dest_reg, 12, sreg, 2);
+               x86_mov_reg_membase (s->code, sreg, source_reg, 14, 1);
+               x86_mov_membase_reg (s->code, dest_reg, 14, sreg, 1);
+               break;
+       default: 
+               g_assert (count > 15);
+
+               if (dest_reg != X86_ESI && source_reg != X86_ESI &&
+                   mono_regset_reg_used (s->rs, X86_ESI))
+                       save_esi = TRUE;
+               if (dest_reg != X86_EDI && source_reg != X86_EDI &&
+                   mono_regset_reg_used (s->rs, X86_EDI))
+                       save_edi = TRUE;
+
+               if (save_esi)
+                       x86_push_reg (s->code, X86_ESI);
+               if (save_edi)
+                       x86_push_reg (s->code, X86_EDI);
+
+               if (dest_reg == X86_ESI) {
+                       dest_offset = ++spill_pos; 
+               }          
+               if (source_reg == X86_EDI) {
+                       source_offset = ++spill_pos; 
+               }          
+
+               if (source_offset)
+                       x86_push_reg (s->code, source_reg);
+               if (dest_offset)
+                       x86_push_reg (s->code, dest_reg);
        
-       x86_pop_reg (s->code, X86_EAX);
+               if (source_reg != X86_ESI) {
+                       if (source_offset)
+                               x86_mov_reg_membase (s->code, X86_ESI, X86_ESP, (source_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_ESI, source_reg, 4);
+               }
+               if (dest_reg != X86_EDI) {
+                       if (dest_offset)
+                               x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+               }
+
+               x86_mov_reg_imm (s->code, X86_ECX, count >> 2); 
+               x86_cld (s->code);
+               x86_prefix (s->code, X86_REP_PREFIX);
+               x86_movsd (s->code);
+
+               switch (count & 3) {
+               case 1:
+                       x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 1);
+                       x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 1);
+                       break;
+               case 2:
+                       x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 2);
+                       x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 2);
+                       break;
+               case 3:
+                       x86_mov_reg_membase (s->code, sreg, X86_ESI, 0, 2);
+                       x86_mov_membase_reg (s->code, X86_EDI, 0, sreg, 2);
+                       x86_mov_reg_membase (s->code, sreg, X86_ESI, 2, 1);
+                       x86_mov_membase_reg (s->code, X86_EDI, 2, sreg, 1);
+                       break;
+               default:
+                       break;
+               }
+
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+
+               if (save_edi)
+                       x86_pop_reg (s->code, X86_EDI);
+               if (save_esi)
+                       x86_pop_reg (s->code, X86_ESI);
+
+               break;
+       }
+} cost {
+       MBCOND (mono_inline_memcpy);
+       return 0;
 }
 
 stmt: CPBLK (reg, CPSRC (reg, reg)) {
        int dest_reg = tree->left->reg1;
        int source_reg = tree->right->left->reg1;
        int size_reg = tree->right->right->reg1;
+       int spill_pos = 0, size_offset = 0, dest_offset = 0, source_offset = 0;
+       int save_esi = FALSE, save_edi = FALSE;
+
+       if (!mono_inline_memcpy) {
+               x86_push_reg (s->code, size_reg);
+               x86_push_reg (s->code, source_reg);
+               x86_push_reg (s->code, dest_reg);
+               mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memmove);
+               x86_call_code (s->code, 0);
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+       } else {
+               if (dest_reg != X86_ESI && source_reg != X86_ESI && size_reg != X86_ESI &&
+                   mono_regset_reg_used (s->rs, X86_ESI))
+                       save_esi = TRUE;
+               if (dest_reg != X86_EDI && source_reg != X86_EDI && size_reg != X86_EDI &&
+                   mono_regset_reg_used (s->rs, X86_EDI))
+                       save_edi = TRUE;
+
+               if (save_esi)
+                       x86_push_reg (s->code, X86_ESI);
+               if (save_edi)
+                       x86_push_reg (s->code, X86_EDI);
+
+               if (size_reg == X86_EDI || size_reg == X86_ESI) {
+                       size_offset = ++spill_pos; 
+               }          
+               if (dest_reg == X86_ECX || dest_reg == X86_ESI) {
+                       dest_offset = ++spill_pos; 
+               }          
+               if (source_reg == X86_ECX || source_reg == X86_EDI) {
+                       source_offset = ++spill_pos; 
+               }          
+
+               if (source_offset)
+                       x86_push_reg (s->code, source_reg);
+               if (dest_offset)
+                       x86_push_reg (s->code, dest_reg);
+               if (size_offset)
+                       x86_push_reg (s->code, size_reg);
+       
+               if (source_reg != X86_ESI) {
+                       if (source_offset)
+                               x86_mov_reg_membase (s->code, X86_ESI, X86_ESP, (source_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_ESI, source_reg, 4);
+               }
+               if (dest_reg != X86_EDI) {
+                       if (dest_offset)
+                               x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+               }
+               if (size_reg != X86_ECX) {
+                       if (size_offset)
+                               x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, (size_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_ECX, size_reg, 4);
+               }
 
-       x86_push_reg (s->code, size_reg);
-       x86_push_reg (s->code, source_reg);
-       x86_push_reg (s->code, dest_reg);
-       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memcpy);
-       x86_call_code (s->code, 0);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+               x86_push_reg (s->code, X86_ECX);
+               x86_shift_reg_imm (s->code, X86_SHR, X86_ECX, 2);
+
+               x86_cld (s->code);
+       
+               // move whole dwords first
+               x86_prefix (s->code, X86_REP_PREFIX);
+               x86_movsd (s->code);
+
+               x86_pop_reg (s->code, X86_ECX);
+               x86_alu_reg_imm (s->code, X86_AND, X86_ECX, 3);
+
+               // move remaining bytes (if any)
+               x86_prefix (s->code, X86_REP_PREFIX);
+               x86_movsb (s->code);
+
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+               
+               if (save_edi)
+                       x86_pop_reg (s->code, X86_EDI);
+               if (save_esi)
+                       x86_pop_reg (s->code, X86_ESI);
+       }
+}
+
+stmt: INITBLK (reg, CPSRC (reg, CONST_I4)) {
+       int dest_reg = tree->left->reg1;
+       int value_reg = tree->right->left->reg1;
+       int size = tree->right->right->data.i;
+       int spill_pos = 0, dest_offset = 0, value_offset = 0;
+       int save_edi = FALSE;
+       int i, j;
+
+       i = size / 4;
+       j = size % 4;
+
+       if (mono_inline_memcpy) {
+
+               if (dest_reg != X86_EDI && value_reg != X86_EDI &&
+                   mono_regset_reg_used (s->rs, X86_EDI)) {
+                       save_edi = TRUE;
+                       x86_push_reg (s->code, X86_EDI);
+               }
+
+               if (dest_reg == X86_ECX || dest_reg == X86_EAX) {
+                       dest_offset = ++spill_pos; 
+               }          
+               if (value_reg == X86_ECX || value_reg == X86_EDI) {
+                       value_offset = ++spill_pos; 
+               }          
+
+               if (value_offset)
+                       x86_push_reg (s->code, value_reg);
+               if (dest_offset)
+                       x86_push_reg (s->code, dest_reg);
+
+               if (value_reg != X86_EAX) {
+                       if (value_offset)
+                               x86_mov_reg_membase (s->code, X86_EAX, X86_ESP, (value_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_EAX, value_reg, 4);
+               }
+               if (dest_reg != X86_EDI) {
+                       if (dest_offset)
+                               x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+               }
+
+               x86_widen_reg (s->code, X86_EAX, X86_EAX, FALSE, FALSE);
+               x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+               x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 8);
+               x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+               x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+               x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 16);
+               x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+
+               if (i) {
+                       x86_mov_reg_imm (s->code, X86_ECX, i);
+                       x86_cld (s->code);
+                       x86_prefix (s->code, X86_REP_PREFIX);
+                       x86_stosd (s->code);
+               }
+
+               for (i = 0; i < j; i++)
+                       x86_stosb (s->code);
+       
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+
+               if (save_edi)
+                       x86_pop_reg (s->code, X86_EDI);
+
+       } else {
+               x86_push_imm (s->code, size);
+               x86_push_reg (s->code, value_reg);
+               x86_push_reg (s->code, dest_reg);
+               mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memset);
+               x86_call_code (s->code, 0);
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+       }
+} cost {
+       MBCOND (mono_inline_memcpy);
+       return 0;
+}
+
+stmt: INITBLK (reg, CPSRC (reg, reg)) {
+       int dest_reg = tree->left->reg1;
+       int value_reg = tree->right->left->reg1;
+       int size_reg = tree->right->right->reg1;
+       int spill_pos = 0, size_offset = 0, dest_offset = 0, value_offset = 0;
+       int save_edi = FALSE;
+
+       if (mono_inline_memcpy) {
+
+               if (dest_reg != X86_EDI && size_reg != X86_EDI && size_reg != X86_EDI &&
+                   mono_regset_reg_used (s->rs, X86_EDI)) {
+                       save_edi = TRUE;
+                       x86_push_reg (s->code, X86_EDI);
+               }
+
+               if (size_reg == X86_EDI || size_reg == X86_EAX) {
+                       size_offset = ++spill_pos; 
+               }          
+               if (dest_reg == X86_ECX || dest_reg == X86_EAX) {
+                       dest_offset = ++spill_pos; 
+               }          
+               if (value_reg == X86_ECX || value_reg == X86_EDI) {
+                       value_offset = ++spill_pos; 
+               }          
+
+               if (value_offset)
+                       x86_push_reg (s->code, value_reg);
+               if (dest_offset)
+                       x86_push_reg (s->code, dest_reg);
+               if (size_offset)
+                       x86_push_reg (s->code, size_reg);
+
+               if (value_reg != X86_EAX) {
+                       if (value_offset)
+                               x86_mov_reg_membase (s->code, X86_EAX, X86_ESP, (value_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_EAX, value_reg, 4);
+               }
+               if (dest_reg != X86_EDI) {
+                       if (dest_offset)
+                               x86_mov_reg_membase (s->code, X86_EDI, X86_ESP, (dest_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_EDI, dest_reg, 4);
+               }
+               if (size_reg != X86_ECX) {
+                       if (size_offset)
+                               x86_mov_reg_membase (s->code, X86_ECX, X86_ESP, (size_offset-1)<<2, 4);
+                       else
+                               x86_mov_reg_reg (s->code, X86_ECX, size_reg, 4);
+               }
+
+               x86_widen_reg (s->code, X86_EAX, X86_EAX, FALSE, FALSE);
+               x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+               x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 8);
+               x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+               x86_mov_reg_reg (s->code, X86_EDX, X86_EAX, 4);
+               x86_shift_reg_imm (s->code, X86_SHL, X86_EAX, 16);
+               x86_alu_reg_reg (s->code, X86_OR, X86_EAX, X86_EDX);
+
+               x86_push_reg (s->code, X86_ECX);
+               x86_shift_reg_imm (s->code, X86_SHR, X86_ECX, 2);
+               x86_cld (s->code);
+
+               // init whole dwords first
+               x86_prefix (s->code, X86_REP_PREFIX);
+               x86_stosd (s->code);
+
+               x86_pop_reg (s->code, X86_ECX);
+               x86_alu_reg_imm (s->code, X86_AND, X86_ECX, 3);
+
+               // init remaining bytes (if any)
+               x86_prefix (s->code, X86_REP_PREFIX);
+               x86_stosb (s->code);
+
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, spill_pos<<2);
+
+               if (save_edi)
+                       x86_pop_reg (s->code, X86_EDI);
+
+       } else {
+               x86_push_reg (s->code, size_reg);
+               x86_push_reg (s->code, value_reg);
+               x86_push_reg (s->code, dest_reg);
+               mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, memset);
+               x86_call_code (s->code, 0);
+               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 12);
+       }
 }
 
 stmt: NOP
@@ -2074,9 +2638,11 @@ stmt: RET_VOID {
        } 
 }
 
-
 stmt: ARG_I4 (LDIND_I4 (addr)) {
        MBTree *at = tree->left->left;
+       int pad = tree->data.arg_info.pad;
+
+       X86_ARG_PAD (pad);
 
        switch (at->data.ainfo.amode) {
 
@@ -2101,6 +2667,9 @@ stmt: ARG_I4 (LDIND_I4 (addr)) {
 
 stmt: ARG_I4 (LDIND_I4 (ADDR_L)) {
        int treg = VARINFO (s, tree->left->left->data.i).reg;
+       int pad = tree->data.arg_info.pad;
+
+       X86_ARG_PAD (pad);
        x86_push_reg (s->code, treg);
 } cost {
        MBCOND ((VARINFO (data, tree->left->left->data.i).reg >= 0));
@@ -2108,34 +2677,23 @@ stmt: ARG_I4 (LDIND_I4 (ADDR_L)) {
 }
 
 stmt: ARG_I4 (reg) {
-       x86_push_reg (s->code, tree->left->reg1);
-       PRINT_REG ("ARG_I4",  tree->left->reg1);
-}
-
-# fixme: we must free the allocated strings somewhere
-stmt: ARG_STRING (reg) {
-       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
-       x86_push_reg (s->code, X86_EAX);
-       x86_push_reg (s->code, X86_ECX);
-       x86_push_reg (s->code, X86_EDX);
+       int pad = tree->data.arg_info.pad;
 
+       X86_ARG_PAD (pad);
        x86_push_reg (s->code, tree->left->reg1);
-       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_string_to_utf8);
-       x86_call_code (s->code, 0);
-       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 4);
-       
-       x86_mov_membase_reg (s->code, X86_ESP, 12, X86_EAX, 4);
-
-       x86_pop_reg (s->code, X86_EDX);
-       x86_pop_reg (s->code, X86_ECX);
-       x86_pop_reg (s->code, X86_EAX);
 }
 
 stmt: ARG_I4 (ADDR_G) {
+       int pad = tree->data.arg_info.pad;
+
+       X86_ARG_PAD (pad);
        x86_push_imm (s->code, tree->left->data.p);
 }
 
 stmt: ARG_I4 (CONST_I4) "MB_USE_OPT1(0)" {
+       int pad = tree->data.arg_info.pad;
+
+       X86_ARG_PAD (pad);
        x86_push_imm (s->code, tree->left->data.i);
 }
 
@@ -2155,6 +2713,31 @@ stmt: CHECKTHIS (reg) {
        x86_alu_membase_imm (s->code, X86_CMP, tree->left->reg1, 0, 0);
 }
 
+stmt: JMP
+{
+       int pos = -4;
+
+       /* restore callee saved registers */
+       if (mono_regset_reg_used (s->rs, X86_EBX)) {
+               x86_mov_reg_membase (s->code, X86_EBX, X86_EBP, pos, 4);
+               pos -= 4;
+       }
+       if (mono_regset_reg_used (s->rs, X86_EDI)) {
+               x86_mov_reg_membase (s->code, X86_EDI, X86_EBP, pos, 4);
+               pos -= 4;
+       }
+       if (mono_regset_reg_used (s->rs, X86_ESI)) {
+               x86_mov_reg_membase (s->code, X86_ESI, X86_EBP, pos, 4);
+               pos -= 4;
+       }
+       /* restore ESP/EBP */
+       x86_leave (s->code);
+
+       /* jump to the method */
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->data.p);
+       x86_jump32 (s->code, 0);
+}
+
 this: NOP
 
 reg: CALL_I4 (this, reg) {
@@ -2169,23 +2752,11 @@ reg: CALL_I4 (this, reg) {
        if (lreg == treg || rreg == treg) 
                mono_assert_not_reached ();
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_call_reg (s->code, rreg);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-       
-       PRINT_REG ("CALL_I4", tree->reg1);
+       X86_CALL_END;
 
        mono_assert (tree->reg1 == X86_EAX);
 }
@@ -2197,37 +2768,37 @@ reg: CALL_I4 (this, ADDR_G) {
        if (lreg == treg) 
                treg = X86_EDX;
        
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-               x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
        x86_call_code (s->code, 0);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
-       PRINT_REG ("CALL_I4", tree->reg1);
+       X86_CALL_END;
 
        mono_assert (tree->reg1 == X86_EAX);
 }
 
 reg: LDVIRTFTN (reg, INTF_ADDR) {
-       int lreg = tree->left->reg1;
+       /* we cant return the value in the vtable, because it can be
+        * a magic trampoline, and we cant pass that to the outside world */
+       
+       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);
 
-       x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
-       x86_mov_reg_membase (s->code, lreg, lreg, 
-               G_STRUCT_OFFSET (MonoVTable, interface_offsets), 4);
-       x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
-       x86_mov_reg_membase (s->code, tree->reg1, lreg, tree->right->data.m->slot << 2, 4);
+       x86_push_imm (s->code, tree->right->data.m->klass->interface_id);
+       x86_push_reg (s->code, tree->left->reg1);
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldintftn);
+       x86_call_code (s->code, 0);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
+
+       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);
+       }
 }
 
 reg: CALL_I4 (this, INTF_ADDR) {
@@ -2237,16 +2808,7 @@ reg: CALL_I4 (this, INTF_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
        x86_mov_reg_membase (s->code, lreg, lreg, 
@@ -2254,20 +2816,32 @@ reg: CALL_I4 (this, INTF_ADDR) {
        x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
        x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
-       PRINT_REG ("CALL_I4(INTERFACE)", tree->reg1);
+       X86_CALL_END;
 
        mono_assert (tree->reg1 == X86_EAX);
 }
 
 reg: LDVIRTFTN (reg, VFUNC_ADDR) {
-       int lreg = tree->left->reg1;
+       /* we cant return the value in the vtable, because it can be
+        * a magic trampoline, and we cant pass that to the outside world */
        
-       x86_mov_reg_membase (s->code, tree->reg1, lreg, 0, 4);
-       
-       x86_mov_reg_membase (s->code, tree->reg1, tree->reg1, G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2), 4);
+       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);
+
+       x86_push_imm (s->code, tree->right->data.m->slot);
+       x86_push_reg (s->code, tree->left->reg1);
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldvirtftn);
+       x86_call_code (s->code, 0);
+       x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, 8);
+
+       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);
+       }
 }
 
 reg: LDFTN {
@@ -2277,7 +2851,7 @@ reg: LDFTN {
        x86_push_reg (s->code, X86_EDX);
 
        x86_push_imm (s->code, tree->data.m);
-       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_compile_method);
+       mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, mono_ldftn);
        x86_call_code (s->code, 0);
        x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, sizeof (gpointer));
 
@@ -2287,7 +2861,6 @@ reg: LDFTN {
                x86_mov_reg_reg (s->code, tree->reg1, X86_EAX, 4);
                x86_pop_reg (s->code, X86_EAX);
        }
-       PRINT_REG ("LDFTN", tree->reg1);
 }
 
 
@@ -2298,25 +2871,13 @@ reg: CALL_I4 (this, VFUNC_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);        
        x86_call_virtual (s->code, lreg, 
                G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
-       PRINT_REG ("CALL_I4(VIRTUAL)", tree->reg1);
+       X86_CALL_END;
 
        mono_assert (tree->reg1 == X86_EAX);
 }
@@ -2328,23 +2889,31 @@ stmt: CALL_VOID (this, ADDR_G) {
        if (lreg == treg) 
                treg = X86_EDX;
        
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-               x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
        x86_call_code (s->code, 0);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+       X86_CALL_END;
+}
+
+stmt: CALL_VOID (this, reg) {
+       int treg = X86_EAX;
+       int lreg = tree->left->reg1;
+       int rreg = tree->right->reg1;
+
+       if (lreg == treg || rreg == treg) 
+               treg = X86_EDX;
+       if (lreg == treg || rreg == treg) 
+               treg = X86_ECX;
+       if (lreg == treg || rreg == treg) 
+               mono_assert_not_reached ();
+       
+       X86_CALL_BEGIN;
+
+       x86_call_reg (s->code, tree->right->reg1);
+
+       X86_CALL_END;
 }
 
 stmt: CALL_VOID (this, INTF_ADDR) {
@@ -2354,16 +2923,7 @@ stmt: CALL_VOID (this, INTF_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
        x86_mov_reg_membase (s->code, lreg, lreg, 
@@ -2371,8 +2931,7 @@ stmt: CALL_VOID (this, INTF_ADDR) {
        x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
        x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+       X86_CALL_END;
 }
 
 stmt: CALL_VOID (this, VFUNC_ADDR) {
@@ -2382,23 +2941,13 @@ stmt: CALL_VOID (this, VFUNC_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
        x86_call_virtual (s->code, lreg, 
                G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+       X86_CALL_END;
 }
 
 stmt: SWITCH (reg) {
@@ -3055,6 +3604,28 @@ lreg: REM_UN (lreg, lreg) {
                     tree->reg2 == X86_EDX);
 }
 
+lreg: CALL_I8 (this, reg) {
+       int treg = X86_EAX;
+       int lreg = tree->left->reg1;
+       int rreg = tree->right->reg1;
+       
+       if (lreg == treg || rreg == treg) 
+               treg = X86_EDX;
+       if (lreg == treg || rreg == treg) 
+               treg = X86_ECX;
+       if (lreg == treg || rreg == treg) 
+               mono_assert_not_reached ();
+
+       X86_CALL_BEGIN;
+
+       x86_call_reg (s->code, rreg);
+
+       X86_CALL_END;
+
+       mono_assert (tree->reg1 == X86_EAX);
+       mono_assert (tree->reg2 == X86_EDX);
+}
+
 lreg: CALL_I8 (this, ADDR_G) {
        int lreg = tree->left->reg1;
        int treg = X86_EAX;
@@ -3062,23 +3633,12 @@ lreg: CALL_I8 (this, ADDR_G) {
        if (lreg == treg) 
                treg = X86_EDX;
        
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-               x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
        x86_call_code (s->code, 0);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+       X86_CALL_END;
 
        mono_assert (tree->reg1 == X86_EAX);
        mono_assert (tree->reg2 == X86_EDX);
@@ -3091,26 +3651,13 @@ lreg: CALL_I8 (this, VFUNC_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
        x86_call_virtual (s->code, lreg, 
                G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
-       PRINT_REG ("CALL0_I8(VIRTUAL)", tree->reg1);
-       PRINT_REG ("CALL1_I8(VIRTUAL)", tree->reg2);
+       X86_CALL_END;
 
        mono_assert (tree->reg1 == X86_EAX);
        mono_assert (tree->reg2 == X86_EDX);
@@ -3123,16 +3670,7 @@ lreg: CALL_I8 (this, INTF_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
        x86_mov_reg_membase (s->code, lreg, lreg, 
@@ -3140,10 +3678,7 @@ lreg: CALL_I8 (this, INTF_ADDR) {
        x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
        x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
-
-       PRINT_REG ("CALL_I8(INTERFACE)", tree->reg1);
+       X86_CALL_END;
 
        mono_assert (tree->reg1 == X86_EAX);
        mono_assert (tree->reg2 == X86_EDX);
@@ -3172,6 +3707,9 @@ stmt: RET (lreg) {
 
 
 stmt: ARG_I8 (lreg) {
+       int pad = tree->data.arg_info.pad;
+
+       X86_ARG_PAD (pad);
        x86_push_reg (s->code, tree->left->reg2);
        x86_push_reg (s->code, tree->left->reg1);
 }
@@ -3602,7 +4140,7 @@ freg: CONV_R_UN (lreg) {
        x86_fst80_membase (s->code, X86_ESP, 0);
 
        /* test if lreg is negative */
-       x86_test_reg_reg (s->code, tree->left->reg1, tree->left->reg1);
+       x86_test_reg_reg (s->code, tree->left->reg2, tree->left->reg2);
        br [0] = s->code; x86_branch8 (s->code, X86_CC_GEZ, 0, TRUE);
 
        /* add correction constant mn */
@@ -3610,7 +4148,7 @@ freg: CONV_R_UN (lreg) {
        x86_fld80_membase (s->code, X86_ESP, 0);
        x86_fp_op_reg (s->code, X86_FADD, 1, TRUE);
        x86_fst80_membase (s->code, X86_ESP, 0);
-
+       //x86_breakpoint (s->code);
        x86_patch (br [0], s->code);
 
        x86_fld80_membase (s->code, X86_ESP, 0);
@@ -3722,6 +4260,16 @@ freg: DIV (freg, freg) {
        x86_fp_op_reg (s->code, X86_FDIV, 1, TRUE);
 }
 
+freg: CKFINITE (freg) {
+       x86_push_reg (s->code, X86_EAX);
+       x86_fxam (s->code);
+       x86_fnstsw (s->code);
+       x86_alu_reg_imm (s->code, X86_AND, X86_EAX, 0x4100);
+       x86_alu_reg_imm (s->code, X86_CMP, X86_EAX, 0x0100);
+       x86_pop_reg (s->code, X86_EAX);
+       EMIT_COND_SYSTEM_EXCEPTION (X86_CC_NE, FALSE, "ArithmeticException");
+}
+
 freg: REM (freg, freg) {
        guint8 *l1, *l2;
 
@@ -3876,12 +4424,16 @@ stmt: REMOTE_STIND_R8 (reg, freg) {
 }
 
 stmt: ARG_R4 (freg) {
-       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4);
+       int pad = tree->data.arg_info.pad;
+
+       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 4 + pad);
        x86_fst_membase (s->code, X86_ESP, 0, FALSE, TRUE);
 }
 
 stmt: ARG_R8 (freg) {
-       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8);
+       int pad = tree->data.arg_info.pad;
+
+       x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, 8 + pad);
        x86_fst_membase (s->code, X86_ESP, 0, TRUE, TRUE);
 }
 
@@ -3945,6 +4497,25 @@ stmt: CBRANCH (COMPARE (freg, freg)) {
        }
 }
 
+freg: CALL_R8 (this, reg) {
+       int treg = X86_EAX;
+       int lreg = tree->left->reg1;
+       int rreg = tree->right->reg1;
+       
+       if (lreg == treg || rreg == treg) 
+               treg = X86_EDX;
+       if (lreg == treg || rreg == treg) 
+               treg = X86_ECX;
+       if (lreg == treg || rreg == treg) 
+               mono_assert_not_reached ();
+
+       X86_CALL_BEGIN;
+
+       x86_call_reg (s->code, rreg);
+
+       X86_CALL_END;
+}
+
 freg: CALL_R8 (this, ADDR_G) {
        int lreg = tree->left->reg1;
        int treg = X86_EAX;
@@ -3952,23 +4523,12 @@ freg: CALL_R8 (this, ADDR_G) {
        if (lreg == treg) 
                treg = X86_EDX;
        
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-               x86_alu_membase_imm (s->code, X86_CMP, lreg, 0, 0);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, tree->right->data.p);
        x86_call_code (s->code, 0);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+       X86_CALL_END;
 }
 
 freg: CALL_R8 (this, INTF_ADDR) {
@@ -3978,16 +4538,7 @@ freg: CALL_R8 (this, INTF_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
        x86_mov_reg_membase (s->code, lreg, lreg, 
@@ -3995,8 +4546,7 @@ freg: CALL_R8 (this, INTF_ADDR) {
        x86_mov_reg_membase (s->code, lreg, lreg, tree->right->data.m->klass->interface_id << 2, 4);
        x86_call_virtual (s->code, lreg, tree->right->data.m->slot << 2);
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+       X86_CALL_END;
 }
 
 freg: CALL_R8 (this, VFUNC_ADDR) {
@@ -4006,23 +4556,13 @@ freg: CALL_R8 (this, VFUNC_ADDR) {
        if (lreg == treg) 
                treg = X86_EDX;
 
-       if (tree->left->op != MB_TERM_NOP) {
-               mono_assert (lreg >= 0);
-               x86_push_reg (s->code, lreg);
-       }
-
-       if (tree->data.ci.vtype_num) {
-               int offset = VARINFO (s, tree->data.ci.vtype_num).offset;
-               x86_lea_membase (s->code, treg, X86_EBP, offset);
-               x86_push_reg (s->code, treg);
-       }
+       X86_CALL_BEGIN;
 
        x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
        x86_call_virtual (s->code, lreg, 
                G_STRUCT_OFFSET (MonoVTable, vtable) + (tree->right->data.m->slot << 2));
 
-       if (tree->data.ci.args_size)
-               x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.ci.args_size);
+       X86_CALL_END;
 }
 
 stmt: RET (freg) {
@@ -4032,6 +4572,18 @@ stmt: RET (freg) {
        }
 }
 
+freg: SIN (freg) {
+       x86_fsin (s->code);
+}
+
+freg: COS (freg) {
+       x86_fcos (s->code);
+}
+
+freg: SQRT (freg) {
+       x86_fsqrt (s->code);
+}
+
 # support for value types
 
 reg: LDIND_OBJ (reg) {
@@ -4055,7 +4607,7 @@ stmt: REMOTE_STIND_OBJ (reg, reg) {
        int treg = X86_EAX;
        int lreg = tree->left->reg1;
        int rreg = tree->right->reg1;
-       int offset;
+       int size, offset;
 
        if (lreg == treg)
                treg = X86_EDX;
@@ -4080,12 +4632,14 @@ stmt: REMOTE_STIND_OBJ (reg, reg) {
        br [1] = s->code; x86_jump8 (s->code, 0);
 
        x86_patch (br [0], s->code);
+
        offset = tree->data.fi.klass->valuetype ? tree->data.fi.field->offset - sizeof (MonoObject) : 
                tree->data.fi.field->offset;
 
-       x86_push_imm (s->code, mono_class_value_size (tree->data.fi.klass, NULL));
+       size = mono_class_value_size (tree->data.fi.field->type->data.klass, NULL);
+       x86_push_imm (s->code, size);
        x86_push_reg (s->code, tree->right->reg1);
-       x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, sizeof (MonoObject));      
+       x86_alu_reg_imm (s->code, X86_ADD, tree->left->reg1, offset);   
        x86_push_reg (s->code, tree->left->reg1);
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
        x86_call_code (s->code, 0);
@@ -4095,17 +4649,21 @@ stmt: REMOTE_STIND_OBJ (reg, reg) {
 }
 
 stmt: ARG_OBJ (CONST_I4) {
+       int pad = tree->data.arg_info.pad;
+
+       X86_ARG_PAD (pad);
        x86_push_imm (s->code, tree->left->data.i);     
 }
 
 stmt: ARG_OBJ (reg) {
-       int size = tree->data.i;
+       int size = tree->data.arg_info.size;
+       int pad = tree->data.arg_info.pad;
        int sa;
        
-       mono_assert (size > 0);
+       if (!size) 
+               return;
 
-       sa = size + 3;
-       sa &= ~3;
+       sa = size + pad;
 
        /* reserve space for the argument */
        x86_alu_reg_imm (s->code, X86_SUB, X86_ESP, sa);
@@ -4135,7 +4693,6 @@ stmt: RET_OBJ (reg) {
        x86_push_reg (s->code, tree->left->reg1);
        x86_push_membase (s->code, X86_EBP, 8);
 
-
        mono_add_jump_info (s, s->code, MONO_JUMP_INFO_ABS, MEMCOPY);
        x86_call_code (s->code, 0);
 
@@ -4230,28 +4787,6 @@ mono_llrem_un (guint64 a, guint64 b)
        return a % b;
 }
 
-MBTree *
-mono_ctree_new (MonoMemPool *mp, int op, MBTree *left, MBTree *right)
-{
-       MBTree *t = mono_mempool_alloc0 (mp, sizeof (MBTree));
-
-       t->op = op;
-       t->left = left;
-       t->right = right;
-       t->reg1 = -1;
-       t->reg2 = -1;
-       t->reg3 = -1;
-       t->svt = VAL_UNKNOWN;
-       t->cli_addr = -1;
-       return t;
-}
-
-MBTree *
-mono_ctree_new_leaf (MonoMemPool *mp, int op)
-{
-       return mono_ctree_new (mp, op, NULL, NULL);
-}
-
 MonoArray*
 mono_array_new_wrapper  (MonoClass *eclass, guint32 n)
 {
@@ -4289,9 +4824,8 @@ mono_ldsflda (MonoClass *klass, int offset)
        return addr;
 }
 
-#ifdef DEBUG
 void *
-MEMCOPY (void *dest, const void *src, size_t n)
+debug_memcopy (void *dest, const void *src, size_t n)
 {
        int i, l = n;
 
@@ -4303,7 +4837,6 @@ MEMCOPY (void *dest, const void *src, size_t n)
        
        return memcpy (dest, src, n);
 }
-#endif
 
 void mono_emit_fast_iconv (MBCGEN_TYPE* s, MBTREE_TYPE* tree)
 {
@@ -4372,3 +4905,73 @@ void mono_emit_fast_iconv_i8 (MBCGEN_TYPE* s, MBTREE_TYPE* tree)
        x86_patch (br[1], s->code);
        x86_patch (br[2], s->code);
 }
+
+gpointer 
+mono_ldvirtftn (MonoObject *this, int slot)
+{
+       MonoClass *class;
+       MonoMethod *m;
+       gpointer addr;
+       gboolean is_proxy = FALSE;
+       g_assert (this);
+
+       if ((class = this->vtable->klass) == mono_defaults.transparent_proxy_class) {
+               class = ((MonoTransparentProxy *)this)->klass;
+               is_proxy = TRUE;
+       }
+
+       
+       g_assert (slot <= class->vtable_size);
+
+       m = class->vtable [slot];
+
+       if (is_proxy) {
+               return mono_jit_create_remoting_trampoline (m);
+       } else {
+               EnterCriticalSection (metadata_section);
+               addr = mono_compile_method (m);
+               LeaveCriticalSection (metadata_section);
+               return addr;
+       }
+}
+
+gpointer 
+mono_ldintftn (MonoObject *this, int slot)
+{
+       MonoClass *class;
+       MonoMethod *m;
+       gpointer addr;
+       gboolean is_proxy = FALSE;
+       g_assert (this);
+
+       if ((class = this->vtable->klass) == mono_defaults.transparent_proxy_class) {
+               class = ((MonoTransparentProxy *)this)->klass;
+               is_proxy = TRUE;
+       }
+
+       g_assert (slot < class->interface_count);
+
+       slot = class->interface_offsets [slot];
+
+       m = class->vtable [slot];
+
+       if (is_proxy) {
+               return mono_jit_create_remoting_trampoline (m);
+       } else {
+               EnterCriticalSection (metadata_section);
+               addr = mono_compile_method (m);
+               LeaveCriticalSection (metadata_section);
+               return addr;
+       }
+}
+
+gpointer mono_ldftn (MonoMethod *method)
+{
+       gpointer addr;
+
+       EnterCriticalSection (metadata_section);
+       addr = mono_compile_method (method);
+       LeaveCriticalSection (metadata_section);
+
+       return addr;
+}