2004-10-14 Joe Shaw <joeshaw@novell.com>
[mono.git] / mono / mini / tramp-amd64.c
index 59ad9f0770e38eb5246b0a3046ddf544c2385a7b..2d3daa0554e7b6a68be42f0f80f57a3721069fff 100644 (file)
@@ -29,15 +29,19 @@ typedef enum {
        MONO_TRAMPOLINE_CLASS_INIT
 } MonoTrampolineType;
 
-/* adapt to mini later... */
-#define mono_jit_share_code (1)
-
 /*
  * Address of the trampoline code.  This is used by the debugger to check
  * whether a method is a trampoline.
  */
 guint8 *mono_generic_trampoline_code = NULL;
 
+/*
+ * AMD64 processors maintain icache coherency only for pages which are marked
+ * executable, so we have to alloc memory through a code manager.
+ */
+static CRITICAL_SECTION tramp_codeman_mutex;
+static MonoCodeManager *tramp_codeman;
+
 /*
  * get_unbox_trampoline:
  * @m: method pointer
@@ -52,11 +56,14 @@ get_unbox_trampoline (MonoMethod *m, gpointer addr)
 {
        guint8 *code, *start;
        int this_reg = AMD64_RDI;
+       MonoDomain *domain = mono_domain_get ();
 
        if (!m->signature->ret->byref && MONO_TYPE_ISSTRUCT (m->signature->ret))
                this_reg = AMD64_RSI;
-           
-       start = code = g_malloc (20);
+
+       mono_domain_lock (domain);
+       start = code = mono_code_manager_reserve (domain->code_mp, 20);
+       mono_domain_unlock (domain);
 
        amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
        /* FIXME: Optimize this */
@@ -138,18 +145,31 @@ amd64_class_init_trampoline (long *regs, guint8 *code, MonoVTable *vtable)
 {
        mono_runtime_class_init (vtable);
 
-       /* FIXME: patch calling code */
-
        code -= 3;
        if ((code [0] == 0x49) && (code [1] == 0xff)) {
                if (!mono_running_on_valgrind ()) {
+                       /* amd64_set_reg_template is 10 bytes long */
+                       guint8* buf = code - 10;
 
                        /* FIXME: Make this thread safe */
-                       code [0] = code [1] = code [2] = 0x90;
+                       /* Padding code suggested by the AMD64 Opt Manual */
+                       buf [0] = 0x66;
+                       buf [1] = 0x66;
+                       buf [2] = 0x66;
+                       buf [3] = 0x90;
+                       buf [4] = 0x66;
+                       buf [5] = 0x66;
+                       buf [6] = 0x66;
+                       buf [7] = 0x90;
+                       buf [8] = 0x66;
+                       buf [9] = 0x66;
+                       buf [10] = 0x90;
+                       buf [11] = 0x66;
+                       buf [12] = 0x90;
                }
        }
        else
-               if (code [0] == 0x90 || code [0] == 0xeb)
+               if (code [0] == 0x90 || code [0] == 0xeb || code [0] == 0x66)
                        /* Already changed by another thread */
                        ;
                else {
@@ -182,7 +202,9 @@ create_trampoline_code (MonoTrampolineType tramp_type)
                break;
        }
 
-       code = buf = g_malloc (512);
+       EnterCriticalSection (&tramp_codeman_mutex);
+       code = buf = mono_code_manager_reserve (tramp_codeman, 512);
+       LeaveCriticalSection (&tramp_codeman_mutex);
 
        framesize = 512 + sizeof (MonoLMF);
        framesize = (framesize + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
@@ -307,6 +329,8 @@ create_trampoline_code (MonoTrampolineType tramp_type)
 
        g_assert ((code - buf) <= 512);
 
+       mono_arch_flush_icache (buf, code - buf);
+
        switch (tramp_type) {
        case MONO_TRAMPOLINE_GENERIC:
                mono_generic_trampoline_code = buf;
@@ -322,7 +346,7 @@ create_trampoline_code (MonoTrampolineType tramp_type)
        return buf;
 }
 
-#define TRAMPOLINE_SIZE 30
+#define TRAMPOLINE_SIZE 34
 
 static MonoJitInfo*
 create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain)
@@ -387,7 +411,7 @@ mono_arch_create_jit_trampoline (MonoMethod *method)
        MonoJitInfo *ji;
        MonoDomain *domain = mono_domain_get ();
 
-       /* Trampoline are arch specific, so cache only the one used in the root domain */
+       /* Trampoline are domain specific, so cache only the one used in the root domain */
        if ((domain == mono_get_root_domain ()) && method->info)
                return method->info;
 
@@ -426,6 +450,19 @@ mono_arch_create_class_init_trampoline (MonoVTable *vtable)
        return code;
 }
 
+void
+mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
+{
+       /* FIXME: This is not thread safe */
+       guint8 *code = ji->code_start;
+
+       amd64_mov_reg_imm (code, AMD64_RDI, func_arg);
+       amd64_mov_reg_imm (code, AMD64_R11, func);
+
+       x86_push_imm (code, (guint64)func_arg);
+       amd64_call_reg (code, AMD64_R11);
+}
+
 /*
  * This method is only called when running in the Mono Debugger.
  */
@@ -434,7 +471,10 @@ mono_debugger_create_notification_function (gpointer *notification_address)
 {
        guint8 *ptr, *buf;
 
-       ptr = buf = g_malloc0 (16);
+       EnterCriticalSection (&tramp_codeman_mutex);
+       ptr = buf = mono_code_manager_reserve (tramp_codeman, 16);
+       LeaveCriticalSection (&tramp_codeman_mutex);
+
        x86_breakpoint (buf);
        if (notification_address)
                *notification_address = buf;
@@ -443,3 +483,14 @@ mono_debugger_create_notification_function (gpointer *notification_address)
        return ptr;
 }
 
+void
+mono_amd64_tramp_init (void)
+{
+       InitializeCriticalSection (&tramp_codeman_mutex);
+
+       tramp_codeman = mono_code_manager_new ();
+
+       create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
+       create_trampoline_code (MONO_TRAMPOLINE_JUMP);
+       create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
+}