2005-07-07 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mono / mini / tramp-x86.c
index 1c82dacc89b2f1c3c77b47f10ec6c7d5b941746b..454fa396778e68657218ee93f2e89fdfd6f04db2 100644 (file)
 #include "mini.h"
 #include "mini-x86.h"
 
-typedef enum {
-       MONO_TRAMPOLINE_GENERIC,
-       MONO_TRAMPOLINE_JUMP,
-       MONO_TRAMPOLINE_CLASS_INIT,
-       MONO_TRAMPOLINE_AOT
-} MonoTrampolineType;
-
-/* adapt to mini later... */
-#define mono_jit_share_code (1)
-
-/*
- * Address of the x86 trampoline code.  This is used by the debugger to check
- * whether a method is a trampoline.
- */
-guint8 *mono_generic_trampoline_code = NULL;
+static guint8* nullified_class_init_trampoline;
 
 /*
  * get_unbox_trampoline:
@@ -70,74 +56,6 @@ get_unbox_trampoline (MonoMethod *m, gpointer addr)
        return start;
 }
 
-static gpointer
-get_vtable_slot_addr (guint8 *code, int eax, int ecx, int edx, int esi, 
-                                         int edi, int ebx)
-{
-       guint8 reg = 0;
-       gint32 disp = 0;
-       char *o = NULL;
-
-       /* go to the start of the call instruction
-        *
-        * address_byte = (m << 6) | (o << 3) | reg
-        * call opcode: 0xff address_byte displacement
-        * 0xff m=1,o=2 imm8
-        * 0xff m=2,o=2 imm32
-        */
-       code -= 6;
-       if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
-               reg = code [4] & 0x07;
-               disp = (signed char)code [5];
-       } else {
-               if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
-                       reg = code [1] & 0x07;
-                       disp = *((gint32*)(code + 2));
-               } else if ((code [1] == 0xe8)) {
-                       return FALSE;
-               } else if ((code [4] == 0xff) && (((code [5] >> 6) & 0x3) == 0) && (((code [5] >> 3) & 0x7) == 2)) {
-                       /*
-                        * This is a interface call: should check the above code can't catch it earlier 
-                        * 8b 40 30   mov    0x30(%eax),%eax
-                        * ff 10      call   *(%eax)
-                        */
-                       disp = 0;
-                       reg = code [5] & 0x07;
-               } else {
-                       printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", code [0], code [1], code [2], code [3],
-                               code [4], code [5], code [6]);
-                       g_assert_not_reached ();
-               }
-       }
-
-       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 o;
-}
-
 /**
  * x86_magic_trampoline:
  * @eax: saved x86 register 
@@ -162,8 +80,9 @@ static gpointer
 x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi, 
                      int ebx, guint8 *code, MonoMethod *m)
 {
-       char *o = NULL;
        gpointer addr;
+       gpointer *vtable_slot;
+       int regs [X86_NREG];
 
        addr = mono_compile_method (m);
        g_assert (addr);
@@ -172,8 +91,15 @@ x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi,
        if (!code)
                return addr;
 
-       o = get_vtable_slot_addr (code, eax, ecx, edx, esi, edi, ebx);
-       if (!o) {
+       regs [X86_EAX] = eax;
+       regs [X86_ECX] = ecx;
+       regs [X86_EDX] = edx;
+       regs [X86_ESI] = esi;
+       regs [X86_EDI] = edi;
+       regs [X86_EBX] = ebx;
+
+       vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
+       if (!vtable_slot) {
                /* go to the start of the call instruction
                 *
                 * address_byte = (m << 6) | (o << 3) | reg
@@ -185,7 +111,7 @@ x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi,
                if ((code [1] == 0xe8)) {
                        if (!mono_running_on_valgrind ()) {
                                MonoJitInfo *ji = 
-                                       mono_jit_info_table_find (mono_domain_get (), code);
+                                       mono_jit_info_table_find (mono_domain_get (), (char*)code);
                                MonoJitInfo *target_ji = 
                                        mono_jit_info_table_find (mono_domain_get (), addr);
 
@@ -206,11 +132,11 @@ x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi,
                }
        }
 
-       if (m->klass->valuetype && !mono_aot_is_got_entry (code, o))
+       if (m->klass->valuetype && !mono_aot_is_got_entry (code, (guint8*)vtable_slot))
                addr = get_unbox_trampoline (m, addr);
 
-       if (mono_aot_is_got_entry (code, o) || mono_domain_owns_vtable_slot (mono_domain_get (), o))
-               *((gpointer *)o) = addr;
+       if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
+               *vtable_slot = addr;
 
        return addr;
 }
@@ -227,31 +153,50 @@ x86_aot_trampoline (int eax, int ecx, int edx, int esi, int edi,
 {
        MonoImage *image;
        guint32 token;
-       MonoMethod *method;
+       MonoMethod *method = NULL;
        gpointer addr;
        gpointer *vtable_slot;
+       int regs [X86_NREG];
+       gboolean is_got_entry;
 
        image = *(gpointer*)token_info;
        token_info += sizeof (gpointer);
        token = *(guint32*)token_info;
 
-       /* Later we could avoid allocating the MonoMethod */
-       method = mono_get_method (image, token, NULL);
-       g_assert (method);
+       addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
+       if (!addr) {
+               method = mono_get_method (image, token, NULL);
+               g_assert (method);
 
-       if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
-               method = mono_marshal_get_synchronized_wrapper (method);
+               //printf ("F: %s\n", mono_method_full_name (method, TRUE));
 
-       addr = mono_compile_method (method);
-       g_assert (addr);
+               if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+                       method = mono_marshal_get_synchronized_wrapper (method);
 
-       vtable_slot = get_vtable_slot_addr (code, eax, ecx, edx, esi, edi, ebx);
+               addr = mono_compile_method (method);
+               g_assert (addr);
+       }
+
+       regs [X86_EAX] = eax;
+       regs [X86_ECX] = ecx;
+       regs [X86_EDX] = edx;
+       regs [X86_ESI] = esi;
+       regs [X86_EDI] = edi;
+       regs [X86_EBX] = ebx;
+
+       vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
        g_assert (vtable_slot);
 
