[Mono-list] jit patch: console.exe works

Dietmar Maurer dietmar@ximian.com
16 Nov 2001 15:57:52 +0100


Index: mono/jit/ChangeLog
===================================================================
RCS file: /cvs/public/mono/mono/jit/ChangeLog,v
retrieving revision 1.43
diff -u -r1.43 ChangeLog
--- mono/jit/ChangeLog	2001/11/15 11:11:20	1.43
+++ mono/jit/ChangeLog	2001/11/16 10:55:38
@@ -1,3 +1,13 @@
+2001-11-16  Dietmar Maurer  <dietmar@ximian.com>
+
+	* x86.brg (STRING_ARG): impl. a way to marshal strings. This
+	will be extensible to handle all possible kinds of marshalling
+	requirements. 
+
+	* jit.c (map_call_type): added MB_TERM_CALL_VOID
+	(mono_analyze_stack): impl. LDELEMA, reimplemented CALL
+	instructions to handle this arguments more effectively.
+
 2001-11-15  Dietmar Maurer  <dietmar@ximian.com>
 
 	* Makefile.am (mono_SOURCES): renamed testjit to mono
Index: mono/jit/emit-x86.c
===================================================================
RCS file: /cvs/public/mono/mono/jit/emit-x86.c,v
retrieving revision 1.17
diff -u -r1.17 emit-x86.c
--- mono/jit/emit-x86.c	2001/11/15 11:11:20	1.17
+++ mono/jit/emit-x86.c	2001/11/16 10:55:38
@@ -633,10 +633,10 @@
 	g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
 	g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
 
-	//g_assert (!method->addr);
-	printf ("Start JIT compilation %p %p\n", method, method->addr);
-	printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
-		method->klass->name, method->name);
+	if (mono_jit_trace_calls) {
+		printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
+			method->klass->name, method->name);
+	}
 
 	cfg = mono_cfg_new (method, mp);
 
@@ -681,8 +681,10 @@
 
 	mono_mempool_destroy (mp);
 
-	printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
-		method->klass->name, method->name, method, method->addr);
+	if (mono_jit_trace_calls) {
+		printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
+			method->klass->name, method->name, method, method->addr);
+	}
 
 	return method->addr;
 }
Index: mono/jit/jit.c
===================================================================
RCS file: /cvs/public/mono/mono/jit/jit.c,v
retrieving revision 1.44
diff -u -r1.44 jit.c
--- mono/jit/jit.c	2001/11/15 11:11:20	1.44
+++ mono/jit/jit.c	2001/11/16 10:55:38
@@ -114,23 +114,10 @@
 	break;                                                                \
 }
 
-/*	
 #define MAKE_STELEM(name, op, s)                                              \
 case CEE_##name: {                                                            \
 	++ip;                                                                 \
 	sp -= 3;                                                              \
-	t1 = mono_ctree_new (mp, MB_TERM_LDELEMA, sp [0], sp [1]);            \
-	t1->data.i = s;                                                       \
-	t1 = mono_ctree_new (mp, op, t1, sp [2]);                             \
-	ADD_TREE (t1);                                                        \
-	break;                                                                \
-}
-*/
-
-#define MAKE_STELEM(name, op, s)                                              \
-case CEE_##name: {                                                            \
-	++ip;                                                                 \
-	sp -= 3;                                                              \
         t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);                      \
         t1->data.i = s;                                                       \
         t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1);                    \
