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