Hi,

The attached patch optimize the imt thunk code. The optimization is to
exploit the fact that IP don't need to be preserved under a particular
situation.

The magic trampoline needs to retrieve the vtable pointer used by the call
site to patch it and this address might be stored in a scratch register,
that's why the IMT code cannot change then. But if the code store the vtable
address within the scratch registers, the magic trampoline code won't
notice. This change allow us to branch without the POP hack.

The optimization loads the vtable pointer into IP and uses r0 and r1 to
compare values. To call the virtual method, we use "ldr pc, [ip + #]". These
changes reduce the code by 3 words for each entry.


Cheers,
Rodrigo
Index: mini/mini-arm.c
===================================================================
--- mini/mini-arm.c	(revision 88111)
+++ mini/mini-arm.c	(working copy)
@@ -3649,7 +3649,11 @@
 
 
 #define ENABLE_WRONG_METHOD_CHECK 0
-#define BASE_SIZE (8)
+#define BASE_SIZE (4 * 4)
+#define BSEARCH_ENTRY_SIZE (4 * 4)
+#define CMP_SIZE (3 * 4)
+#define BRANCH_SIZE (3 * 4)
+#define WMC_SIZE (5 * 4)
 
 static arminstr_t *
 arm_emit_value_and_patch_ldr (arminstr_t *code, arminstr_t *target, guint32 value)
@@ -3666,24 +3670,26 @@
 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
 {
 	int size, i, extra_space = 0;
-	arminstr_t *code, *start;
+	arminstr_t *code, *start, *vtable_target = NULL;
 	size = BASE_SIZE;
 
 	for (i = 0; i < count; ++i) {
 		MonoIMTCheckItem *item = imt_entries [i];
 		if (item->is_equals) {
+			g_assert (arm_is_imm12 (item->vtable_slot * 4));
+
 			if (item->check_target_idx) {
 				if (!item->compare_done)
-					item->chunk_size += 3 * 4;
-				item->chunk_size += 6 * 4;
+					item->chunk_size += CMP_SIZE;
+				item->chunk_size += BRANCH_SIZE;
 			} else {
-				item->chunk_size += 5 * 4;
+				item->chunk_size += BRANCH_SIZE;
 #if ENABLE_WRONG_METHOD_CHECK
-				item->chunk_size += 5 * 4;
+				item->chunk_size += WMC_SIZE;
 #endif
 			}
 		} else {
-			item->chunk_size += 4 * 4;
+			item->chunk_size += BSEARCH_ENTRY_SIZE;
 			imt_entries [item->check_target_idx]->compare_done = TRUE;
 		}
 		size += item->chunk_size;
@@ -3699,68 +3705,67 @@
 	}
 #endif
 
-	ARM_PUSH3 (code, ARMREG_R0, ARMREG_IP, ARMREG_LR);
-	ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, -4);
+	ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
+	ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
+	vtable_target = code;
+	ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
 
 	for (i = 0; i < count; ++i) {
 		MonoIMTCheckItem *item = imt_entries [i];
 		arminstr_t *imt_method = NULL;
-		arminstr_t *vtable_target = NULL;		
 		item->code_target = (guint8*)code;
 
 		if (item->is_equals) {
 			if (item->check_target_idx) {
 				if (!item->compare_done) {
 					imt_method = code;
-					ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
-					ARM_CMP_REG_REG (code, ARMREG_IP, ARMREG_R0);
+					ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
+					ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
 				}
 				item->jmp_code = (guint8*)code;
 				ARM_B_COND (code, ARMCOND_NE, 0);
 
-				vtable_target = code;
-				ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
-				ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 0);
-				ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
-				ARM_POP3 (code, ARMREG_R0, ARMREG_IP, ARMREG_PC);
+				ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
+				ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, item->vtable_slot * 4);
 			} else {
 				/*Enable the commented code to assert on wrong method*/
 #if ENABLE_WRONG_METHOD_CHECK
 				imt_method = code;
-				ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
-				ARM_CMP_REG_REG (code, ARMREG_IP, ARMREG_R0);
-				ARM_B_COND (code, ARMCOND_NE, 3);
+				ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
+				ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
+				ARM_B_COND (code, ARMCOND_NE, 1);
 #endif
-				vtable_target = code;
-				ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
-				ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 0);
-				ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, 8);
-				ARM_POP3 (code, ARMREG_R0, ARMREG_IP, ARMREG_PC);
+				ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
+				ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, item->vtable_slot * 4);
 
 #if ENABLE_WRONG_METHOD_CHECK
 				ARM_DBRK (code);
 #endif
 			}
+
+			if (imt_method)
+				code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->method);
+
+			/*must emit after unconditional branch*/
+			if (vtable_target) {
+				code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)&(vtable->vtable [0]));
+				item->chunk_size += 4;
+				vtable_target = NULL;
+			}
+
+			/*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
+			if (extra_space) {
+				code += extra_space;
+				extra_space = 0;
+			}
 		} else {
-			ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
-			ARM_CMP_REG_REG (code, ARMREG_IP, ARMREG_R0);
+			ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
+			ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
 
 			item->jmp_code = (guint8*)code;
 			ARM_B_COND (code, ARMCOND_GE, 0);
 			++extra_space;
 		}
-
-		if (imt_method)
-			code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->method);
-
-		if (vtable_target)
-			code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)&(vtable->vtable [item->vtable_slot]));
-
-		/*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
-		if (item->is_equals && extra_space) {
-			code += extra_space;
-			extra_space = 0;
-		}
 	}
 
 	for (i = 0; i < count; ++i) {
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to