@@ -393,6 +380,8 @@
 {
 	switch (type->type) {
 	case MONO_TYPE_VOID:
+		*svt = VAL_UNKNOWN;
+		return MB_TERM_CALL_VOID;
 	case MONO_TYPE_I1:
 	case MONO_TYPE_U1:
 	case MONO_TYPE_BOOLEAN:
@@ -402,9 +391,11 @@
 	case MONO_TYPE_I:
 	case MONO_TYPE_I4:
 	case MONO_TYPE_U4:
-	case MONO_TYPE_VALUETYPE:
 		*svt = VAL_I32;
 		return MB_TERM_CALL_I4;
+	case MONO_TYPE_VALUETYPE:
+		*svt = VAL_I32;
+		return MB_TERM_CALL_VOID;
 	case MONO_TYPE_CLASS:
 	case MONO_TYPE_OBJECT:
 	case MONO_TYPE_STRING:
@@ -447,8 +438,11 @@
 	else 
 		printf (" %s", mono_burg_term_string [tree->op]);
 
-	if (tree->op == MB_TERM_ADDR_L)
+	switch (tree->op) {
+	case MB_TERM_ADDR_L:
 		printf ("[%d]", tree->data.i);
+		break;
+	}
 
 	g_assert (!(tree->right && !tree->left));
 
@@ -974,6 +968,7 @@
 		case CEE_LDFLDA:
 		case CEE_STSFLD: 
 		case CEE_STFLD:
+		case CEE_LDELEMA:
 		case CEE_NEWOBJ:
 		case CEE_CPOBJ:
 		case CEE_NEWARR:
@@ -1606,6 +1601,35 @@
 			ADD_TREE (t1);
 			break;
 		}
+		case CEE_LDELEMA: {
+			MonoClass *class;
+			guint32 esize, token;
+
+			++ip;
+			token = read32 (ip);
+			ip += 4;
+			sp -= 2;
+
+			class = mono_class_get (image, token);
+
+			if (!class->inited)
+				mono_jit_init_class (class);
+
+			esize = mono_class_instance_size (class);
+			if (class->valuetype)
+				esize -= sizeof (MonoObject);
+
+			t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+			t1->data.i = esize;
+			t1 = mono_ctree_new (mp, MB_TERM_MUL, sp [1], t1);
+			t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+			t2->data.i = G_STRUCT_OFFSET (MonoArray, vector);
+			t2 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t2);
+			t1 = mono_ctree_new (mp, MB_TERM_ADD, t1, t2);
+
+			PUSH_TREE (t1, VAL_POINTER);
+			break;
+		}
 		case CEE_NOP: { 
 			++ip;
 			break;
@@ -1699,6 +1723,7 @@
 		}
 		case CEE_NEWOBJ: {
 			MonoMethodSignature *csig;
+			MethodCallInfo *ci;
 			MonoMethod *cm;
 			MBTree *this = NULL;
 			guint32 token;
@@ -1713,6 +1738,9 @@
 			g_assert (cm);
 			g_assert (!strcmp (cm->name, ".ctor"));
 			
+			ci =  mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
+			ci->m = cm;
+
 			csig = cm->signature;
 			g_assert (csig->call_convention == MONO_CALL_DEFAULT);
 			g_assert (csig->hasthis);
@@ -1720,13 +1748,10 @@
 			arg_sp = sp -= csig->param_count;
 
 			if (cm->klass->parent == mono_defaults.array_class) {
-
 				newarr = TRUE;
 				this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
 				this->data.p = cm;
-
-			} else {
-				
+			} else {				
 				this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
 				this->data.p = cm->klass;
 				this->svt = VAL_POINTER;
@@ -1734,7 +1759,6 @@
 				t1 = mono_store_tree (cfg, -1, this, &this);
 				g_assert (t1);
 				ADD_TREE (t1);
-
 			}
 
 			for (i = csig->param_count - 1; i >= 0; i--) {
@@ -1744,18 +1768,22 @@
 				args_size += (size + 3) & ~3;
 			}
 
-			t1 = mono_ctree_new (mp, MB_TERM_ARG, this, NULL);	
-			ADD_TREE (t1);
-			args_size += sizeof (gpointer);
-			
+			args_size += sizeof (gpointer); /* this argument */		
+			ci->args_size = args_size;
+
 			if (newarr) {
 
 				t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
 				t2->data.p = mono_array_new_va;
 
-				t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, t2, NULL);
-				t1->data.i = args_size;
-				t1->svt = VAL_I32;
+				t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
+				t1->data.p = ci;
+				t1->svt = VAL_POINTER;
+
+				t1 = mono_store_tree (cfg, -1, t1, &t2);
+				g_assert (t1);
+				ADD_TREE (t1);
+				PUSH_TREE (t2, t2->svt);
 
 			} else {
 				
@@ -1765,30 +1793,22 @@
 				t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
 				t2->data.p = (char *)cm + G_STRUCT_OFFSET (MonoMethod, addr);
 				t2 = mono_ctree_new (mp, MB_TERM_LDIND_I4, t2, NULL);
-			}
-
-			t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), t2, NULL);
-			t1->data.i = args_size;
-			t1->svt = svt;
 
