[Mono-list] jit patch

Dietmar Maurer dietmar@ximian.com
07 Nov 2001 11:43:51 +0100


Index: mono/arch/x86/x86-codegen.h
===================================================================
RCS file: /cvs/public/mono/mono/arch/x86/x86-codegen.h,v
retrieving revision 1.13
diff -u -r1.13 x86-codegen.h
--- mono/arch/x86/x86-codegen.h	2001/10/10 10:11:17	1.13
+++ mono/arch/x86/x86-codegen.h	2001/11/07 06:30:28
@@ -1114,7 +1114,7 @@
  */
 #define x86_jump_code(inst,target)	\
 	do {	\
-		int t = (target) - (inst) - 2;	\
+		int t = (unsigned char*)(target) - (inst) - 2;	\
 		if (x86_is_imm8(t)) {	\
 			x86_jump8 ((inst), t);	\
 		} else {	\
Index: mono/jit/ChangeLog
===================================================================
RCS file: /cvs/public/mono/mono/jit/ChangeLog,v
retrieving revision 1.35
diff -u -r1.35 ChangeLog
--- mono/jit/ChangeLog	2001/11/06 09:46:18	1.35
+++ mono/jit/ChangeLog	2001/11/07 06:30:29
@@ -1,3 +1,11 @@
+2001-11-07  Dietmar Maurer  <dietmar@ximian.com>
+
+	* emit-x86.c (enter_method): print out all method arguments
+	(x86_magic_trampoline): impl.
+	(arch_create_simple_jit_trampoline): we use different trampolines
+	for static methods (no need to write the address back into to
+	vtable).
+
 2001-11-06  Dietmar Maurer  <dietmar@ximian.com>
 
 	* emit-x86.c (arch_create_jit_trampoline): optimised trampoline to
Index: mono/jit/emit-x86.c
===================================================================
RCS file: /cvs/public/mono/mono/jit/emit-x86.c,v
retrieving revision 1.13
diff -u -r1.13 emit-x86.c
--- mono/jit/emit-x86.c	2001/11/06 09:46:18	1.13
+++ mono/jit/emit-x86.c	2001/11/07 06:30:29
@@ -23,15 +23,77 @@
 #include "codegen.h"
 
 static void
-enter_method (MonoMethod *method)
+enter_method (MonoMethod *method, gpointer ebp)
 {
-	printf ("ENTER: %s.%s::%s\n", method->klass->name_space,
+	int i;
+	MonoClass *class;
+	MonoObject *o;
+
+	printf ("ENTER: %s.%s::%s (", method->klass->name_space,
 		method->klass->name, method->name);
+
+	ebp += 8;
+	
+	if (method->signature->hasthis) {
+		o = *((MonoObject **)ebp);
+		class = o->klass;
+		printf ("%p[%s.%s], ", o, class->name_space, class->name);
+		ebp += sizeof (gpointer);
+	}
+
+	for (i = 0; i < method->signature->param_count; ++i) {
+		MonoType *type = method->signature->params [i];
+		int size, align;
+
+		switch (type->type) {
+		case MONO_TYPE_BOOLEAN:
+		case MONO_TYPE_CHAR:
+		case MONO_TYPE_I1:
+		case MONO_TYPE_U1:
+		case MONO_TYPE_I2:
+		case MONO_TYPE_U2:
+		case MONO_TYPE_I4:
+		case MONO_TYPE_U4:
+		case MONO_TYPE_I:
+		case MONO_TYPE_U:
+			printf ("%d, ", *((int *)(ebp)));
+			break;
+		case MONO_TYPE_STRING:
+		case MONO_TYPE_PTR:
+		case MONO_TYPE_CLASS:
+		case MONO_TYPE_OBJECT:
+		case MONO_TYPE_FNPTR:
+		case MONO_TYPE_ARRAY:
+		case MONO_TYPE_SZARRAY:
+			printf ("%p, ", *((gpointer *)(ebp)));
+			break;
+		case MONO_TYPE_I8:
+			printf ("%lld, ", *((gint64 *)(ebp)));
+			break;
+		case MONO_TYPE_R8:
+			printf ("%f, ", *((double *)(ebp)));
+			break;
+
+		default:
+			printf ("XX, ");
+		}
+
+		size = mono_type_size (type, &align);
+		if (size < 4) 
+			size = 4;
+
+		ebp += size;
+
+	}
+
+	printf (")\n");
 }
 
 static void
 leave_method (MonoMethod *method, int edx, int eax, double test)
 {
+	gint64 l;
+
 	switch (method->signature->ret->type) {
 	case MONO_TYPE_VOID:
 		printf ("LEAVE: %s.%s::%s\n", method->klass->name_space,
@@ -61,8 +123,10 @@
 			method->klass->name, method->name, (gpointer)eax);
 		break;
 	case MONO_TYPE_I8:
-		printf ("LEAVE: %s.%s::%s EAX=%d EDX=%d\n", method->klass->name_space,
-			method->klass->name, method->name, eax, edx);
+		*((gint32 *)&l) = eax;
+		*((gint32 *)&l + 1) = edx;
+		printf ("LEAVE: %s.%s::%s EAX/EDX=%lld\n", method->klass->name_space,
+			method->klass->name, method->name, l);
 		break;
 	case MONO_TYPE_R8:
 		printf ("LEAVE: %s.%s::%s FP=%f\n", method->klass->name_space,
@@ -76,7 +140,7 @@
 
 /**
  * arch_emit_prologue:
- * @s: pointer to status information
+ * @cfg: pointer to status information
  *
  * Emits the function prolog.
  */
@@ -99,15 +163,16 @@
 		x86_push_reg (cfg->code, X86_ESI);
 
 	if (mono_jit_trace_calls) {
+		x86_push_reg (cfg->code, X86_EBP);
 		x86_push_imm (cfg->code, cfg->method);
 		x86_call_code (cfg->code, enter_method);
-		x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
+		x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
 	}
 }
 
 /**
- * arch_emit_prologue:
- * @s: pointer to status information
+ * arch_emit_epilogue:
+ * @cfg: pointer to status information
  *
  * Emits the function epilog.
  */
@@ -142,19 +207,141 @@
 }
 
 /**
+ * x86_magic_trampoline:
+ * @eax: saved x86 register 
+ * @ecx: saved x86 register 
+ * @edx: saved x86 register 
+ * @esi: saved x86 register 
+ * @edi: saved x86 register 
+ * @ebx: saved x86 register
+ * @code: pointer into caller code
+ * @method: the method to translate
+ *
+ * This method is called by the trampoline functions for virtual
+ * methods. It inspects the caller code to find the address of the
+ * vtable slot, then calls the JIT compiler and writes the address
+ * of the compiled method back to the vtable. All virtual methods 
+ * are called with: x86_call_membase (inst, basereg, disp). We always
+ * use 32 bit displacement to ensure that the length of the call 
+ * instruction is 6 bytes. We need to get the value of the basereg 
+ * and the constant displacement.
+ */
+static gpointer
+x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi, 
+		      int ebx, guint8 *code, MonoMethod *m)
+{
+	guint8 ab, reg;
+	gint32 disp;
+	gpointer o;
+
+	/* go to the start of the call instruction */
+	code -= 6;
+	g_assert (*code == 0xff);
+
+	code++;
+	ab = *code;
+	g_assert ((ab >> 6) == 2);
+	
+	/* extract the register number containing the address */
+	reg = ab & 0x07;
+	code++;
+
+	/* extract the displacement */
+	disp = *((gint32*)code);
+
+	switch (reg) {
+	case X86_EAX:
+		o = (gpointer)eax;
+		break;
+	case X86_EDX:
+		o = (gpointer)edx;
+		break;
+	case X86_ECX:
+		o = (gpointer)ecx;
+		break;
+	case X86_ESI:
+		o = (gpointer)esi;
+		break;
+	case X86_EDI:
+		o = (gpointer)edi;
+		break;
+	case X86_EBX:
+		o = (gpointer)ebx;
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	o += disp;
+
+	return *((gpointer *)o) = arch_compile_method (m);
+}
+
+/**
  * arch_create_jit_trampoline:
  * @method: pointer to the method info
  *
+ * Creates a trampoline function for virtual methods. If the created
+ * code is called it first starts JIT compilation of method,
+ * and then calls the newly created method. I also replaces the
+ * corresponding vtable entry (see x86_magic_trampoline).
+ * 
+ * Returns: a pointer to the newly created code 
+ */
+gpointer
+arch_create_jit_trampoline (MonoMethod *method)
+{
+	guint8 *code, *buf;
+	static guint8 *vc = NULL;
+
+	if (method->addr)
+		return method->addr;
+
+	if (!vc) {
+		vc = buf = g_malloc (24);
+
+		/* push the return address onto the stack */
+		x86_push_membase (buf, X86_ESP, 4);
+
+		/* save all register values */
+		x86_push_reg (buf, X86_EBX);
+		x86_push_reg (buf, X86_EDI);
+		x86_push_reg (buf, X86_ESI);
+		x86_push_reg (buf, X86_EDX);
+		x86_push_reg (buf, X86_ECX);
+		x86_push_reg (buf, X86_EAX);
+
+		x86_call_code (buf, x86_magic_trampoline);
+		x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 8*4);
+
+		/* call the compiled method */
+		x86_jump_reg (buf, X86_EAX);
+
+		g_assert ((buf - vc) <= 24);
+	}
+
+	code = buf = g_malloc (16);
+	x86_push_imm (buf, method);
+	x86_jump_code (buf, vc);
+	g_assert ((buf - code) <= 16);
+
+	return code;
+}
+
+/**
+ * arch_create_simple_jit_trampoline:
+ * @method: pointer to the method info
+ *
  * Creates a trampoline function for method. If the created
  * code is called it first starts JIT compilation of method,
  * and then calls the newly created method. I also replaces the
  * address in method->addr with the result of the JIT 
- * compilation step.
+ * compilation step (in arch_compile_method).
  * 
  * Returns: a pointer to the newly created code 
  */
 gpointer
-arch_create_jit_trampoline (MonoMethod *method)
+arch_create_simple_jit_trampoline (MonoMethod *method)
 {
 	guint8 *code, *buf;
 
Index: mono/jit/jit.h
=================================================================_=
RCS file: /cvs/public/mono/mono/jit/jit.h,v
retrieving revision 1.10
diff -u -r1.10 jit.h
--- mono/jit/jit.h	2001/11/06 09:46:18	1.10
+++ mono/jit/jit.h	2001/11/07 06:30:29
@@ -93,6 +93,9 @@
 gpointer
 arch_create_jit_trampoline (MonoMethod *method);
 
+gpointer
+arch_create_simple_jit_trampoline (MonoMethod *method);
+
 /* some handy debugging functions */
 
 void
Index: mono/jit/testjit.c
===================================================================
RCS file: /cvs/public/mono/mono/jit/testjit.c,v
retrieving revision 1.37
diff -u -r1.37 testjit.c
--- mono/jit/testjit.c	2001/11/06 09:46:18	1.37
+++ mono/jit/testjit.c	2001/11/07 06:30:29
@@ -1136,11 +1136,11 @@
 		superblock_end = TRUE;
 		sp = stack;
 
-		printf ("START\n");
+		//printf ("START\n");
 		for (i = 0; i < cfg->block_count; i++) {
 			bb = &cfg->bblocks [i];
 
-			printf ("BBS %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
+			//printf ("BBS %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
 			
 			if (!bb->reached && !superblock_end) {
 
@@ -1181,8 +1181,8 @@
         while (ip < end) {
 		guint32 cli_addr = ip - header->code;
 					
-		printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, opcode_names [*ip], 
-			forest->len, superblock_end, sp - stack);
+		//printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, opcode_names [*ip], 
+		//forest->len, superblock_end, sp - stack);
 
 		switch (*ip) {
 			case CEE_THROW: {
@@ -1554,8 +1554,8 @@
 				sp = sp - nargs;
 			}
 
-			printf ("MINFO %s.%s::%s %d %d\n", cm->klass->name_space, 
-				cm->klass->name, cm->name, cm->flags & METHOD_ATTRIBUTE_VIRTUAL, virtual);
+			//printf ("MINFO %s.%s::%s %d %d\n", cm->klass->name_space, 
+			//cm->klass->name, cm->name, cm->flags & METHOD_ATTRIBUTE_VIRTUAL, virtual);
  
 			if (virtual) {
 				t2 = ctree_create_dup (mp, this);
@@ -1571,7 +1571,7 @@
 				t2->data.m = cm;
 			} else {
 				if (!cm->addr)
-					cm->addr = arch_create_jit_trampoline (cm);
+					cm->addr = arch_create_simple_jit_trampoline (cm);
 
 				t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
 				t2->data.p = (char *)cm + G_STRUCT_OFFSET (MonoMethod, addr);
@@ -2082,16 +2082,16 @@
 				repeat = TRUE;
 				g_assert (repeat_count < 10);
 			}
-	printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
+				//printf ("BBE %d %d %d %d\n", i, bb->reached, bb->finished, superblock_end);
 		}
 
 		repeat_count++;
-		printf ("REPEAT %d\n", repeat);
+		//printf ("REPEAT %d\n", repeat);
 
 
 	} while (repeat);
 
-	printf ("FINISHED\n");
+		//printf ("FINISHED\n");
 }
 	
 /**
Index: mono/jit/x86.brg
===================================================================
RCS file: /cvs/public/mono/mono/jit/x86.brg,v
retrieving revision 1.30
diff -u -r1.30 x86.brg
--- mono/jit/x86.brg	2001/11/06 09:46:18	1.30
+++ mono/jit/x86.brg	2001/11/07 06:30:29
@@ -92,6 +92,16 @@
 #define MB_USE_OPT2(c) c
 #endif
 
+/* The call instruction for virtual functions must have a known
+ * size (used by x86_magic_trampoline)
+ */
+#define x86_call_virtual(inst,basereg,disp)	               \
+	do {	                                               \
+		*(inst)++ = (unsigned char)0xff;               \
+		x86_address_byte ((inst), 2, 2, (basereg));    \
+		x86_imm_emit32 ((inst), (disp));	       \
+	} while (0)
+
 %%
 
 #
@@ -837,7 +847,7 @@
 	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_membase (s->code, reg1, tree->left->data.m->slot << 2);
+	x86_call_virtual (s->code, reg1, tree->left->data.m->slot << 2);
 
 	if (tree->data.i)
 		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
@@ -849,7 +859,7 @@
 	int reg1 = tree->left->left->reg1;
 
 	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_call_membase (s->code, reg1, 
+	x86_call_virtual (s->code, reg1, 
 	        G_STRUCT_OFFSET (MonoClass, vtable) + (tree->left->data.m->slot << 2));
 
 	if (tree->data.i)
@@ -872,7 +882,7 @@
 	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_membase (s->code, reg1, tree->left->data.m->slot << 2);
+	x86_call_virtual (s->code, reg1, tree->left->data.m->slot << 2);
 
 	if (tree->data.i)
 		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
@@ -882,7 +892,7 @@
 	int reg1 = tree->left->left->reg1;
 
 	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_call_membase (s->code, reg1, 
+	x86_call_virtual (s->code, reg1, 
                 G_STRUCT_OFFSET (MonoClass, vtable) + (tree->left->data.m->slot << 2));
 
 	if (tree->data.i)
@@ -1556,7 +1566,7 @@
 	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_membase (s->code, reg1, tree->left->data.m->slot << 2);
+	x86_call_virtual (s->code, reg1, tree->left->data.m->slot << 2);
 
 	if (tree->data.i)
 		x86_alu_reg_imm (s->code, X86_ADD, X86_ESP, tree->data.i);
@@ -1566,7 +1576,7 @@
 	int reg1 = tree->left->left->reg1;
 
 	x86_mov_reg_membase (s->code, reg1, reg1, 0, 4);
-	x86_call_membase (s->code, reg1, 
+	x86_call_virtual (s->code, reg1, 
 	        G_STRUCT_OFFSET (MonoClass, vtable) + (tree->left->data.m->slot << 2));
 
 	if (tree->data.i)
Index: mono/tests/jit-long.cs
===================================================================
RCS file: /cvs/public/mono/mono/tests/jit-long.cs,v
retrieving revision 1.2
diff -u -r1.2 jit-long.cs
--- mono/tests/jit-long.cs	2001/09/24 12:56:27	1.2
+++ mono/tests/jit-long.cs	2001/11/07 06:30:29
@@ -67,8 +67,6 @@
 	public static int Main() {
 		int num = 1;
 
-		return test_alu();
-		
 		if (test_call (3, 5) != 8)
 			return num;
 		num++;