In metadata/
[mono.git] / mono / mini / tramp-amd64.c
index c22b72d206a9d76e7591f9cdc1b5a11c9103c73f..c5a10f8339737839e7bd5837b3ea249ed48ff7f5 100644 (file)
@@ -49,9 +49,7 @@ mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m,
 
        this_reg = mono_arch_get_this_arg_reg (mono_method_signature (m), gsctx, NULL);
 
-       mono_domain_lock (domain);
-       start = code = mono_code_manager_reserve (domain->code_mp, 20);
-       mono_domain_unlock (domain);
+       start = code = mono_domain_code_reserve (domain, 20);
 
        amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
        /* FIXME: Optimize this */
@@ -64,6 +62,40 @@ mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m,
        return start;
 }
 
+/*
+ * mono_arch_get_static_rgctx_trampoline:
+ *
+ *   Create a trampoline which sets RGCTX_REG to MRGCTX, then jumps to ADDR.
+ */
+gpointer
+mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
+{
+       guint8 *code, *start;
+       int buf_len;
+
+       MonoDomain *domain = mono_domain_get ();
+
+#ifdef MONO_ARCH_NOMAP32BIT
+       buf_len = 32;
+#else
+       /* AOTed code could still have a non-32 bit address */
+       if ((((guint64)addr) >> 32) == 0)
+               buf_len = 16;
+       else
+               buf_len = 30;
+#endif
+
+       start = code = mono_domain_code_reserve (domain, buf_len);
+
+       amd64_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
+       amd64_jump_code (code, addr);
+       g_assert ((code - start) < buf_len);
+
+       mono_arch_flush_icache (start, code - start);
+
+       return start;
+}
+
 /*
  * mono_arch_patch_callsite:
  *
@@ -157,19 +189,28 @@ mono_arch_nullify_class_init_trampoline (guint8 *code, gssize *regs)
                gpointer *vtable_slot;
 
                /* call *<OFFSET>(%rip) */
-               vtable_slot = mono_arch_get_vcall_slot_addr (code + 3, (gpointer*)regs);
+               vtable_slot = mono_get_vcall_slot_addr (code + 3, (gpointer*)regs);
                g_assert (vtable_slot);
 
                *vtable_slot = nullified_class_init_trampoline;
        } else if (code [-2] == 0xe8) {
                /* call <TARGET> */
-               guint8 *buf = code - 2;
-
+               //guint8 *buf = code - 2;
+
+               /* 
+                * It would be better to replace the call with nops, but that doesn't seem
+                * to work on SMP machines even when the whole call is inside a cache line.
+                * Patching the call address seems to work.
+                */
+               /*
                buf [0] = 0x66;
                buf [1] = 0x66;
                buf [2] = 0x90;
                buf [3] = 0x66;
                buf [4] = 0x90;
+               */
+
+               mono_arch_patch_callsite (code - 2, code - 2 + 5, nullified_class_init_trampoline);
        } else if ((code [0] == 0x41) && (code [1] == 0xff)) {
                /* call <REG> */
                /* happens on machines without MAP_32BIT like freebsd */
@@ -215,19 +256,28 @@ mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
 {
        MonoJumpInfo *ji;
        guint32 code_size;
+       guchar *code;
+       GSList *unwind_ops, *l;
+
+       code = mono_arch_create_trampoline_code_full (tramp_type, &code_size, &ji, &unwind_ops, FALSE);
+
+       mono_save_trampoline_xdebug_info ("<generic_trampoline>", code, code_size, unwind_ops);
+
+       for (l = unwind_ops; l; l = l->next)
+               g_free (l->data);
+       g_slist_free (unwind_ops);
 
-       return mono_arch_create_trampoline_code_full (tramp_type, &code_size, &ji, FALSE);
+       return code;
 }
 
 guchar*
-mono_arch_create_trampoline_code_full (MonoTrampolineType tramp_type, guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
+mono_arch_create_trampoline_code_full (MonoTrampolineType tramp_type, guint32 *code_size, MonoJumpInfo **ji, GSList **out_unwind_ops, gboolean aot)
 {
        guint8 *buf, *code, *tramp, *br [2], *r11_save_code, *after_r11_save_code;
        int i, lmf_offset, offset, res_offset, arg_offset, rax_offset, tramp_offset, saved_regs_offset;
        int saved_fpregs_offset, rbp_offset, framesize, orig_rsp_to_rbp_offset, cfa_offset;
        gboolean has_caller;
        GSList *unwind_ops = NULL;
-       GSList *l;
 
        if (tramp_type == MONO_TRAMPOLINE_JUMP)
                has_caller = FALSE;
@@ -501,11 +551,7 @@ mono_arch_create_trampoline_code_full (MonoTrampolineType tramp_type, guint32 *c
                nullified_class_init_trampoline = mono_arch_get_nullified_class_init_trampoline (&code_len);
        }
 
-       mono_save_trampoline_xdebug_info ("<generic_trampoline>", buf, *code_size, unwind_ops);
-
-       for (l = unwind_ops; l; l = l->next)
-               g_free (l->data);
-       g_slist_free (unwind_ops);
+       *out_unwind_ops = unwind_ops;
        
        return buf;
 }
@@ -538,9 +584,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty
        else
                size = 5 + 1 + 8;
 
-       mono_domain_lock (domain);
-       code = buf = mono_code_manager_reserve_align (domain->code_mp, size, 1);
-       mono_domain_unlock (domain);
+       code = buf = mono_domain_code_reserve_align (domain, size, 1);
 
        amd64_call_code (code, tramp);
        /* The trampoline code will obtain the argument from the instruction stream */
@@ -745,6 +789,8 @@ mono_arch_create_monitor_enter_trampoline_full (guint32 *code_size, MonoJumpInfo
        int tramp_size;
        int owner_offset, nest_offset, dummy;
 
+       *ji = NULL;
+
        g_assert (MONO_ARCH_MONITOR_OBJECT_REG == AMD64_RDI);
 
        mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &dummy);
@@ -857,6 +903,8 @@ mono_arch_create_monitor_exit_trampoline_full (guint32 *code_size, MonoJumpInfo
        int tramp_size;
        int owner_offset, nest_offset, entry_count_offset;
 
+       *ji = NULL;
+
        g_assert (MONO_ARCH_MONITOR_OBJECT_REG == AMD64_RDI);
 
        mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &entry_count_offset);