-			if (newarr) {
-     
-				t1 = mono_store_tree (cfg, -1, t1, &t2);
-				g_assert (t1);
-				ADD_TREE (t1);
-				PUSH_TREE (t2, t2->svt);
-
-			} else {
+				t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
+				t1->data.p = ci;
+				t1->svt = svt;
 
 				ADD_TREE (t1);			
 				t1 = ctree_create_dup (mp, this);		
 				PUSH_TREE (t1, t1->svt);
+
 			}
 			break;
 		}
 		case CEE_CALL: 
 		case CEE_CALLVIRT: {
 			MonoMethodSignature *csig;
+			MethodCallInfo *ci;
 			MonoMethod *cm;
 			MBTree *this = NULL;
 			guint32 token;
@@ -1796,6 +1816,7 @@
 			int virtual_= *ip == CEE_CALLVIRT;
 			gboolean array_set = FALSE;
 			gboolean array_get = FALSE;
+			gboolean pinvoke = FALSE;
 			int nargs, vtype_num = 0;
 
 			++ip;
@@ -1804,7 +1825,13 @@
 
 			cm = mono_get_method (image, token, NULL);
 			g_assert (cm);
-			
+
+			ci =  mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
+			ci->m = cm;
+
+			if (cm->flags &  METHOD_ATTRIBUTE_PINVOKE_IMPL)
+			    pinvoke = TRUE;
+
 			if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
 			    !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
 				virtual = 0;
@@ -1829,7 +1856,11 @@
 			}
 
 			for (i = nargs - 1; i >= 0; i--) {
-				t1 = mono_ctree_new (mp, MB_TERM_ARG, arg_sp [i], NULL);	
+				if (pinvoke && cm->signature->params [i]->type == MONO_TYPE_STRING) {
+					t1 = mono_ctree_new (mp, MB_TERM_STRING_ARG, arg_sp [i], NULL);
+				} else {
+					t1 = mono_ctree_new (mp, MB_TERM_ARG, arg_sp [i], NULL);
+				}	
 				ADD_TREE (t1);
 				size = mono_type_size (cm->signature->params [i], &align);
 				args_size += (size + 3) & ~3;
@@ -1837,40 +1868,27 @@
 
 			if (csig->hasthis) {
 				this = *(--sp);
-				t1 = mono_ctree_new (mp, MB_TERM_ARG, this, NULL);	
-				ADD_TREE (t1);
 				args_size += sizeof (gpointer);
-			}
+			} else
+				this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
 
 			if (csig->ret->type == MONO_TYPE_VALUETYPE) {
 				int size, align;
-
-				if ((size = mono_type_size (csig->ret, &align)) > 4 || size == 3) {
-
-					//printf ("VALUETYPE RETURN %s.%s::%s %d\n", cm->klass->name_space, 
-					//cm->klass->name, cm->name, size);
-				
+				if ((size = mono_type_size (csig->ret, &align)) > 4 || size == 3)
 					vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
-				
-					t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
-					t2->data.i = vtype_num;
-				
-					t1 = mono_ctree_new (mp, MB_TERM_ARG, t2, NULL);	
-					ADD_TREE (t1);
-					t1->svt = VAL_POINTER;
-
-					args_size += sizeof (gpointer);
-				}
 			}
 
+			ci->args_size = args_size;
+			ci->vtype_num = vtype_num;
+
 			if (array_get) {
 				int size, align, vnum;
 				
 				t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
 				t2->data.p = ves_array_element_address;
 
-				t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, t2, NULL);
-				t1->data.i = args_size;
+				t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
+				t1->data.p = ci;
 
 				t1 = mono_ctree_new (mp, map_ldind_type (csig->ret, &svt), t1, NULL);
 				t1->svt = svt;		
@@ -1892,8 +1910,8 @@
 				t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
 				t2->data.p = ves_array_element_address;
 
