+#ifdef MONO_ARCH_HAVE_IMT
+
+// Linear handler, the bsearch head compare is shorter
+//[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
+//[1 + 1] x86_branch8(inst,cond,imm,is_signed)
+// x86_patch(ins,target)
+//[1 + 5] x86_jump_mem(inst,mem)
+
+#define CMP_SIZE 6
+#define BR_SMALL_SIZE 2
+#define BR_LARGE_SIZE 5
+#define JUMP_IMM_SIZE 6
+#define ENABLE_WRONG_METHOD_CHECK 0
+
+static int
+imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
+{
+ int i, distance = 0;
+ for (i = start; i < target; ++i)
+ distance += imt_entries [i]->chunk_size;
+ return distance;
+}
+
+/*
+ * LOCKING: called with the domain lock held
+ */
+gpointer
+mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
+{
+ int i;
+ int size = 0;
+ guint8 *code, *start;
+
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ if (item->is_equals) {
+ if (item->check_target_idx) {
+ if (!item->compare_done)
+ item->chunk_size += CMP_SIZE;
+ item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
+ } else {
+ item->chunk_size += JUMP_IMM_SIZE;
+#if ENABLE_WRONG_METHOD_CHECK
+ item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
+#endif
+ }
+ } else {
+ item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
+ imt_entries [item->check_target_idx]->compare_done = TRUE;
+ }
+ size += item->chunk_size;
+ }
+ code = mono_code_manager_reserve (domain->code_mp, size);
+ start = code;
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ item->code_target = code;
+ if (item->is_equals) {
+ if (item->check_target_idx) {
+ if (!item->compare_done)
+ x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
+ item->jmp_code = code;
+ x86_branch8 (code, X86_CC_NE, 0, FALSE);
+ x86_jump_mem (code, & (vtable->vtable [item->vtable_slot]));
+ } else {
+ /* enable the commented code to assert on wrong method */
+#if ENABLE_WRONG_METHOD_CHECK
+ x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
+ item->jmp_code = code;
+ x86_branch8 (code, X86_CC_NE, 0, FALSE);
+#endif
+ x86_jump_mem (code, & (vtable->vtable [item->vtable_slot]));
+#if ENABLE_WRONG_METHOD_CHECK
+ x86_patch (item->jmp_code, code);
+ x86_breakpoint (code);
+ item->jmp_code = NULL;
+#endif
+ }
+ } else {
+ x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
+ item->jmp_code = code;
+ if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
+ x86_branch8 (code, X86_CC_GE, 0, FALSE);
+ else
+ x86_branch32 (code, X86_CC_GE, 0, FALSE);
+ }
+ }
+ /* patch the branches to get to the target items */
+ for (i = 0; i < count; ++i) {
+ MonoIMTCheckItem *item = imt_entries [i];
+ if (item->jmp_code) {
+ if (item->check_target_idx) {
+ x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
+ }
+ }
+ }
+
+ mono_stats.imt_thunks_size += code - start;
+ g_assert (code - start <= size);
+ return start;
+}
+
+MonoMethod*
+mono_arch_find_imt_method (gpointer *regs, guint8 *code)
+{
+ return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
+}
+
+MonoObject*
+mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
+{
+ MonoMethodSignature *sig = mono_method_signature (method);
+ CallInfo *cinfo = get_call_info (NULL, NULL, sig, FALSE);
+ int this_argument_offset;
+ MonoObject *this_argument;
+
+ /*
+ * this is the offset of the this arg from esp as saved at the start of
+ * mono_arch_create_trampoline_code () in tramp-x86.c.
+ */
+ this_argument_offset = 5;
+ if (MONO_TYPE_ISSTRUCT (sig->ret) && (cinfo->ret.storage == ArgOnStack))
+ this_argument_offset++;
+
+ this_argument = * (MonoObject**) (((guint8*) regs [X86_ESP]) + this_argument_offset * sizeof (gpointer));
+
+ g_free (cinfo);
+ return this_argument;
+}
+#endif
+