-       if (method->klass->valuetype)
-               addr = get_unbox_trampoline (method, addr);
+       is_got_entry = mono_aot_is_got_entry (code, (guint8*)vtable_slot);
+
+       if (!is_got_entry) {
+               if (!method)
+                       method = mono_get_method (image, token, NULL);
+               if (method->klass->valuetype)
+                       addr = get_unbox_trampoline (method, addr);
+       }
 
-       if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
+       if (is_got_entry || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
                *vtable_slot = addr;
 
        return addr;
@@ -299,8 +244,7 @@ x86_class_init_trampoline (int eax, int ecx, int edx, int esi, int edi,
 
                        /* Then atomically change the first 4 bytes to a nop as well */
                        ops = 0x90909090;
-                       InterlockedExchange ((guint32*)code, ops);
-
+                       InterlockedExchange ((gint32*)code, ops);
 #ifdef HAVE_VALGRIND_MEMCHECK_H
                        /* FIXME: the calltree skin trips on the self modifying code above */
 
@@ -313,8 +257,20 @@ x86_class_init_trampoline (int eax, int ecx, int edx, int esi, int edi,
                ;
        } else if ((code [-1] == 0xff) && (x86_modrm_reg (code [0]) == 0x2)) {
                /* call *<OFFSET>(<REG>) -> Call made from AOT code */
-               /* FIXME: Patch up the trampoline */
-               ;
+               int regs [X86_NREG];
+               gpointer *vtable_slot;
+
+               regs [X86_EAX] = eax;
+               regs [X86_ECX] = ecx;
+               regs [X86_EDX] = edx;
+               regs [X86_ESI] = esi;
+               regs [X86_EDI] = edi;
+               regs [X86_EBX] = ebx;
+
+               vtable_slot = mono_arch_get_vcall_slot_addr (code + 5, (gpointer*)regs);
+               g_assert (vtable_slot);
+
+               *vtable_slot = nullified_class_init_trampoline;
        } else {
                        printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", code [0], code [1], code [2], code [3],
                                code [4], code [5], code [6]);
@@ -322,14 +278,10 @@ x86_class_init_trampoline (int eax, int ecx, int edx, int esi, int edi,
                }
 }
 
-static guchar*
-create_trampoline_code (MonoTrampolineType tramp_type)
+guchar*
+mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
 {
        guint8 *buf, *code;
-       static guint8 *trampoline_code [16];
-
-       if (trampoline_code [tramp_type])
-               return trampoline_code [tramp_type];
 
        code = buf = mono_global_codeman_reserve (256);
 
@@ -416,22 +368,23 @@ create_trampoline_code (MonoTrampolineType tramp_type)
 
        g_assert ((buf - code) <= 256);
 
-       if (tramp_type == MONO_TRAMPOLINE_GENERIC)
-               mono_generic_trampoline_code = code;
-       trampoline_code [tramp_type] = code;
+       if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
+               /* Initialize the nullified class init trampoline used in the AOT case */
+               nullified_class_init_trampoline = buf = mono_global_codeman_reserve (16);
+               x86_ret (buf);
+       }
 
        return code;
 }
 
 #define TRAMPOLINE_SIZE 10
 
