Fix code buffer reallocation check for OP_SWITCH on arm.
[mono.git] / mono / mini / tramp-amd64.c
1 /*
2  * tramp-amd64.c: JIT trampoline code for amd64
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Zoltan Varga (vargaz@gmail.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13
14 #include <mono/metadata/appdomain.h>
15 #include <mono/metadata/marshal.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/mono-debug-debugger.h>
18 #include <mono/metadata/monitor.h>
19 #include <mono/arch/amd64/amd64-codegen.h>
20
21 #include <mono/utils/memcheck.h>
22
23 #include "mini.h"
24 #include "mini-amd64.h"
25
26 #define IS_REX(inst) (((inst) >= 0x40) && ((inst) <= 0x4f))
27
28 static guint8* nullified_class_init_trampoline;
29
30 /*
31  * mono_arch_get_unbox_trampoline:
32  * @gsctx: the generic sharing context
33  * @m: method pointer
34  * @addr: pointer to native code for @m
35  *
36  * when value type methods are called through the vtable we need to unbox the
37  * this argument. This method returns a pointer to a trampoline which does
38  * unboxing before calling the method
39  */
40 gpointer
41 mono_arch_get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr)
42 {
43         guint8 *code, *start;
44         int this_reg;
45
46         MonoDomain *domain = mono_domain_get ();
47
48         this_reg = mono_arch_get_this_arg_reg (mono_method_signature (m), gsctx, NULL);
49
50         start = code = mono_domain_code_reserve (domain, 20);
51
52         amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
53         /* FIXME: Optimize this */
54         amd64_mov_reg_imm (code, AMD64_RAX, addr);
55         amd64_jump_reg (code, AMD64_RAX);
56         g_assert ((code - start) < 20);
57
58         mono_arch_flush_icache (start, code - start);
59
60         return start;
61 }
62
63 /*
64  * mono_arch_get_static_rgctx_trampoline:
65  *
66  *   Create a trampoline which sets RGCTX_REG to MRGCTX, then jumps to ADDR.
67  */
68 gpointer
69 mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
70 {
71         guint8 *code, *start;
72         int buf_len;
73
74         MonoDomain *domain = mono_domain_get ();
75
76 #ifdef MONO_ARCH_NOMAP32BIT
77         buf_len = 32;
78 #else
79         /* AOTed code could still have a non-32 bit address */
80         if ((((guint64)addr) >> 32) == 0)
81                 buf_len = 16;
82         else
83                 buf_len = 30;
84 #endif
85
86         start = code = mono_domain_code_reserve (domain, buf_len);
87
88         amd64_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
89         amd64_jump_code (code, addr);
90         g_assert ((code - start) < buf_len);
91
92         mono_arch_flush_icache (start, code - start);
93
94         return start;
95 }
96
97 gpointer
98 mono_arch_get_llvm_imt_trampoline (MonoDomain *domain, MonoMethod *m, int vt_offset)
99 {
100         guint8 *code, *start;
101         int buf_len;
102         int this_reg;
103
104         buf_len = 32;
105
106         start = code = mono_domain_code_reserve (domain, buf_len);
107
108         this_reg = mono_arch_get_this_arg_reg (mono_method_signature (m), NULL, NULL);
109
110         /* Set imt arg */
111         amd64_mov_reg_imm (code, MONO_ARCH_IMT_REG, m);
112         /* Load vtable address */
113         amd64_mov_reg_membase (code, AMD64_RAX, this_reg, 0, 8);
114         amd64_jump_membase (code, AMD64_RAX, vt_offset);
115         amd64_ret (code);
116
117         g_assert ((code - start) < buf_len);
118
119         mono_arch_flush_icache (start, code - start);
120
121         return start;
122 }
123
124 /*
125  * mono_arch_patch_callsite:
126  *
127  *   Patch the callsite whose address is given by ORIG_CODE so it calls ADDR. ORIG_CODE
128  * points to the pc right after the call.
129  */
130 void
131 mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
132 {
133         guint8 *code;
134         guint8 buf [16];
135         gboolean can_write = mono_breakpoint_clean_code (method_start, orig_code, 14, buf, sizeof (buf));
136
137         code = buf + 14;
138
139         if (((code [-13] == 0x49) && (code [-12] == 0xbb)) || (code [-5] == 0xe8)) {
140                 if (code [-5] != 0xe8) {
141                         if (can_write) {
142                                 InterlockedExchangePointer ((gpointer*)(orig_code - 11), addr);
143                                 VALGRIND_DISCARD_TRANSLATIONS (orig_code - 11, sizeof (gpointer));
144                         }
145                 } else {
146                         if ((((guint64)(addr)) >> 32) != 0) {
147 #ifdef MONO_ARCH_NOMAP32BIT
148                                 /* Print some diagnostics */
149                                 MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), (char*)orig_code);
150                                 if (ji)
151                                         fprintf (stderr, "At %s, offset 0x%zx\n", mono_method_full_name (ji->method, TRUE), (guint8*)orig_code - (guint8*)ji->code_start);
152                                 fprintf (stderr, "Addr: %p\n", addr);
153                                 ji = mono_jit_info_table_find (mono_domain_get (), (char*)addr);
154                                 if (ji)
155                                         fprintf (stderr, "Callee: %s\n", mono_method_full_name (ji->method, TRUE));
156                                 g_assert_not_reached ();
157 #else
158                                 /* 
159                                  * This might happen when calling AOTed code. Create a thunk.
160                                  */
161                                 guint8 *thunk_start, *thunk_code;
162
163                                 thunk_start = thunk_code = mono_domain_code_reserve (mono_domain_get (), 32);
164                                 amd64_jump_membase (thunk_code, AMD64_RIP, 0);
165                                 *(guint64*)thunk_code = (guint64)addr;
166                                 addr = thunk_start;
167                                 g_assert ((((guint64)(addr)) >> 32) == 0);
168                                 mono_arch_flush_icache (thunk_start, thunk_code - thunk_start);
169 #endif
170                         }
171                         g_assert ((((guint64)(orig_code)) >> 32) == 0);
172                         if (can_write) {
173                                 InterlockedExchange ((gint32*)(orig_code - 4), ((gint64)addr - (gint64)orig_code));
174                                 VALGRIND_DISCARD_TRANSLATIONS (orig_code - 5, 4);
175                         }
176                 }
177         }
178         else if ((code [-7] == 0x41) && (code [-6] == 0xff) && (code [-5] == 0x15)) {
179                 /* call *<OFFSET>(%rip) */
180                 gpointer *got_entry = (gpointer*)((guint8*)orig_code + (*(guint32*)(orig_code - 4)));
181                 if (can_write) {
182                         InterlockedExchangePointer (got_entry, addr);
183                         VALGRIND_DISCARD_TRANSLATIONS (orig_code - 5, sizeof (gpointer));
184                 }
185         }
186 }
187
188 void
189 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
190 {
191         gint32 disp;
192         gpointer *plt_jump_table_entry;
193
194         /* A PLT entry: jmp *<DISP>(%rip) */
195         g_assert (code [0] == 0xff);
196         g_assert (code [1] == 0x25);
197
198         disp = *(gint32*)(code + 2);
199
200         plt_jump_table_entry = (gpointer*)(code + 6 + disp);
201
202         InterlockedExchangePointer (plt_jump_table_entry, addr);
203 }
204
205 static gpointer
206 get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
207 {
208         guint8 buf [10];
209         gint32 disp;
210         MonoJitInfo *ji = NULL;
211
212 #ifdef ENABLE_LLVM
213         /* code - 9 might be before the start of the method */
214         /* FIXME: Avoid this expensive call somehow */
215         ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
216 #endif
217
218         mono_breakpoint_clean_code (ji ? ji->code_start : NULL, code, 9, buf, sizeof (buf));
219         code = buf + 9;
220
221         *displacement = 0;
222
223         code -= 7;
224
225         if ((code [0] == 0x41) && (code [1] == 0xff) && (code [2] == 0x15)) {
226                 /* call OFFSET(%rip) */
227                 g_assert_not_reached ();
228                 *displacement = *(guint32*)(code + 3);
229                 return (gpointer*)(code + disp + 7);
230         } else {
231                 g_assert_not_reached ();
232                 return NULL;
233         }
234 }
235
236 static gpointer*
237 get_vcall_slot_addr (guint8* code, mgreg_t *regs)
238 {
239         gpointer vt;
240         int displacement;
241         vt = get_vcall_slot (code, regs, &displacement);
242         if (!vt)
243                 return NULL;
244         return (gpointer*)((char*)vt + displacement);
245 }
246
247 void
248 mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs)
249 {
250         guint8 buf [16];
251         MonoJitInfo *ji = NULL;
252         gboolean can_write;
253
254         if (mono_use_llvm) {
255                 /* code - 7 might be before the start of the method */
256                 /* FIXME: Avoid this expensive call somehow */
257                 ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
258         }
259
260         can_write = mono_breakpoint_clean_code (ji ? ji->code_start : NULL, code, 7, buf, sizeof (buf));
261
262         if (!can_write)
263                 return;
264
265         /* 
266          * A given byte sequence can match more than case here, so we have to be
267          * really careful about the ordering of the cases. Longer sequences
268          * come first.
269          */
270         if ((buf [0] == 0x41) && (buf [1] == 0xff) && (buf [2] == 0x15)) {
271                 gpointer *vtable_slot;
272
273                 /* call *<OFFSET>(%rip) */
274                 vtable_slot = get_vcall_slot_addr (code, regs);
275                 g_assert (vtable_slot);
276
277                 *vtable_slot = nullified_class_init_trampoline;
278         } else if (buf [2] == 0xe8) {
279                 /* call <TARGET> */
280                 //guint8 *buf = code - 2;
281
282                 /* 
283                  * It would be better to replace the call with nops, but that doesn't seem
284                  * to work on SMP machines even when the whole call is inside a cache line.
285                  * Patching the call address seems to work.
286                  */
287                 /*
288                 buf [0] = 0x66;
289                 buf [1] = 0x66;
290                 buf [2] = 0x90;
291                 buf [3] = 0x66;
292                 buf [4] = 0x90;
293                 */
294
295                 mono_arch_patch_callsite (code - 5, code, nullified_class_init_trampoline);
296         } else if ((buf [5] == 0xff) && x86_modrm_mod (buf [6]) == 3 && x86_modrm_reg (buf [6]) == 2) {
297                 /* call *<reg> */
298                 /* Generated by the LLVM JIT or on platforms without MAP_32BIT set */
299                 mono_arch_patch_callsite (code - 13, code, nullified_class_init_trampoline);
300         } else if (buf [4] == 0x90 || buf [5] == 0xeb || buf [6] == 0x66) {
301                 /* Already changed by another thread */
302                 ;
303         } else {
304                 printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", buf [0], buf [1], buf [2], buf [3],
305                         buf [4], buf [5], buf [6]);
306                 g_assert_not_reached ();
307         }
308 }
309
310 void
311 mono_arch_nullify_plt_entry (guint8 *code, mgreg_t *regs)
312 {
313         if (mono_aot_only && !nullified_class_init_trampoline)
314                 nullified_class_init_trampoline = mono_aot_get_trampoline ("nullified_class_init_trampoline");
315
316         mono_arch_patch_plt_entry (code, NULL, regs, nullified_class_init_trampoline);
317 }
318
319 guchar*
320 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
321 {
322         guint8 *buf, *code, *tramp, *br [2], *r11_save_code, *after_r11_save_code;
323         int i, lmf_offset, offset, res_offset, arg_offset, rax_offset, tramp_offset;
324         int buf_len, saved_regs_offset;
325         int saved_fpregs_offset, rbp_offset, framesize, orig_rsp_to_rbp_offset, cfa_offset;
326         gboolean has_caller;
327         GSList *unwind_ops = NULL;
328         MonoJumpInfo *ji = NULL;
329
330         if (tramp_type == MONO_TRAMPOLINE_JUMP)
331                 has_caller = FALSE;
332         else
333                 has_caller = TRUE;
334
335         buf_len = 548;
336         code = buf = mono_global_codeman_reserve (buf_len);
337
338         framesize = 538 + sizeof (MonoLMF);
339         framesize = (framesize + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
340
341         orig_rsp_to_rbp_offset = 0;
342         r11_save_code = code;
343         /* Reserve 5 bytes for the mov_membase_reg to save R11 */
344         code += 5;
345         after_r11_save_code = code;
346
347         // CFA = sp + 16 (the trampoline address is on the stack)
348         cfa_offset = 16;
349         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, 16);
350         // IP saved at CFA - 8
351         mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RIP, -8);
352
353         /* Pop the return address off the stack */
354         amd64_pop_reg (code, AMD64_R11);
355         orig_rsp_to_rbp_offset += 8;
356
357         cfa_offset -= 8;
358         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
359
360         /* 
361          * Allocate a new stack frame
362          */
363         amd64_push_reg (code, AMD64_RBP);
364         cfa_offset += 8;
365         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
366         mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RBP, - cfa_offset);
367
368         orig_rsp_to_rbp_offset -= 8;
369         amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, 8);
370         mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
371         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
372
373         offset = 0;
374         rbp_offset = - offset;
375
376         offset += 8;
377         rax_offset = - offset;
378
379         offset += 8;
380         tramp_offset = - offset;
381
382         offset += 8;
383         arg_offset = - offset;
384
385         /* Compute the trampoline address from the return address */
386         if (aot) {
387                 /* 7 = length of call *<offset>(rip) */
388                 amd64_alu_reg_imm (code, X86_SUB, AMD64_R11, 7);
389         } else {
390                 /* 5 = length of amd64_call_membase () */
391                 amd64_alu_reg_imm (code, X86_SUB, AMD64_R11, 5);
392         }
393         amd64_mov_membase_reg (code, AMD64_RBP, tramp_offset, AMD64_R11, 8);
394
395         offset += 8;
396         res_offset = - offset;
397
398         /* Save all registers */
399
400         offset += AMD64_NREG * 8;
401         saved_regs_offset = - offset;
402         for (i = 0; i < AMD64_NREG; ++i) {
403                 if (i == AMD64_RBP) {
404                         /* RAX is already saved */
405                         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RBP, rbp_offset, 8);
406                         amd64_mov_membase_reg (code, AMD64_RBP, saved_regs_offset + (i * 8), AMD64_RAX, 8);
407                 } else if (i != AMD64_R11) {
408                         amd64_mov_membase_reg (code, AMD64_RBP, saved_regs_offset + (i * 8), i, 8);
409                 } else {
410                         /* We have to save R11 right at the start of
411                            the trampoline code because it's used as a
412                            scratch register */
413                         amd64_mov_membase_reg (r11_save_code, AMD64_RSP, saved_regs_offset + orig_rsp_to_rbp_offset + (i * 8), i, 8);
414                         g_assert (r11_save_code == after_r11_save_code);
415                 }
416         }
417         offset += 8 * 8;
418         saved_fpregs_offset = - offset;
419         for (i = 0; i < 8; ++i)
420                 amd64_movsd_membase_reg (code, AMD64_RBP, saved_fpregs_offset + (i * 8), i);
421
422         if (tramp_type != MONO_TRAMPOLINE_GENERIC_CLASS_INIT &&
423                         tramp_type != MONO_TRAMPOLINE_MONITOR_ENTER &&
424                         tramp_type != MONO_TRAMPOLINE_MONITOR_EXIT) {
425                 /* Obtain the trampoline argument which is encoded in the instruction stream */
426                 if (aot) {
427                         /* Load the GOT offset */
428                         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, tramp_offset, 8);
429                         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 7, 4);
430                         /* Compute the address of the GOT slot */
431                         amd64_alu_reg_reg_size (code, X86_ADD, AMD64_R11, AMD64_RAX, 8);
432                         /* Load the value */
433                         amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, 8);
434                 } else {                        
435                         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, tramp_offset, 8);
436                         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 5, 1);
437                         amd64_widen_reg (code, AMD64_RAX, AMD64_RAX, TRUE, FALSE);
438                         amd64_alu_reg_imm_size (code, X86_CMP, AMD64_RAX, 4, 1);
439                         br [0] = code;
440                         x86_branch8 (code, X86_CC_NE, 6, FALSE);
441                         /* 32 bit immediate */
442                         amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 6, 4);
443                         br [1] = code;
444                         x86_jump8 (code, 10);
445                         /* 64 bit immediate */
446                         mono_amd64_patch (br [0], code);
447                         amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 6, 8);
448                         mono_amd64_patch (br [1], code);
449                 }
450                 amd64_mov_membase_reg (code, AMD64_RBP, arg_offset, AMD64_R11, 8);
451         } else {
452                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, saved_regs_offset + (MONO_AMD64_ARG_REG1 * 8), 8);
453                 amd64_mov_membase_reg (code, AMD64_RBP, arg_offset, AMD64_R11, 8);
454         }
455
456         /* Save LMF begin */
457
458         offset += sizeof (MonoLMF);
459         lmf_offset = - offset;
460
461         /* Save ip */
462         if (has_caller)
463                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, 8, 8);
464         else
465                 amd64_mov_reg_imm (code, AMD64_R11, 0);
466         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rip), AMD64_R11, 8);
467         /* Save fp */
468         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RSP, framesize, 8);
469         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rbp), AMD64_R11, 8);
470         /* Save sp */
471         amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, 8);
472         amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, framesize + 16);
473         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsp), AMD64_R11, 8);
474         /* Save method */
475         if (tramp_type == MONO_TRAMPOLINE_JIT || tramp_type == MONO_TRAMPOLINE_JUMP) {
476                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, arg_offset, 8);
477                 amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), AMD64_R11, 8);
478         } else {
479                 amd64_mov_membase_imm (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), 0, 8);
480         }
481         /* Save callee saved regs */
482 #ifdef TARGET_WIN32
483         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rdi), AMD64_RDI, 8);
484         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rsi), AMD64_RSI, 8);
485 #endif
486         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, rbx), AMD64_RBX, 8);
487         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r12), AMD64_R12, 8);
488         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r13), AMD64_R13, 8);
489         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r14), AMD64_R14, 8);
490         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, r15), AMD64_R15, 8);
491
492         if (aot) {
493                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr");
494         } else {
495                 amd64_mov_reg_imm (code, AMD64_R11, mono_get_lmf_addr);
496         }
497         amd64_call_reg (code, AMD64_R11);
498
499         /* Save lmf_addr */
500         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), AMD64_RAX, 8);
501         /* Save previous_lmf */
502         /* Set the lowest bit to 1 to signal that this LMF has the ip field set */
503         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, 0, 8);
504         amd64_alu_reg_imm_size (code, X86_ADD, AMD64_R11, 1, 8);
505         amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_R11, 8);
506         /* Set new lmf */
507         amd64_lea_membase (code, AMD64_R11, AMD64_RBP, lmf_offset);
508         amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, 8);
509
510         /* Save LMF end */
511
512         /* Arg1 is the pointer to the saved registers */
513         amd64_lea_membase (code, AMD64_ARG_REG1, AMD64_RBP, saved_regs_offset);
514
515         /* Arg2 is the address of the calling code */
516         if (has_caller)
517                 amd64_mov_reg_membase (code, AMD64_ARG_REG2, AMD64_RBP, 8, 8);
518         else
519                 amd64_mov_reg_imm (code, AMD64_ARG_REG2, 0);
520
521         /* Arg3 is the method/vtable ptr */
522         amd64_mov_reg_membase (code, AMD64_ARG_REG3, AMD64_RBP, arg_offset, 8);
523
524         /* Arg4 is the trampoline address */
525         amd64_mov_reg_membase (code, AMD64_ARG_REG4, AMD64_RBP, tramp_offset, 8);
526
527         if (aot) {
528                 char *icall_name = g_strdup_printf ("trampoline_func_%d", tramp_type);
529                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
530         } else {
531                 tramp = (guint8*)mono_get_trampoline_func (tramp_type);
532                 amd64_mov_reg_imm (code, AMD64_R11, tramp);
533         }
534         amd64_call_reg (code, AMD64_R11);
535
536         /* Check for thread interruption */
537         /* This is not perf critical code so no need to check the interrupt flag */
538         /* 
539          * Have to call the _force_ variant, since there could be a protected wrapper on the top of the stack.
540          */
541         amd64_mov_membase_reg (code, AMD64_RBP, res_offset, AMD64_RAX, 8);
542         if (aot) {
543                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint");
544         } else {
545                 amd64_mov_reg_imm (code, AMD64_R11, (guint8*)mono_thread_force_interruption_checkpoint);
546         }
547         amd64_call_reg (code, AMD64_R11);
548
549         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RBP, res_offset, 8);      
550
551         /* Restore LMF */
552
553         amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 8);
554         amd64_alu_reg_imm_size (code, X86_SUB, AMD64_RCX, 1, 8);
555         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 8);
556         amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, 8);
557
558         /* 
559          * Save rax to the stack, after the leave instruction, this will become part of
560          * the red zone.
561          */
562         amd64_mov_membase_reg (code, AMD64_RBP, rax_offset, AMD64_RAX, 8);
563
564         /* Restore argument registers, r10 (imt method/rgxtx)
565            and rax (needed for direct calls to C vararg functions). */
566         for (i = 0; i < AMD64_NREG; ++i)
567                 if (AMD64_IS_ARGUMENT_REG (i) || i == AMD64_R10 || i == AMD64_RAX)
568                         amd64_mov_reg_membase (code, i, AMD64_RBP, saved_regs_offset + (i * 8), 8);
569
570         for (i = 0; i < 8; ++i)
571                 amd64_movsd_reg_membase (code, i, AMD64_RBP, saved_fpregs_offset + (i * 8));
572
573         /* Restore stack */
574         amd64_leave (code);
575
576         if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
577                 /* Load result */
578                 amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, rax_offset - 0x8, 8);
579                 amd64_ret (code);
580         } else {
581                 /* call the compiled method using the saved rax */
582                 amd64_jump_membase (code, AMD64_RSP, rax_offset - 0x8);
583         }
584
585         g_assert ((code - buf) <= buf_len);
586
587         mono_arch_flush_icache (buf, code - buf);
588
589         if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
590                 /* Initialize the nullified class init trampoline used in the AOT case */
591                 nullified_class_init_trampoline = mono_arch_get_nullified_class_init_trampoline (NULL);
592         }
593
594         if (info)
595                 *info = mono_tramp_info_create (mono_get_generic_trampoline_name (tramp_type), buf, code - buf, ji, unwind_ops);
596
597         return buf;
598 }
599
600 gpointer
601 mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
602 {
603         guint8 *code, *buf;
604
605         code = buf = mono_global_codeman_reserve (16);
606         amd64_ret (code);
607
608         mono_arch_flush_icache (buf, code - buf);
609
610         if (info)
611                 *info = mono_tramp_info_create (g_strdup_printf ("nullified_class_init_trampoline"), buf, code - buf, NULL, NULL);
612
613         if (mono_jit_map_is_enabled ())
614                 mono_emit_jit_tramp (buf, code - buf, "nullified_class_init_trampoline");
615
616         return buf;
617 }
618
619 gpointer
620 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
621 {
622         guint8 *code, *buf, *tramp;
623         int size;
624
625         tramp = mono_get_trampoline_code (tramp_type);
626
627         if ((((guint64)arg1) >> 32) == 0)
628                 size = 5 + 1 + 4;
629         else
630                 size = 5 + 1 + 8;
631
632         code = buf = mono_domain_code_reserve_align (domain, size, 1);
633
634         amd64_call_code (code, tramp);
635         /* The trampoline code will obtain the argument from the instruction stream */
636         if ((((guint64)arg1) >> 32) == 0) {
637                 *code = 0x4;
638                 *(guint32*)(code + 1) = (gint64)arg1;
639                 code += 5;
640         } else {
641                 *code = 0x8;
642                 *(guint64*)(code + 1) = (gint64)arg1;
643                 code += 9;
644         }
645
646         g_assert ((code - buf) <= size);
647
648         if (code_len)
649                 *code_len = size;
650
651         mono_arch_flush_icache (buf, size);
652
653         return buf;
654 }       
655
656 gpointer
657 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
658 {
659         guint8 *tramp;
660         guint8 *code, *buf;
661         guint8 **rgctx_null_jumps;
662         int tramp_size;
663         int depth, index;
664         int i;
665         gboolean mrgctx;
666         MonoJumpInfo *ji = NULL;
667         GSList *unwind_ops = NULL;
668
669         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
670         index = MONO_RGCTX_SLOT_INDEX (slot);
671         if (mrgctx)
672                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
673         for (depth = 0; ; ++depth) {
674                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
675
676                 if (index < size - 1)
677                         break;
678                 index -= size - 1;
679         }
680
681         tramp_size = 64 + 8 * depth;
682
683         code = buf = mono_global_codeman_reserve (tramp_size);
684
685         unwind_ops = mono_arch_get_cie_program ();
686
687         rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
688
689         if (mrgctx) {
690                 /* get mrgctx ptr */
691                 amd64_mov_reg_reg (code, AMD64_RAX, AMD64_ARG_REG1, 8);
692         } else {
693                 /* load rgctx ptr from vtable */
694                 amd64_mov_reg_membase (code, AMD64_RAX, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context), 8);
695                 /* is the rgctx ptr null? */
696                 amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
697                 /* if yes, jump to actual trampoline */
698                 rgctx_null_jumps [0] = code;
699                 amd64_branch8 (code, X86_CC_Z, -1, 1);
700         }
701
702         for (i = 0; i < depth; ++i) {
703                 /* load ptr to next array */
704                 if (mrgctx && i == 0)
705                         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT, 8);
706                 else
707                         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, 0, 8);
708                 /* is the ptr null? */
709                 amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
710                 /* if yes, jump to actual trampoline */
711                 rgctx_null_jumps [i + 1] = code;
712                 amd64_branch8 (code, X86_CC_Z, -1, 1);
713         }
714
715         /* fetch slot */
716         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, sizeof (gpointer) * (index + 1), 8);
717         /* is the slot null? */
718         amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
719         /* if yes, jump to actual trampoline */
720         rgctx_null_jumps [depth + 1] = code;
721         amd64_branch8 (code, X86_CC_Z, -1, 1);
722         /* otherwise return */
723         amd64_ret (code);
724
725         for (i = mrgctx ? 1 : 0; i <= depth + 1; ++i)
726                 x86_patch (rgctx_null_jumps [i], code);
727
728         g_free (rgctx_null_jumps);
729
730         /* move the rgctx pointer to the VTABLE register */
731         amd64_mov_reg_reg (code, MONO_ARCH_VTABLE_REG, AMD64_ARG_REG1, 8);
732
733         if (aot) {
734                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot));
735                 amd64_jump_reg (code, AMD64_R11);
736         } else {
737                 tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
738
739                 /* jump to the actual trampoline */
740                 amd64_jump_code (code, tramp);
741         }
742
743         mono_arch_flush_icache (buf, code - buf);
744
745         g_assert (code - buf <= tramp_size);
746
747         if (info)
748                 *info = mono_tramp_info_create (mono_get_rgctx_fetch_trampoline_name (slot), buf, code - buf, ji, unwind_ops);
749
750         return buf;
751 }
752
753 gpointer
754 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot)
755 {
756         guint8 *tramp;
757         guint8 *code, *buf;
758         static int byte_offset = -1;
759         static guint8 bitmask;
760         guint8 *jump;
761         int tramp_size;
762         GSList *unwind_ops = NULL;
763         MonoJumpInfo *ji = NULL;
764
765         tramp_size = 64;
766
767         code = buf = mono_global_codeman_reserve (tramp_size);
768
769         if (byte_offset < 0)
770                 mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
771
772         amd64_test_membase_imm_size (code, MONO_AMD64_ARG_REG1, byte_offset, bitmask, 1);
773         jump = code;
774         amd64_branch8 (code, X86_CC_Z, -1, 1);
775
776         amd64_ret (code);
777
778         x86_patch (jump, code);
779
780         if (aot) {
781                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_generic_class_init");
782                 amd64_jump_reg (code, AMD64_R11);
783         } else {
784                 tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_GENERIC_CLASS_INIT, mono_get_root_domain (), NULL);
785
786                 /* jump to the actual trampoline */
787                 amd64_jump_code (code, tramp);
788         }
789
790         mono_arch_flush_icache (buf, code - buf);
791
792         g_assert (code - buf <= tramp_size);
793
794         if (info)
795                 *info = mono_tramp_info_create (g_strdup_printf ("generic_class_init_trampoline"), buf, code - buf, ji, unwind_ops);
796
797         return buf;
798 }
799
800 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
801
802 gpointer
803 mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot)
804 {
805         guint8 *tramp;
806         guint8 *code, *buf;
807         guint8 *jump_obj_null, *jump_sync_null, *jump_cmpxchg_failed, *jump_other_owner, *jump_tid;
808         int tramp_size;
809         int owner_offset, nest_offset, dummy;
810         MonoJumpInfo *ji = NULL;
811         GSList *unwind_ops = NULL;
812
813         g_assert (MONO_ARCH_MONITOR_OBJECT_REG == AMD64_RDI);
814
815         mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &dummy);
816         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer));
817         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
818         owner_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (owner_offset);
819         nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
820
821         tramp_size = 96;
822
823         code = buf = mono_global_codeman_reserve (tramp_size);
824
825         unwind_ops = mono_arch_get_cie_program ();
826
827         if (mono_thread_get_tls_offset () != -1) {
828                 /* MonoObject* obj is in RDI */
829                 /* is obj null? */
830                 amd64_test_reg_reg (code, AMD64_RDI, AMD64_RDI);
831                 /* if yes, jump to actual trampoline */
832                 jump_obj_null = code;
833                 amd64_branch8 (code, X86_CC_Z, -1, 1);
834
835                 /* load obj->synchronization to RCX */
836                 amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RDI, G_STRUCT_OFFSET (MonoObject, synchronisation), 8);
837                 /* is synchronization null? */
838                 amd64_test_reg_reg (code, AMD64_RCX, AMD64_RCX);
839                 /* if yes, jump to actual trampoline */
840                 jump_sync_null = code;
841                 amd64_branch8 (code, X86_CC_Z, -1, 1);
842
843                 /* load MonoInternalThread* into RDX */
844                 code = mono_amd64_emit_tls_get (code, AMD64_RDX, mono_thread_get_tls_offset ());
845                 /* load TID into RDX */
846                 amd64_mov_reg_membase (code, AMD64_RDX, AMD64_RDX, G_STRUCT_OFFSET (MonoInternalThread, tid), 8);
847
848                 /* is synchronization->owner null? */
849                 amd64_alu_membase_imm_size (code, X86_CMP, AMD64_RCX, owner_offset, 0, 8);
850                 /* if not, jump to next case */
851                 jump_tid = code;
852                 amd64_branch8 (code, X86_CC_NZ, -1, 1);
853
854                 /* if yes, try a compare-exchange with the TID */
855                 /* zero RAX */
856                 amd64_alu_reg_reg (code, X86_XOR, AMD64_RAX, AMD64_RAX);
857                 /* compare and exchange */
858                 amd64_prefix (code, X86_LOCK_PREFIX);
859                 amd64_cmpxchg_membase_reg_size (code, AMD64_RCX, owner_offset, AMD64_RDX, 8);
860                 /* if not successful, jump to actual trampoline */
861                 jump_cmpxchg_failed = code;
862                 amd64_branch8 (code, X86_CC_NZ, -1, 1);
863                 /* if successful, return */
864                 amd64_ret (code);
865
866                 /* next case: synchronization->owner is not null */
867                 x86_patch (jump_tid, code);
868                 /* is synchronization->owner == TID? */
869                 amd64_alu_membase_reg_size (code, X86_CMP, AMD64_RCX, owner_offset, AMD64_RDX, 8);
870                 /* if not, jump to actual trampoline */
871                 jump_other_owner = code;
872                 amd64_branch8 (code, X86_CC_NZ, -1, 1);
873                 /* if yes, increment nest */
874                 amd64_inc_membase_size (code, AMD64_RCX, nest_offset, 4);
875                 /* return */
876                 amd64_ret (code);
877
878                 x86_patch (jump_obj_null, code);
879                 x86_patch (jump_sync_null, code);
880                 x86_patch (jump_cmpxchg_failed, code);
881                 x86_patch (jump_other_owner, code);
882         }
883
884         /* jump to the actual trampoline */
885 #if MONO_AMD64_ARG_REG1 != AMD64_RDI
886         amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RDI);
887 #endif
888
889         if (aot) {
890                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_monitor_enter");
891                 amd64_jump_reg (code, AMD64_R11);
892         } else {
893                 tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_ENTER, mono_get_root_domain (), NULL);
894
895                 /* jump to the actual trampoline */
896                 amd64_jump_code (code, tramp);
897         }
898
899         mono_arch_flush_icache (code, code - buf);
900         g_assert (code - buf <= tramp_size);
901
902         if (info)
903                 *info = mono_tramp_info_create (g_strdup_printf ("monitor_enter_trampoline"), buf, code - buf, ji, unwind_ops);
904
905         return buf;
906 }
907
908 gpointer
909 mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
910 {
911         guint8 *tramp;
912         guint8 *code, *buf;
913         guint8 *jump_obj_null, *jump_have_waiters, *jump_sync_null, *jump_not_owned;
914         guint8 *jump_next;
915         int tramp_size;
916         int owner_offset, nest_offset, entry_count_offset;
917         MonoJumpInfo *ji = NULL;
918         GSList *unwind_ops = NULL;
919
920         g_assert (MONO_ARCH_MONITOR_OBJECT_REG == AMD64_RDI);
921
922         mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &entry_count_offset);
923         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer));
924         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
925         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (entry_count_offset) == sizeof (gint32));
926         owner_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (owner_offset);
927         nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
928         entry_count_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (entry_count_offset);
929
930         tramp_size = 94;
931
932         code = buf = mono_global_codeman_reserve (tramp_size);
933
934         unwind_ops = mono_arch_get_cie_program ();
935
936         if (mono_thread_get_tls_offset () != -1) {
937                 /* MonoObject* obj is in RDI */
938                 /* is obj null? */
939                 amd64_test_reg_reg (code, AMD64_RDI, AMD64_RDI);
940                 /* if yes, jump to actual trampoline */
941                 jump_obj_null = code;
942                 amd64_branch8 (code, X86_CC_Z, -1, 1);
943
944                 /* load obj->synchronization to RCX */
945                 amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RDI, G_STRUCT_OFFSET (MonoObject, synchronisation), 8);
946                 /* is synchronization null? */
947                 amd64_test_reg_reg (code, AMD64_RCX, AMD64_RCX);
948                 /* if yes, jump to actual trampoline */
949                 jump_sync_null = code;
950                 amd64_branch8 (code, X86_CC_Z, -1, 1);
951
952                 /* next case: synchronization is not null */
953                 /* load MonoInternalThread* into RDX */
954                 code = mono_amd64_emit_tls_get (code, AMD64_RDX, mono_thread_get_tls_offset ());
955                 /* load TID into RDX */
956                 amd64_mov_reg_membase (code, AMD64_RDX, AMD64_RDX, G_STRUCT_OFFSET (MonoInternalThread, tid), 8);
957                 /* is synchronization->owner == TID */
958                 amd64_alu_membase_reg_size (code, X86_CMP, AMD64_RCX, owner_offset, AMD64_RDX, 8);
959                 /* if no, jump to actual trampoline */
960                 jump_not_owned = code;
961                 amd64_branch8 (code, X86_CC_NZ, -1, 1);
962
963                 /* next case: synchronization->owner == TID */
964                 /* is synchronization->nest == 1 */
965                 amd64_alu_membase_imm_size (code, X86_CMP, AMD64_RCX, nest_offset, 1, 4);
966                 /* if not, jump to next case */
967                 jump_next = code;
968                 amd64_branch8 (code, X86_CC_NZ, -1, 1);
969                 /* if yes, is synchronization->entry_count zero? */
970                 amd64_alu_membase_imm_size (code, X86_CMP, AMD64_RCX, entry_count_offset, 0, 4);
971                 /* if not, jump to actual trampoline */
972                 jump_have_waiters = code;
973                 amd64_branch8 (code, X86_CC_NZ, -1 , 1);
974                 /* if yes, set synchronization->owner to null and return */
975                 amd64_mov_membase_imm (code, AMD64_RCX, owner_offset, 0, 8);
976                 amd64_ret (code);
977
978                 /* next case: synchronization->nest is not 1 */
979                 x86_patch (jump_next, code);
980                 /* decrease synchronization->nest and return */
981                 amd64_dec_membase_size (code, AMD64_RCX, nest_offset, 4);
982                 amd64_ret (code);
983
984                 x86_patch (jump_obj_null, code);
985                 x86_patch (jump_have_waiters, code);
986                 x86_patch (jump_not_owned, code);
987                 x86_patch (jump_sync_null, code);
988         }
989
990         /* jump to the actual trampoline */
991 #if MONO_AMD64_ARG_REG1 != AMD64_RDI
992         amd64_mov_reg_reg (code, MONO_AMD64_ARG_REG1, AMD64_RDI);
993 #endif
994
995         if (aot) {
996                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "specific_trampoline_monitor_exit");
997                 amd64_jump_reg (code, AMD64_R11);
998         } else {
999                 tramp = mono_arch_create_specific_trampoline (NULL, MONO_TRAMPOLINE_MONITOR_EXIT, mono_get_root_domain (), NULL);
1000                 amd64_jump_code (code, tramp);
1001         }
1002
1003         mono_arch_flush_icache (code, code - buf);
1004         g_assert (code - buf <= tramp_size);
1005
1006         if (info)
1007                 *info = mono_tramp_info_create (g_strdup_printf ("monitor_exit_trampoline"), buf, code - buf, ji, unwind_ops);
1008
1009         return buf;
1010 }
1011 #endif
1012
1013 void
1014 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
1015 {
1016         /* FIXME: This is not thread safe */
1017         guint8 *code = ji->code_start;
1018
1019         amd64_mov_reg_imm (code, AMD64_ARG_REG1, func_arg);
1020         amd64_mov_reg_imm (code, AMD64_R11, func);
1021
1022         x86_push_imm (code, (guint64)func_arg);
1023         amd64_call_reg (code, AMD64_R11);
1024 }
1025
1026 /*
1027  * mono_arch_get_call_target:
1028  *
1029  *   Return the address called by the code before CODE if exists.
1030  */
1031 guint8*
1032 mono_arch_get_call_target (guint8 *code)
1033 {
1034         if (code [-5] == 0xe8) {
1035                 guint32 disp = *(guint32*)(code - 4);
1036                 guint8 *target = code + disp;
1037
1038                 return target;
1039         } else {
1040                 return NULL;
1041         }
1042 }
1043
1044 /*
1045  * mono_arch_get_plt_info_offset:
1046  *
1047  *   Return the PLT info offset belonging to the plt entry PLT_ENTRY.
1048  */
1049 guint32
1050 mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code)
1051 {
1052         return *(guint32*)(plt_entry + 6);
1053 }