[System] Fixes UdpClient.Receive with IPv6 endpoint
[mono.git] / mono / mini / tramp-x86.c
1 /*
2  * tramp-x86.c: JIT trampoline code for x86
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12
13 #include <mono/metadata/abi-details.h>
14 #include <mono/metadata/appdomain.h>
15 #include <mono/metadata/metadata-internals.h>
16 #include <mono/metadata/marshal.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/mono-debug.h>
19 #include <mono/metadata/mono-debug-debugger.h>
20 #include <mono/metadata/profiler-private.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/arch/x86/x86-codegen.h>
23
24 #include <mono/utils/memcheck.h>
25
26 #include "mini.h"
27 #include "mini-x86.h"
28 #include "debugger-agent.h"
29
30 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
31
32 /*
33  * mono_arch_get_unbox_trampoline:
34  * @m: method pointer
35  * @addr: pointer to native code for @m
36  *
37  * when value type methods are called through the vtable we need to unbox the
38  * this argument. This method returns a pointer to a trampoline which does
39  * unboxing before calling the method
40  */
41 gpointer
42 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
43 {
44         guint8 *code, *start;
45         int this_pos = 4, size = NACL_SIZE(16, 32);
46         MonoDomain *domain = mono_domain_get ();
47         GSList *unwind_ops;
48
49         start = code = mono_domain_code_reserve (domain, size);
50
51         unwind_ops = mono_arch_get_cie_program ();
52
53         x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
54         x86_jump_code (code, addr);
55         g_assert ((code - start) < size);
56
57         nacl_domain_code_validate (domain, &start, size, &code);
58         mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m);
59
60         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
61
62         return start;
63 }
64
65 gpointer
66 mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
67 {
68         guint8 *code, *start;
69         int buf_len;
70         GSList *unwind_ops;
71
72         MonoDomain *domain = mono_domain_get ();
73
74         buf_len = NACL_SIZE (10, 32);
75
76         start = code = mono_domain_code_reserve (domain, buf_len);
77
78         unwind_ops = mono_arch_get_cie_program ();
79
80         x86_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
81         x86_jump_code (code, addr);
82         g_assert ((code - start) <= buf_len);
83
84         nacl_domain_code_validate (domain, &start, buf_len, &code);
85         mono_arch_flush_icache (start, code - start);
86         mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
87
88         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
89
90         return start;
91 }
92
93 gpointer
94 mono_arch_get_llvm_imt_trampoline (MonoDomain *domain, MonoMethod *m, int vt_offset)
95 {
96         guint8 *code, *start;
97         int buf_len;
98         int this_offset;
99
100         buf_len = 32;
101
102         start = code = mono_domain_code_reserve (domain, buf_len);
103
104         this_offset = mono_x86_get_this_arg_offset (mono_method_signature (m));
105
106         /* Set imt arg */
107         x86_mov_reg_imm (code, MONO_ARCH_IMT_REG, m);
108         /* Load this */
109         x86_mov_reg_membase (code, X86_EAX, X86_ESP, this_offset + 4, 4);
110         /* Load vtable address */
111         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
112         x86_jump_membase (code, X86_EAX, vt_offset);
113
114         g_assert ((code - start) < buf_len);
115
116         nacl_domain_code_validate (domain, &start, buf_len, &code);
117
118         mono_arch_flush_icache (start, code - start);
119         mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
120
121         return start;
122 }
123
124 void
125 mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
126 {
127 #if defined(__default_codegen__)
128         guint8 *code;
129         guint8 buf [8];
130         gboolean can_write = mono_breakpoint_clean_code (method_start, orig_code, 8, buf, sizeof (buf));
131
132         code = buf + 8;
133
134         /* go to the start of the call instruction
135          *
136          * address_byte = (m << 6) | (o << 3) | reg
137          * call opcode: 0xff address_byte displacement
138          * 0xff m=1,o=2 imm8
139          * 0xff m=2,o=2 imm32
140          */
141         code -= 6;
142         orig_code -= 6;
143         if (code [1] == 0xe8) {
144                 if (can_write) {
145                         InterlockedExchange ((gint32*)(orig_code + 2), (guint)addr - ((guint)orig_code + 1) - 5);
146
147                         /* Tell valgrind to recompile the patched code */
148                         VALGRIND_DISCARD_TRANSLATIONS (orig_code + 2, 4);
149                 }
150         } else if (code [1] == 0xe9) {
151                 /* A PLT entry: jmp <DISP> */
152                 if (can_write)
153                         InterlockedExchange ((gint32*)(orig_code + 2), (guint)addr - ((guint)orig_code + 1) - 5);
154         } else {
155                 printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", code [0], code [1], code [2], code [3],
156                                 code [4], code [5], code [6]);
157                 g_assert_not_reached ();
158         }
159 #elif defined(__native_client__)
160         /* Target must be bundle-aligned */
161         g_assert (((guint32)addr & kNaClAlignmentMask) == 0);
162
163         /* 0xe8 = call <DISP>, 0xe9 = jump <DISP> */
164         if ((orig_code [-5] == 0xe8) || orig_code [-6] == 0xe9) {
165                 int ret;
166                 gint32 offset = (gint32)addr - (gint32)orig_code;
167                 guint8 buf[sizeof(gint32)];
168                 *((gint32*)(buf)) = offset;
169                 ret = nacl_dyncode_modify (orig_code - sizeof(gint32), buf, sizeof(gint32));
170                 g_assert (ret == 0);
171         } else {
172                 printf ("Invalid trampoline sequence %p: %02x %02x %02x %02x %02x\n", orig_code, orig_code [-5], orig_code [-4], orig_code [-3], orig_code [-2], orig_code[-1]);
173                 g_assert_not_reached ();
174         }
175 #endif
176 }
177
178 void
179 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
180 {
181         guint32 offset;
182
183         /* Patch the jump table entry used by the plt entry */
184
185 #if defined(__native_client_codegen__) || defined(__native_client__)
186         /* for both compiler and runtime      */
187         /* A PLT entry:                       */
188         /*        mov <DISP>(%ebx), %ecx      */
189         /*        and 0xffffffe0, %ecx        */
190         /*        jmp *%ecx                   */
191         g_assert (code [0] == 0x8b);
192         g_assert (code [1] == 0x8b);
193
194         offset = *(guint32*)(code + 2);
195 #elif defined(__default_codegen__)
196         /* A PLT entry: jmp *<DISP>(%ebx) */
197         g_assert (code [0] == 0xff);
198         g_assert (code [1] == 0xa3);
199
200         offset = *(guint32*)(code + 2);
201 #endif  /* __native_client_codegen__ */
202         if (!got)
203                 got = (gpointer*)(gsize) regs [MONO_ARCH_GOT_REG];
204         *(guint8**)((guint8*)got + offset) = addr;
205 }
206
207 static gpointer
208 get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
209 {
210         const int kBufSize = NACL_SIZE (8, 16);
211         guint8 buf [64];
212         guint8 reg = 0;
213         gint32 disp = 0;
214
215         mono_breakpoint_clean_code (NULL, code, kBufSize, buf, kBufSize);
216         code = buf + 8;
217
218         *displacement = 0;
219
220         if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
221                 reg = code [1] & 0x07;
222                 disp = *((gint32*)(code + 2));
223 #if defined(__native_client_codegen__) || defined(__native_client__)
224         } else if ((code[1] == 0x83) && (code[2] == 0xe1) && (code[4] == 0xff) &&
225                            (code[5] == 0xd1) && (code[-5] == 0x8b)) {
226                 disp = *((gint32*)(code - 3));
227                 reg = code[-4] & 0x07;
228         } else if ((code[-2] == 0x8b) && (code[1] == 0x83) && (code[4] == 0xff)) {
229                 reg = code[-1] & 0x07;
230                 disp = (signed char)code[0];
231 #endif
232         } else {
233                 g_assert_not_reached ();
234                 return NULL;
235         }
236
237         *displacement = disp;
238         return (gpointer)regs [reg];
239 }
240
241 static gpointer*
242 get_vcall_slot_addr (guint8* code, mgreg_t *regs)
243 {
244         gpointer vt;
245         int displacement;
246         vt = get_vcall_slot (code, regs, &displacement);
247         if (!vt)
248                 return NULL;
249         return (gpointer*)((char*)vt + displacement);
250 }
251
252 guchar*
253 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
254 {
255         char *tramp_name;
256         guint8 *buf, *code, *tramp;
257         GSList *unwind_ops = NULL;
258         MonoJumpInfo *ji = NULL;
259         int i, offset, frame_size, regarray_offset, lmf_offset, caller_ip_offset, arg_offset;
260         int cfa_offset; /* cfa = cfa_reg + cfa_offset */
261
262         code = buf = mono_global_codeman_reserve (256);
263
264         /* Note that there is a single argument to the trampoline
265          * and it is stored at: esp + pushed_args * sizeof (gpointer)
266          * the ret address is at: esp + (pushed_args + 1) * sizeof (gpointer)
267          */
268
269         /* Compute frame offsets relative to the frame pointer %ebp */
270         arg_offset = sizeof (mgreg_t);
271         caller_ip_offset = 2 * sizeof (mgreg_t);
272         offset = 0;
273         offset += sizeof (MonoLMF);
274         lmf_offset = -offset;
275         offset += X86_NREG * sizeof (mgreg_t);
276         regarray_offset = -offset;
277         /* Argument area */
278         offset += 4 * sizeof (mgreg_t);
279         frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
280
281         /* ret addr and arg are on the stack */
282         cfa_offset = 2 * sizeof (mgreg_t);
283         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
284         // IP saved at CFA - 4
285         mono_add_unwind_op_offset (unwind_ops, code, buf, X86_NREG, -4);
286
287         /* Allocate frame */
288         x86_push_reg (code, X86_EBP);
289         cfa_offset += sizeof (mgreg_t);
290         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
291         mono_add_unwind_op_offset (unwind_ops, code, buf, X86_EBP, -cfa_offset);
292
293         x86_mov_reg_reg (code, X86_EBP, X86_ESP, sizeof (mgreg_t));
294         mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, X86_EBP);
295
296         /* There are three words on the stack, adding + 4 aligns the stack to 16, which is needed on osx */
297         x86_alu_reg_imm (code, X86_SUB, X86_ESP, frame_size + sizeof (mgreg_t));
298
299         /* Save all registers */
300         for (i = X86_EAX; i <= X86_EDI; ++i) {
301                 int reg = i;
302
303                 if (i == X86_EBP) {
304                         /* Save original ebp */
305                         /* EAX is already saved */
306                         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 0, sizeof (mgreg_t));
307                         reg = X86_EAX;
308                 } else if (i == X86_ESP) {
309                         /* Save original esp */
310                         /* EAX is already saved */
311                         x86_mov_reg_reg (code, X86_EAX, X86_EBP, sizeof (mgreg_t));
312                         /* Saved ebp + trampoline arg + return addr */
313                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, 3 * sizeof (mgreg_t));
314                         reg = X86_EAX;
315                 }
316                 x86_mov_membase_reg (code, X86_EBP, regarray_offset + (i * sizeof (mgreg_t)), reg, sizeof (mgreg_t));
317         }
318
319         /* Setup LMF */
320         /* eip */
321         if (tramp_type == MONO_TRAMPOLINE_JUMP) {
322                 x86_mov_membase_imm (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), 0, sizeof (mgreg_t));
323         } else {
324                 x86_mov_reg_membase (code, X86_EAX, X86_EBP, caller_ip_offset, sizeof (mgreg_t));
325                 x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), X86_EAX, sizeof (mgreg_t));
326         }
327         /* method */
328         if ((tramp_type == MONO_TRAMPOLINE_JIT) || (tramp_type == MONO_TRAMPOLINE_JUMP)) {
329                 x86_mov_reg_membase (code, X86_EAX, X86_EBP, arg_offset, sizeof (mgreg_t));
330                 x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), X86_EAX, sizeof (mgreg_t));
331         } else {
332                 x86_mov_membase_imm (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), 0, sizeof (mgreg_t));
333         }
334         /* esp */
335         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_ESP * sizeof (mgreg_t)), sizeof (mgreg_t));
336         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esp), X86_EAX, sizeof (mgreg_t));
337         /* callee save registers */
338         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EBX * sizeof (mgreg_t)), sizeof (mgreg_t));
339         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), X86_EAX, sizeof (mgreg_t));
340         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EDI * sizeof (mgreg_t)), sizeof (mgreg_t));
341         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), X86_EAX, sizeof (mgreg_t));
342         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_ESI * sizeof (mgreg_t)), sizeof (mgreg_t));
343         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), X86_EAX, sizeof (mgreg_t));
344         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EBP * sizeof (mgreg_t)), sizeof (mgreg_t));
345         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp), X86_EAX, sizeof (mgreg_t));
346
347         /* Push LMF */
348         /* get the address of lmf for the current thread */
349         if (aot) {
350                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr");
351                 x86_call_reg (code, X86_EAX);
352         } else {
353                 x86_call_code (code, mono_get_lmf_addr);
354         }
355         /* lmf->lmf_addr = lmf_addr (%eax) */
356         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), X86_EAX, sizeof (mgreg_t));
357         /* lmf->previous_lmf = *(lmf_addr) */
358         x86_mov_reg_membase (code, X86_ECX, X86_EAX, 0, sizeof (mgreg_t));
359         /* Signal to mono_arch_unwind_frame () that this is a trampoline frame */
360         x86_alu_reg_imm (code, X86_ADD, X86_ECX, 1);
361         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), X86_ECX, sizeof (mgreg_t));
362         /* *lmf_addr = lmf */
363         x86_lea_membase (code, X86_ECX, X86_EBP, lmf_offset);
364         x86_mov_membase_reg (code, X86_EAX, 0, X86_ECX, sizeof (mgreg_t));
365
366         /* Call trampoline function */
367         /* Arg 1 - registers */
368         x86_lea_membase (code, X86_EAX, X86_EBP, regarray_offset);
369         x86_mov_membase_reg (code, X86_ESP, (0 * sizeof (mgreg_t)), X86_EAX, sizeof (mgreg_t));
370         /* Arg2 - calling code */
371         if (tramp_type == MONO_TRAMPOLINE_JUMP) {
372                 x86_mov_membase_imm (code, X86_ESP, (1 * sizeof (mgreg_t)), 0, sizeof (mgreg_t));
373         } else {
374                 x86_mov_reg_membase (code, X86_EAX, X86_EBP, caller_ip_offset, sizeof (mgreg_t));
375                 x86_mov_membase_reg (code, X86_ESP, (1 * sizeof (mgreg_t)), X86_EAX, sizeof (mgreg_t));
376         }
377         /* Arg3 - trampoline argument */
378         x86_mov_reg_membase (code, X86_EAX, X86_EBP, arg_offset, sizeof (mgreg_t));
379         x86_mov_membase_reg (code, X86_ESP, (2 * sizeof (mgreg_t)), X86_EAX, sizeof (mgreg_t));
380         /* Arg4 - trampoline address */
381         // FIXME:
382         x86_mov_membase_imm (code, X86_ESP, (3 * sizeof (mgreg_t)), 0, sizeof (mgreg_t));
383
384 #ifdef __APPLE__
385         /* check the stack is aligned after the ret ip is pushed */
386         /*
387         x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
388         x86_alu_reg_imm (code, X86_AND, X86_EDX, 15);
389         x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
390         x86_branch_disp (code, X86_CC_Z, 3, FALSE);
391         x86_breakpoint (code);
392         */
393 #endif
394
395         if (aot) {
396                 char *icall_name = g_strdup_printf ("trampoline_func_%d", tramp_type);
397                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
398                 x86_call_reg (code, X86_EAX);
399         } else {
400                 tramp = (guint8*)mono_get_trampoline_func (tramp_type);
401                 x86_call_code (code, tramp);
402         }
403
404         /*
405          * Overwrite the trampoline argument with the address we need to jump to,
406          * to free %eax.
407          */
408         x86_mov_membase_reg (code, X86_EBP, arg_offset, X86_EAX, 4);
409
410         /* Check for interruptions */
411         if (aot) {
412                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint");
413                 x86_call_reg (code, X86_EAX);
414         } else {
415                 x86_call_code (code, (guint8*)mono_thread_force_interruption_checkpoint);
416         }
417
418         /* Restore LMF */
419         x86_mov_reg_membase (code, X86_EAX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof (mgreg_t));
420         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof (mgreg_t));
421         x86_alu_reg_imm (code, X86_SUB, X86_ECX, 1);
422         x86_mov_membase_reg (code, X86_EAX, 0, X86_ECX, sizeof (mgreg_t));
423
424         /* Restore registers */
425         for (i = X86_EAX; i <= X86_EDI; ++i) {
426                 if (i == X86_ESP || i == X86_EBP)
427                         continue;
428                 if (i == X86_EAX && !((tramp_type == MONO_TRAMPOLINE_RESTORE_STACK_PROT) || (tramp_type == MONO_TRAMPOLINE_AOT_PLT)))
429                         continue;
430                 x86_mov_reg_membase (code, i, X86_EBP, regarray_offset + (i * 4), 4);
431         }
432
433         /* Restore frame */
434         x86_leave (code);
435         cfa_offset -= sizeof (mgreg_t);
436         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
437         mono_add_unwind_op_same_value (unwind_ops, code, buf, X86_EBP);
438
439         if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
440                 /* Load the value returned by the trampoline */
441                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 0, 4);
442                 /* The trampoline returns normally, pop the trampoline argument */
443                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
444                 cfa_offset -= sizeof (mgreg_t);
445                 mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
446                 x86_ret (code);
447         } else {
448                 /* The trampoline argument is at the top of the stack, and it contains the address we need to branch to */
449                 if (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD) {
450                         x86_pop_reg (code, X86_EAX);
451                         cfa_offset -= sizeof (mgreg_t);
452                         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
453                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 0x8);
454                         x86_jump_reg (code, X86_EAX);
455                 } else {
456                         x86_ret (code);
457                 }
458         }
459
460         nacl_global_codeman_validate (&buf, 256, &code);
461         g_assert ((code - buf) <= 256);
462         mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
463
464         tramp_name = mono_get_generic_trampoline_name (tramp_type);
465         *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
466         g_free (tramp_name);
467
468         return buf;
469 }
470
471 #define TRAMPOLINE_SIZE 10
472
473 gpointer
474 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
475 {
476         guint8 *code, *buf, *tramp;
477         
478         tramp = mono_get_trampoline_code (tramp_type);
479
480         code = buf = mono_domain_code_reserve_align (domain, TRAMPOLINE_SIZE, NACL_SIZE (4, kNaClAlignment));
481
482         x86_push_imm (buf, arg1);
483         x86_jump_code (buf, tramp);
484         g_assert ((buf - code) <= TRAMPOLINE_SIZE);
485
486         nacl_domain_code_validate (domain, &code, NACL_SIZE (4, kNaClAlignment), &buf);
487
488         mono_arch_flush_icache (code, buf - code);
489         mono_profiler_code_buffer_new (code, buf - code, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type));
490
491         if (code_len)
492                 *code_len = buf - code;
493
494         return code;
495 }
496
497 gpointer
498 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
499 {
500         guint8 *tramp;
501         guint8 *code, *buf;
502         guint8 **rgctx_null_jumps;
503         int tramp_size;
504         int depth, index;
505         int i;
506         gboolean mrgctx;
507         MonoJumpInfo *ji = NULL;
508         GSList *unwind_ops = NULL;
509
510         unwind_ops = mono_arch_get_cie_program ();
511
512         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
513         index = MONO_RGCTX_SLOT_INDEX (slot);
514         if (mrgctx)
515                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
516         for (depth = 0; ; ++depth) {
517                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
518
519                 if (index < size - 1)
520                         break;
521                 index -= size - 1;
522         }
523
524 #if defined(__default_codegen__)
525         tramp_size = (aot ? 64 : 36) + 6 * depth;
526 #elif defined(__native_client_codegen__)
527         tramp_size = (aot ? 64 : 36) + 2 * kNaClAlignment +
528           6 * (depth + kNaClAlignment);
529 #endif
530
531         code = buf = mono_global_codeman_reserve (tramp_size);
532
533         rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
534
535         /* load vtable/mrgctx ptr */
536         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
537         if (!mrgctx) {
538                 /* load rgctx ptr from vtable */
539                 x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context), 4);
540                 /* is the rgctx ptr null? */
541                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
542                 /* if yes, jump to actual trampoline */
543                 rgctx_null_jumps [0] = code;
544                 x86_branch8 (code, X86_CC_Z, -1, 1);
545         }
546
547         for (i = 0; i < depth; ++i) {
548                 /* load ptr to next array */
549                 if (mrgctx && i == 0)
550                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT, 4);
551                 else
552                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
553                 /* is the ptr null? */
554                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
555                 /* if yes, jump to actual trampoline */
556                 rgctx_null_jumps [i + 1] = code;
557                 x86_branch8 (code, X86_CC_Z, -1, 1);
558         }
559
560         /* fetch slot */
561         x86_mov_reg_membase (code, X86_EAX, X86_EAX, sizeof (gpointer) * (index + 1), 4);
562         /* is the slot null? */
563         x86_test_reg_reg (code, X86_EAX, X86_EAX);
564         /* if yes, jump to actual trampoline */
565         rgctx_null_jumps [depth + 1] = code;
566         x86_branch8 (code, X86_CC_Z, -1, 1);
567         /* otherwise return */
568         x86_ret (code);
569
570         for (i = mrgctx ? 1 : 0; i <= depth + 1; ++i)
571                 x86_patch (rgctx_null_jumps [i], code);
572
573         g_free (rgctx_null_jumps);
574
575         x86_mov_reg_membase (code, MONO_ARCH_VTABLE_REG, X86_ESP, 4, 4);
576
577         if (aot) {
578                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot));
579                 x86_jump_reg (code, X86_EAX);
580         } else {
581                 tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
582
583                 /* jump to the actual trampoline */
584                 x86_jump_code (code, tramp);
585         }
586
587         nacl_global_codeman_validate (&buf, tramp_size, &code);
588         mono_arch_flush_icache (buf, code - buf);
589         mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
590
591         g_assert (code - buf <= tramp_size);
592
593         char *name = mono_get_rgctx_fetch_trampoline_name (slot);
594         *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
595         g_free (name);
596
597         return buf;
598 }
599
600 /*
601  * mono_arch_create_general_rgctx_lazy_fetch_trampoline:
602  *
603  *   This is a general variant of the rgctx fetch trampolines. It receives a pointer to gpointer[2] in the rgctx reg. The first entry contains the slot, the second
604  * the trampoline to call if the slot is not filled.
605  */
606 gpointer
607 mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot)
608 {
609         guint8 *code, *buf;
610         int tramp_size;
611         MonoJumpInfo *ji = NULL;
612         GSList *unwind_ops = NULL;
613
614         g_assert (aot);
615
616         unwind_ops = mono_arch_get_cie_program ();
617
618         tramp_size = 64;
619
620         code = buf = mono_global_codeman_reserve (tramp_size);
621
622         // FIXME: Currently, we always go to the slow path.
623         
624         /* Load trampoline addr */
625         x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_RGCTX_REG, 4, 4);
626         /* Load mrgctx/vtable */
627         x86_mov_reg_membase (code, MONO_ARCH_VTABLE_REG, X86_ESP, 4, 4);
628
629         x86_jump_reg (code, X86_EAX);
630
631         nacl_global_codeman_validate (&buf, tramp_size, &code);
632         mono_arch_flush_icache (buf, code - buf);
633         mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
634
635         g_assert (code - buf <= tramp_size);
636
637         *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops);
638
639         return buf;
640 }
641
642 void
643 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
644 {
645         /* FIXME: This is not thread safe */
646         guint8 *code = ji->code_start;
647
648         x86_push_imm (code, func_arg);
649         x86_call_code (code, (guint8*)func);
650 }
651
652 static gpointer
653 handler_block_trampoline_helper (void)
654 {
655         MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
656         return jit_tls->handler_block_return_address;
657 }
658
659 gpointer
660 mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
661 {
662         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
663         guint8 *code, *buf;
664         int tramp_size = 64;
665         MonoJumpInfo *ji = NULL;
666         int cfa_offset;
667         GSList *unwind_ops = NULL;
668
669         g_assert (!aot);
670
671         code = buf = mono_global_codeman_reserve (tramp_size);
672
673         unwind_ops = mono_arch_get_cie_program ();
674         cfa_offset = sizeof (mgreg_t);
675         /*
676         This trampoline restore the call chain of the handler block then jumps into the code that deals with it.
677         */
678
679         /*
680          * We are in a method frame after the call emitted by OP_CALL_HANDLER.
681          */
682
683         if (mono_get_jit_tls_offset () != -1) {
684                 code = mono_x86_emit_tls_get (code, X86_EAX, mono_get_jit_tls_offset ());
685                 x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (MonoJitTlsData, handler_block_return_address), 4);
686         } else {
687                 /*Slow path uses a c helper*/
688                 x86_call_code (code, handler_block_trampoline_helper);
689         }
690         /* Simulate a call */
691         /*Fix stack alignment*/
692         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x4);
693         cfa_offset += sizeof (mgreg_t);
694         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
695
696         /* This is the address the trampoline will return to */
697         x86_push_reg (code, X86_EAX);
698         cfa_offset += sizeof (mgreg_t);
699         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
700
701         /* Dummy trampoline argument, since we call the generic trampoline directly */
702         x86_push_imm (code, 0);
703         cfa_offset += sizeof (mgreg_t);
704         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
705         x86_jump_code (code, tramp);
706
707         nacl_global_codeman_validate (&buf, tramp_size, &code);
708
709         mono_arch_flush_icache (buf, code - buf);
710         mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL);
711         g_assert (code - buf <= tramp_size);
712
713         *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
714
715         return buf;
716 }
717
718 guint8*
719 mono_arch_get_call_target (guint8 *code)
720 {
721         if (code [-5] == 0xe8) {
722                 gint32 disp = *(gint32*)(code - 4);
723                 guint8 *target = code + disp;
724
725                 return target;
726         } else {
727                 return NULL;
728         }
729 }
730
731 guint32
732 mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code)
733 {
734         return *(guint32*)(plt_entry + NACL_SIZE (6, 12));
735 }
736
737 /*
738  * mono_arch_get_gsharedvt_arg_trampoline:
739  *
740  *   Return a trampoline which passes ARG to the gsharedvt in/out trampoline ADDR.
741  */
742 gpointer
743 mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
744 {
745         guint8 *code, *start;
746         int buf_len;
747         GSList *unwind_ops;
748
749
750         buf_len = 10;
751
752         start = code = mono_domain_code_reserve (domain, buf_len);
753
754         unwind_ops = mono_arch_get_cie_program ();
755
756         x86_mov_reg_imm (code, X86_EAX, arg);
757         x86_jump_code (code, addr);
758         g_assert ((code - start) <= buf_len);
759
760         nacl_domain_code_validate (domain, &start, buf_len, &code);
761         mono_arch_flush_icache (start, code - start);
762         mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL);
763
764         mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
765
766         return start;
767 }
768
769 /*
770  * mono_arch_create_sdb_trampoline:
771  *
772  *   Return a trampoline which captures the current context, passes it to
773  * debugger_agent_single_step_from_context ()/debugger_agent_breakpoint_from_context (),
774  * then restores the (potentially changed) context.
775  */
776 guint8*
777 mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot)
778 {
779         int tramp_size = 256;
780         int framesize, ctx_offset, cfa_offset;
781         guint8 *code, *buf;
782         GSList *unwind_ops = NULL;
783         MonoJumpInfo *ji = NULL;
784
785         code = buf = mono_global_codeman_reserve (tramp_size);
786
787         framesize = 0;
788
789         /* Argument area */
790         framesize += sizeof (mgreg_t);
791
792         ctx_offset = framesize;
793         framesize += sizeof (MonoContext);
794
795         framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT);
796
797         // CFA = sp + 4
798         cfa_offset = 4;
799         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, 4);
800         // IP saved at CFA - 4
801         mono_add_unwind_op_offset (unwind_ops, code, buf, X86_NREG, -cfa_offset);
802
803         x86_push_reg (code, X86_EBP);
804         cfa_offset += sizeof(mgreg_t);
805         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
806         mono_add_unwind_op_offset (unwind_ops, code, buf, X86_EBP, - cfa_offset);
807
808         x86_mov_reg_reg (code, X86_EBP, X86_ESP, sizeof(mgreg_t));
809         mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, X86_EBP);
810         /* The + 8 makes the stack aligned */
811         x86_alu_reg_imm (code, X86_SUB, X86_ESP, framesize + 8);
812
813         /* Initialize a MonoContext structure on the stack */
814         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eax), X86_EAX, sizeof (mgreg_t));
815         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebx), X86_EBX, sizeof (mgreg_t));
816         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ecx), X86_ECX, sizeof (mgreg_t));
817         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edx), X86_EDX, sizeof (mgreg_t));
818         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 0, sizeof (mgreg_t));
819         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebp), X86_EAX, sizeof (mgreg_t));
820         x86_mov_reg_reg (code, X86_EAX, X86_EBP, sizeof (mgreg_t));
821         x86_alu_reg_imm (code, X86_ADD, X86_EAX, cfa_offset);
822         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, esp), X86_ESP, sizeof (mgreg_t));
823         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, esi), X86_ESI, sizeof (mgreg_t));
824         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edi), X86_EDI, sizeof (mgreg_t));
825         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 4, sizeof (mgreg_t));
826         x86_mov_membase_reg (code, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eip), X86_EAX, sizeof (mgreg_t));
827
828         /* Call the single step/breakpoint function in sdb */
829         x86_lea_membase (code, X86_EAX, X86_ESP, ctx_offset);
830         x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, sizeof (mgreg_t));
831
832         if (aot) {
833                 x86_breakpoint (code);
834         } else {
835                 if (single_step)
836                         x86_call_code (code, debugger_agent_single_step_from_context);
837                 else
838                         x86_call_code (code, debugger_agent_breakpoint_from_context);
839         }
840
841         /* Restore registers from ctx */
842         /* Overwrite the saved ebp */
843         x86_mov_reg_membase (code, X86_EAX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebp), sizeof (mgreg_t));
844         x86_mov_membase_reg (code, X86_EBP, 0, X86_EAX, sizeof (mgreg_t));
845         /* Overwrite saved eip */
846         x86_mov_reg_membase (code, X86_EAX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eip), sizeof (mgreg_t));
847         x86_mov_membase_reg (code, X86_EBP, 4, X86_EAX, sizeof (mgreg_t));
848         x86_mov_reg_membase (code, X86_EAX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, eax), sizeof (mgreg_t));
849         x86_mov_reg_membase (code, X86_EBX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ebx), sizeof (mgreg_t));
850         x86_mov_reg_membase (code, X86_ECX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, ecx), sizeof (mgreg_t));
851         x86_mov_reg_membase (code, X86_EDX, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edx), sizeof (mgreg_t));
852         x86_mov_reg_membase (code, X86_ESI, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, esi), sizeof (mgreg_t));
853         x86_mov_reg_membase (code, X86_EDI, X86_ESP, ctx_offset + G_STRUCT_OFFSET (MonoContext, edi), sizeof (mgreg_t));
854
855         x86_leave (code);
856         cfa_offset -= sizeof (mgreg_t);
857         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, cfa_offset);
858         x86_ret (code);
859
860         mono_arch_flush_icache (code, code - buf);
861         g_assert (code - buf <= tramp_size);
862
863         const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline";
864         *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
865
866         return buf;
867 }
868
869 #if defined(ENABLE_GSHAREDVT)
870
871 #include "../../../mono-extensions/mono/mini/tramp-x86-gsharedvt.c"
872
873 #else
874
875 gpointer
876 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
877 {
878         *info = NULL;
879         return NULL;
880 }
881
882 #endif /* !MONOTOUCH */