-				t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, t2, NULL);
-				t1->data.i = args_size;
+				t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
+				t1->data.p = ci;
 
 				t1 = mono_ctree_new (mp, map_stind_type (csig->params [nargs]), t1, arg_sp [nargs]);
 				ADD_TREE (t1);
@@ -1901,16 +1919,13 @@
 			} else {
 
 				if (virtual) {
-				
-					t2 = ctree_create_dup (mp, this);
-			       
 					if (!cm->klass->metadata_inited)
 						mono_class_metadata_init (cm->klass);
 
 					if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
-						t2 = mono_ctree_new (mp, MB_TERM_INTF_ADDR, t2, NULL);
+						t2 = mono_ctree_new_leaf (mp, MB_TERM_INTF_ADDR);
 					else 
-						t2 = mono_ctree_new (mp, MB_TERM_VFUNC_ADDR, t2, NULL);
+						t2 = mono_ctree_new_leaf (mp, MB_TERM_VFUNC_ADDR);
 	 
 					t2->data.m = cm;
 
@@ -1924,8 +1939,8 @@
 					t2 = mono_ctree_new (mp, MB_TERM_LDIND_I4, t2, NULL);
 				}
 
-				t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), t2, NULL);
-				t1->data.i = args_size;
+				t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
+				t1->data.p = ci;
 				t1->svt = svt;
 
 				if (csig->ret->type != MONO_TYPE_VOID) {
@@ -2317,7 +2332,7 @@
 			++ip;
 			--sp;
 
-			t1 = ctree_create_store (mp, MB_TERM_ADDR_L, *sp, LOCAL_TYPE (*ip), 
+			t1 = ctree_create_store (mp, MB_TERM_ADDR_L, *sp, ARG_TYPE (*ip), 
 						 (gpointer)ARG_POS (*ip));
 			++ip;
 
@@ -2479,7 +2494,7 @@
 
 			} else {
 				superblock_end = TRUE;
-				printf ("unreached block %d\n", i);
+				//printf ("unreached block %d\n", i);
 				repeat = TRUE;
 				g_assert (repeat_count < 10);
 			}
Index: mono/jit/jit.h
===================================================================
RCS file: /cvs/public/mono/mono/jit/jit.h,v
retrieving revision 1.12
diff -u -r1.12 jit.h
--- mono/jit/jit.h	2001/11/15 11:11:20	1.12
+++ mono/jit/jit.h	2001/11/16 10:55:38
@@ -65,6 +65,12 @@
 	guint32           epilog;
 } MonoFlowGraph;
 
+typedef struct {
+	MonoMethod *m;
+	int args_size;
+	int vtype_num;
+} MethodCallInfo;
+
 extern gboolean mono_jit_dump_asm;
 extern gboolean mono_jit_dump_forest;
 extern gboolean mono_jit_trace_calls;
Index: mono/jit/x86.brg
===================================================================
RCS file: /cvs/public/mono/mono/jit/x86.brg,v
retrieving revision 1.36
diff -u -r1.36 x86.brg
--- mono/jit/x86.brg	2001/11/15 11:11:20	1.36
+++ mono/jit/x86.brg	2001/11/16 10:55:38
@@ -66,6 +66,7 @@
 		gpointer p;
 		MonoBBlock *bb;
 		MonoMethod *m;
+		MethodCallInfo *ci;
 		X86AddressInfo ainfo;
 	} data;
 };
@@ -139,7 +140,7 @@
 %term LDIND_I1 LDIND_U1 LDIND_I2 LDIND_U2 LDIND_I4 LDIND_I8 LDIND_R4 LDIND_R8
 %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 CALL_I4 CALL_I8 CALL_R8
+%term ADDR_L ADDR_G ARG STRING_ARG CALL_I4 CALL_I8 CALL_R8 CALL_VOID
 %term BREAK SWITCH BR RET RETV 
 %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 
@@ -1056,6 +1057,24 @@
 	x86_push_reg (s->code, tree->left->reg1);
 }
 
+# fixme: we must free the allocated strings somewhere
+stmt: STRING_ARG (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);
+
+	x86_push_reg (s->code, tree->left->reg1);
+	x86_call_code (s->code, mono_string_to_utf8);
+	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 (ADDR_G) {
 	x86_push_imm (s->code, tree->left->data.p);
 }
