#include "mini.h"
#include "mini-amd64.h"
-typedef enum {
- MONO_TRAMPOLINE_GENERIC,
- MONO_TRAMPOLINE_JUMP,
- MONO_TRAMPOLINE_CLASS_INIT
-} MonoTrampolineType;
-
-/*
- * 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;
-
/*
* get_unbox_trampoline:
* @m: method pointer
/* the method was jumped to */
if (!code)
+ /* FIXME: Optimize the case when the call is from a delegate wrapper */
return addr;
- vtable_slot = mono_amd64_get_vcall_slot_addr (code, regs);
+ vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
if (vtable_slot) {
if (m->klass->valuetype)
else {
/* Patch calling code */
- if ((code [-13] == 0x49) && (code [-12] == 0xbb)) {
+ if (((code [-13] == 0x49) && (code [-12] == 0xbb)) ||
+ (code [-5] == 0xe8)) {
MonoJitInfo *ji =
mono_jit_info_table_find (mono_domain_get (), code);
MonoJitInfo *target_ji =
mono_jit_info_table_find (mono_domain_get (), addr);
if (mono_method_same_domain (ji, target_ji)) {
- InterlockedExchangePointer ((gpointer*)(code - 11), addr);
+ if (code [-5] != 0xe8)
+ InterlockedExchangePointer ((gpointer*)(code - 11), addr);
+ else {
+ g_assert ((((guint64)(addr)) >> 32) == 0);
+ g_assert ((((guint64)(code)) >> 32) == 0);
+ InterlockedExchange ((guint32*)(code - 4), ((gint64)addr - (gint64)code));
+ }
}
}
else if ((code [-7] == 0x41) && (code [-6] == 0xff) && (code [-5] == 0x15)) {
InterlockedExchangePointer (got_entry, addr);
}
}
- else {
- /* FIXME: handle more cases */
- }
-
- /* Patch trampoline */
- /* FIXME: Make this thread safe */
- if (!m->klass->valuetype) {
- /*
- * Valuetype method trampolines can't be patched since they are used for virtual
- * calls which need an unbox trampoline.
- */
- amd64_mov_reg_imm (tramp, AMD64_R11, addr);
- amd64_jump_reg (tramp, AMD64_R11);
- }
}
return addr;
}
+/*
+ * amd64_aot_trampoline:
+ *
+ * This trampoline handles calls made from AOT code. We try to bypass the
+ * normal JIT compilation logic to avoid loading the metadata for the method.
+ */
+static gpointer
+amd64_aot_trampoline (long *regs, guint8 *code, guint8 *token_info,
+ guint8* tramp)
+{
+ MonoImage *image;
+ guint32 token;
+ MonoMethod *method;
+ gpointer addr;
+ gpointer *vtable_slot;
+
+ 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);
+
+ if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ method = mono_marshal_get_synchronized_wrapper (method);
+
+ addr = mono_compile_method (method);
+ g_assert (addr);
+
+ 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);
+
+ if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
+ *vtable_slot = addr;
+
+ return addr;
+}
+
/**
* amd64_class_init_trampoline:
*
buf [11] = 0x66;
buf [12] = 0x90;
}
- }
- else if (code [0] == 0x90 || code [0] == 0xeb || code [0] == 0x66)
+ } else if (code [-2] == 0xe8) {
+ guint8 *buf = code - 2;
+
+ buf [0] = 0x66;
+ buf [1] = 0x66;
+ buf [2] = 0x90;
+ buf [3] = 0x66;
+ buf [4] = 0x90;
+ } else if (code [0] == 0x90 || code [0] == 0xeb || code [0] == 0x66)
/* Already changed by another thread */
;
else if ((code [-4] == 0x41) && (code [-3] == 0xff) && (code [-2] == 0x15))
}
}
-static guchar*
-create_trampoline_code (MonoTrampolineType tramp_type)
+guchar*
+mono_arch_create_trampoline_code (MonoTrampolineType tramp_type)
{
guint8 *buf, *code, *tramp;
int i, lmf_offset, offset, method_offset, tramp_offset, saved_regs_offset, saved_fpregs_offset, framesize;
- static guint8* generic_jump_trampoline = NULL;
- static guint8 *generic_class_init_trampoline = NULL;
-
- switch (tramp_type) {
- case MONO_TRAMPOLINE_GENERIC:
- if (mono_generic_trampoline_code)
- return mono_generic_trampoline_code;
- break;
- case MONO_TRAMPOLINE_JUMP:
- if (generic_jump_trampoline)
- return generic_jump_trampoline;
- break;
- case MONO_TRAMPOLINE_CLASS_INIT:
- if (generic_class_init_trampoline)
- return generic_class_init_trampoline;
- break;
- }
+ gboolean has_caller;
+
+ if (tramp_type == MONO_TRAMPOLINE_JUMP)
+ has_caller = FALSE;
+ else
+ has_caller = TRUE;
code = buf = mono_global_codeman_reserve (512);
lmf_offset = - offset;
/* Save ip */
- if (tramp_type == MONO_TRAMPOLINE_JUMP)
- amd64_mov_reg_imm (code, AMD64_R11, 0);
- else
+ if (has_caller)
amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, 8, 8);
+ else
+ amd64_mov_reg_imm (code, AMD64_R11, 0);
amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rip), AMD64_R11, 8);
/* Save fp */
amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp), AMD64_RBP, 8);
amd64_lea_membase (code, AMD64_RDI, AMD64_RBP, saved_regs_offset);
/* Arg2 is the address of the calling code */
- amd64_mov_reg_membase (code, AMD64_RSI, AMD64_RBP, 8, 8);
+ if (has_caller)
+ amd64_mov_reg_membase (code, AMD64_RSI, AMD64_RBP, 8, 8);
+ else
+ amd64_mov_reg_imm (code, AMD64_RSI, 0);
/* Arg3 is the method/vtable ptr */
amd64_mov_reg_membase (code, AMD64_RDX, AMD64_RBP, method_offset, 8);
if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT)
tramp = (guint8*)amd64_class_init_trampoline;
+ else if (tramp_type == MONO_TRAMPOLINE_AOT)
+ tramp = (guint8*)amd64_aot_trampoline;
else
tramp = (guint8*)amd64_magic_trampoline;
mono_arch_flush_icache (buf, code - buf);
- switch (tramp_type) {
- case MONO_TRAMPOLINE_GENERIC:
- mono_generic_trampoline_code = buf;
- break;
- case MONO_TRAMPOLINE_JUMP:
- generic_jump_trampoline = buf;
- break;
- case MONO_TRAMPOLINE_CLASS_INIT:
- generic_class_init_trampoline = buf;
- break;
- }
-
return buf;
}
{
MonoJitInfo *ji;
guint8 *code, *buf, *tramp;
+ int jump_offset;
- 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);
- mono_domain_unlock (domain);
+ code = buf = g_alloca (TRAMPOLINE_SIZE);
/* push trampoline address */
amd64_lea_membase (code, AMD64_R11, AMD64_RIP, -7);
amd64_push_reg (code, AMD64_R11);
/* push argument */
- amd64_mov_reg_imm (code, AMD64_R11, arg1);
- amd64_push_reg (code, AMD64_R11);
+ if (amd64_is_imm32 ((gint64)arg1))
+ amd64_push_imm (code, (gint64)arg1);
+ else {
+ amd64_mov_reg_imm (code, AMD64_R11, arg1);
+ amd64_push_reg (code, AMD64_R11);
+ }
- /* FIXME: Optimize this */
- amd64_mov_reg_imm (code, AMD64_R11, tramp);
- amd64_jump_reg (code, AMD64_R11);
+ jump_offset = code - buf;
+ amd64_jump_disp (code, 0xffffffff);
g_assert ((code - buf) <= TRAMPOLINE_SIZE);
ji = g_new0 (MonoJitInfo, 1);
- ji->code_start = buf;
+
+ mono_domain_lock (domain);
+ /*
+ * FIXME: Changing the size to code - buf causes strange crashes during
+ * mcs bootstrap.
+ */
+ ji->code_start = mono_code_manager_reserve (domain->code_mp, TRAMPOLINE_SIZE);
ji->code_size = code - buf;
+ mono_domain_unlock (domain);
+
+ memcpy (ji->code_start, buf, ji->code_size);
+
+ /* Fix up jump */
+ g_assert ((((gint64)tramp) >> 32) == 0);
+ code = (guint8*)ji->code_start + jump_offset;
+ amd64_jump_disp (code, tramp - code);
mono_jit_stats.method_trampolines++;
return code_start;
}
+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);
+ buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
+ mono_domain_unlock (domain);
+
+ *(gpointer*)buf = image;
+ 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;
+}
+
/**
* mono_arch_create_class_init_trampoline:
* @vtable: the type to initialize
return ptr;
}
-
-void
-mono_amd64_tramp_init (void)
-{
- create_trampoline_code (MONO_TRAMPOLINE_GENERIC);
- create_trampoline_code (MONO_TRAMPOLINE_JUMP);
- create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
-}