-static MonoJitInfo*
-create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain)
+static gpointer
+create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
 {
        guint8 *code, *buf, *tramp;
-       MonoJitInfo *ji;
        
-       tramp = create_trampoline_code (tramp_type);
+       tramp = mono_get_trampoline_code (tramp_type);
 
        mono_domain_lock (domain);
        code = buf = mono_code_manager_reserve (domain->code_mp, TRAMPOLINE_SIZE);
@@ -441,23 +394,30 @@ create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDo
        x86_jump_code (buf, tramp);
        g_assert ((buf - code) <= TRAMPOLINE_SIZE);
 
-       ji = g_new0 (MonoJitInfo, 1);
-       ji->code_start = code;
-       ji->code_size = buf - code;
-
-       mono_arch_flush_icache (ji->code_start, ji->code_size);
+       mono_arch_flush_icache (code, buf - code);
 
        mono_jit_stats.method_trampolines++;
 
-       return ji;
+       if (code_len)
+               *code_len = buf - code;
+
+       return code;
 }
 
 MonoJitInfo*
 mono_arch_create_jump_trampoline (MonoMethod *method)
 {
-       MonoJitInfo *ji = create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get ());
+       MonoJitInfo *ji;
+       gpointer code;
+       guint32 code_size;
 
+       code = create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
+
+       ji = g_new0 (MonoJitInfo, 1);
+       ji->code_start = code;
+       ji->code_size = code_size;
        ji->method = method;
+
        return ji;
 }
 
@@ -475,22 +435,13 @@ mono_arch_create_jump_trampoline (MonoMethod *method)
 gpointer
 mono_arch_create_jit_trampoline (MonoMethod *method)
 {
-       MonoJitInfo *ji;
-       gpointer code_start;
-
-       ji = create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, mono_domain_get ());
-       code_start = ji->code_start;
-       g_free (ji);
-
-       return code_start;
+       return create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, mono_domain_get (), NULL);
 }
 
 gpointer
 mono_arch_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 {
        MonoDomain *domain = mono_domain_get ();
-       MonoJitInfo *ji;
-       gpointer code_start;
        guint8 *buf, *start;
 
        mono_domain_lock (domain);
@@ -501,11 +452,7 @@ mono_arch_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
        buf += sizeof (gpointer);
        *(guint32*)buf = token;
 
-       ji = create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain);
-       code_start = ji->code_start;
-       g_free (ji);
-
-       return code_start;
+       return create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
 }
 
 /**
@@ -522,14 +469,7 @@ mono_arch_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 gpointer
 mono_arch_create_class_init_trampoline (MonoVTable *vtable)
 {
-       MonoJitInfo *ji;
-       gpointer code;
-
-       ji = create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain);
-       code = ji->code_start;
-       g_free (ji);
-
-       return code;
+       return create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
 }
 
 void
@@ -559,11 +499,3 @@ mono_debugger_create_notification_function (gpointer *notification_address)
 
        return ptr;
 }
-
-void
-mono_x86_tramp_init (void)
-{
-       create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
-       create_trampoline_code (MONO_TRAMPOLINE_JUMP);
-       create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
-}