@@ -1063,86 +1082,217 @@
 stmt: ARG (CONST_I4) "MB_USE_OPT1(0)" {
 	x86_push_imm (s->code, tree->left->data.i);
 }
+
+this: reg
+
+this: NOP
 
-reg: CALL_I4 (CONST_I4) {
+reg: CALL_I4 (this, reg) {
+	MethodCallInfo *ci = tree->data.ci;
+	int treg = X86_EAX;
+	int lreg = tree->left->reg1;
+	int rreg = tree->right->reg1;
 	
-	x86_call_code (s->code, tree->left->data.p);
+	if (lreg == treg || rreg == treg) 
+		treg = X86_EDX;
+	if (lreg == treg || rreg == treg) 
+		treg = X86_ECX;
+	if (lreg == treg || rreg == treg) 
+		g_assert_not_reached ();
+
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	x86_call_reg (s->code, rreg);
+
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 	
+	PRINT_REG ("CALL_I4", tree->reg1);
+
 	g_assert (tree->reg1 == X86_EAX);
 }
+
+reg: CALL_I4 (this, LDIND_I4 (ADDR_G)) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-reg: CALL_I4 (LDIND_I4 (ADDR_G)) {
+	if (lreg == treg) 
+		treg = X86_EDX;
 	
-	x86_call_mem (s->code, tree->left->left->data.p);
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
+
+	x86_call_mem (s->code, tree->right->left->data.p);
+
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 
-	if (tree->dat_.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	PRINT_REG ("CALL_I4", tree->reg1);
 
 	g_assert (tree->reg1 == X86_EAX);
 }
 
-reg: CALL_I4 (INTF_ADDR (reg)) {
-	int reg1 = tree->left->left->reg1;
+reg: CALL_I4 (this, INTF_ADDR) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_mov_reg_membase (s->code, reg1, reg1, 
+	if (lreg == treg) 
+		treg = X86_EDX;
+
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
+
+	x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
+	x86_mov_reg_membase (s->code, lreg, lreg, 
 	        G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
-	x86_mov_reg_membase (s->code, reg1, reg1, tree->left->data.m->klass->interface_id << 2, 4);
-	x86_call_virtual (s->code, reg1, tree->left->data.m->slot << 2);
+	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.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 
+	PRINT_REG ("CALL_I4(INTERFACE)", tree->reg1);
+
 	g_assert (tree->reg1 == X86_EAX);
 }
+
+reg: CALL_I4 (this, VFUNC_ADDR) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-reg: CALL_I4 (VFUNC_ADDR (reg)) {
-	int reg1 = tree->left->left->reg1;
+	if (lreg == treg) 
+		treg = X86_EDX;
+
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
 
-	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_call_virtual (s->code, reg1, 
-	        G_STRUCT_OFFSET (MonoClass, vtable) + (tree->left->data.m->slot << 2));
+	x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
+	x86_call_virtual (s->code, lreg, 
+	        G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 
-	PRINT_REG ("CONV_I4(VIRTUAL)", tree->reg1);
+	PRINT_REG ("CALL_I4(VIRTUAL)", tree->reg1);
 
 	g_assert (tree->reg1 == X86_EAX);
 }
 
-stmt: CALL_I4 (LDIND_I4 (ADDR_G)) {
-	x86_call_mem (s->code, tree->left->left->data.p);
+stmt: CALL_VOID (this, LDIND_I4 (ADDR_G)) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (lreg == treg) 
+		treg = X86_EDX;
+	
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
+
+	x86_call_mem (s->code, tree->right->left->data.p);
+
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 }
+
+stmt: CALL_VOID (this, INTF_ADDR) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-stmt: CALL_I4 (INTF_ADDR (reg)) {
-	int reg1 = tree->left->left->reg1;
+	if (lreg == treg) 
+		treg = X86_EDX;
 
-	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_mov_reg_membase (s->code, reg1, reg1, 
-                G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
-	x86_mov_reg_membase (s->code, reg1, reg1, tree->left->data.m->klass->interface_id << 2, 4);
-	x86_call_virtual (s->code, reg1, tree->left->data.m->slot << 2);
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
+	x86_mov_reg_membase (s->code, lreg, lreg, 
+	        G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
+	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 (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 }
 
-stmt: CALL_I4 (VFUNC_ADDR (reg)) {
-	int reg1 = tree->left->left->reg1;
+stmt: CALL_VOID (this, VFUNC_ADDR) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_call_virtual (s->code, reg1, 
-                G_STRUCT_OFFSET (MonoClass, vtable) + (tree->left->data.m->slot << 2));
+	if (lreg == treg) 
+		treg = X86_EDX;
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
+
+	x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
+	x86_call_virtual (s->code, lreg, 
+	        G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
+
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 }
 
 stmt: SWITCH (reg) {
@@ -1416,12 +1566,29 @@
 		x86_pop_reg (s->code, X86_ECX);
 }
 
-lreg: CALL_I8 (LDIND_I4 (ADDR_G)) {
+lreg: CALL_I8 (this, LDIND_I4 (ADDR_G)) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
+
+	if (lreg == treg) 
+		treg = X86_EDX;
 	
-	x86_call_mem (s->code, tree->left->left->data.p);
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
+
+	x86_call_mem (s->code, tree->right->left->data.p);
+
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 
 	g_assert (tree->reg1 == X86_EAX);
 	g_assert (tree->reg2 == X86_EDX);
@@ -1679,7 +1846,6 @@
 
 freg: CONST_R8 {
 	double d = *(double *)tree->data.p;
-	printf ("TEST %f\n", d);
 
 	if (d == 0.0)
 		x86_fldz (s->code);
@@ -1818,36 +1984,85 @@
 	x86_branch32 (s->code, X86_CC_NE, tree->data.bb->addr - offset, FALSE);
 }
 
-freg: CALL_R8 (LDIND_I4 (ADDR_G)) {
+freg: CALL_R8 (this, LDIND_I4 (ADDR_G)) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
+
+	if (lreg == treg) 
+		treg = X86_EDX;
 	
-	x86_call_mem (s->code, tree->left->left->data.p);
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
+
+	x86_call_mem (s->code, tree->right->left->data.p);
+
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 }
+
+freg: CALL_R8 (this, INTF_ADDR) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-freg: CALL_R8 (INTF_ADDR (reg)) {
-	int reg1 = tree->left->left->reg1;
+	if (lreg == treg) 
+		treg = X86_EDX;
 
-	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_mov_reg_membase (s->code, reg1, reg1, 
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
+
+	x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
+	x86_mov_reg_membase (s->code, lreg, lreg, 
 	        G_STRUCT_OFFSET (MonoClass, interface_offsets), 4);
-	x86_mov_reg_membase (s->code, reg1, reg1, tree->left->data.m->klass->interface_id << 2, 4);
-	x86_call_virtual (s->code, reg1, tree->left->data.m->slot << 2);
+	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.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 }
+
+freg: CALL_R8 (this, VFUNC_ADDR) {
+	MethodCallInfo *ci = tree->data.ci;
+	int lreg = tree->left->reg1;
+	int treg = X86_EAX;
 
-freg: CALL_R8 (VFUNC_ADDR (reg)) {
-	int reg1 = tree->left->left->reg1;
+	if (lreg == treg) 
+		treg = X86_EDX;
+
+	if (ci->vtype_num) {
+		int offset = g_array_index (s->varinfo, MonoVarInfo, ci->vtype_num).offset;
+		x86_lea_membase (s->code, treg, X86_EBP, offset);
+		x86_push_reg (s->code, treg);
+	}
+
+	if (tree->left->op != MB_TERM_NOP) {
+		g_assert (lreg >= 0);
+		x86_push_reg (s->code, lreg);
+	}
 
-	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_call_virtual (s->code, reg1, 
-	        G_STRUCT_OFFSET (MonoClass, vtable) + (tree->left->data.m->slot << 2));
+	x86_mov_reg_membase (s->code, lreg, lreg, 0, 4);
+	x86_call_virtual (s->code, lreg, 
+	        G_STRUCT_OFFSET (MonoClass, vtable) + (tree->right->data.m->slot << 2));
 
-	if (tree->data.i)
-		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
+	if (ci->args_size)
+		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, ci->args_size);
 }
 
 stmt: RETV (freg) {