Merge pull request #1304 from slluis/mac-proxy-autoconfig
[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/monitor.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
29 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
30
31 /*
32  * mono_arch_get_unbox_trampoline:
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 (MonoMethod *m, gpointer addr)
42 {
43         guint8 *code, *start;
44         int this_pos = 4, size = NACL_SIZE(16, 32);
45         MonoDomain *domain = mono_domain_get ();
46
47         start = code = mono_domain_code_reserve (domain, size);
48
49         x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
50         x86_jump_code (code, addr);
51         g_assert ((code - start) < size);
52
53         nacl_domain_code_validate (domain, &start, size, &code);
54
55         return start;
56 }
57
58 gpointer
59 mono_arch_get_static_rgctx_trampoline (MonoMethod *m, MonoMethodRuntimeGenericContext *mrgctx, gpointer addr)
60 {
61         guint8 *code, *start;
62         int buf_len;
63
64         MonoDomain *domain = mono_domain_get ();
65
66         buf_len = NACL_SIZE (10, 32);
67
68         start = code = mono_domain_code_reserve (domain, buf_len);
69
70         x86_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, mrgctx);
71         x86_jump_code (code, addr);
72         g_assert ((code - start) <= buf_len);
73
74         nacl_domain_code_validate (domain, &start, buf_len, &code);
75         mono_arch_flush_icache (start, code - start);
76
77         return start;
78 }
79
80 gpointer
81 mono_arch_get_llvm_imt_trampoline (MonoDomain *domain, MonoMethod *m, int vt_offset)
82 {
83         guint8 *code, *start;
84         int buf_len;
85         int this_offset;
86
87         buf_len = 32;
88
89         start = code = mono_domain_code_reserve (domain, buf_len);
90
91         this_offset = mono_x86_get_this_arg_offset (NULL, mono_method_signature (m));
92
93         /* Set imt arg */
94         x86_mov_reg_imm (code, MONO_ARCH_IMT_REG, m);
95         /* Load this */
96         x86_mov_reg_membase (code, X86_EAX, X86_ESP, this_offset + 4, 4);
97         /* Load vtable address */
98         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
99         x86_jump_membase (code, X86_EAX, vt_offset);
100
101         g_assert ((code - start) < buf_len);
102
103         nacl_domain_code_validate (domain, &start, buf_len, &code);
104
105         mono_arch_flush_icache (start, code - start);
106
107         return start;
108 }
109
110 void
111 mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
112 {
113 #if defined(__default_codegen__)
114         guint8 *code;
115         guint8 buf [8];
116         gboolean can_write = mono_breakpoint_clean_code (method_start, orig_code, 8, buf, sizeof (buf));
117
118         code = buf + 8;
119
120         /* go to the start of the call instruction
121          *
122          * address_byte = (m << 6) | (o << 3) | reg
123          * call opcode: 0xff address_byte displacement
124          * 0xff m=1,o=2 imm8
125          * 0xff m=2,o=2 imm32
126          */
127         code -= 6;
128         orig_code -= 6;
129         if (code [1] == 0xe8) {
130                 if (can_write) {
131                         InterlockedExchange ((gint32*)(orig_code + 2), (guint)addr - ((guint)orig_code + 1) - 5);
132
133                         /* Tell valgrind to recompile the patched code */
134                         VALGRIND_DISCARD_TRANSLATIONS (orig_code + 2, 4);
135                 }
136         } else if (code [1] == 0xe9) {
137                 /* A PLT entry: jmp <DISP> */
138                 if (can_write)
139                         InterlockedExchange ((gint32*)(orig_code + 2), (guint)addr - ((guint)orig_code + 1) - 5);
140         } else {
141                 printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", code [0], code [1], code [2], code [3],
142                                 code [4], code [5], code [6]);
143                 g_assert_not_reached ();
144         }
145 #elif defined(__native_client__)
146         /* Target must be bundle-aligned */
147         g_assert (((guint32)addr & kNaClAlignmentMask) == 0);
148
149         /* 0xe8 = call <DISP>, 0xe9 = jump <DISP> */
150         if ((orig_code [-5] == 0xe8) || orig_code [-6] == 0xe9) {
151                 int ret;
152                 gint32 offset = (gint32)addr - (gint32)orig_code;
153                 guint8 buf[sizeof(gint32)];
154                 *((gint32*)(buf)) = offset;
155                 ret = nacl_dyncode_modify (orig_code - sizeof(gint32), buf, sizeof(gint32));
156                 g_assert (ret == 0);
157         } else {
158                 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]);
159                 g_assert_not_reached ();
160         }
161 #endif
162 }
163
164 void
165 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
166 {
167         guint32 offset;
168
169         /* Patch the jump table entry used by the plt entry */
170
171 #if defined(__native_client_codegen__) || defined(__native_client__)
172         /* for both compiler and runtime      */
173         /* A PLT entry:                       */
174         /*        mov <DISP>(%ebx), %ecx      */
175         /*        and 0xffffffe0, %ecx        */
176         /*        jmp *%ecx                   */
177         g_assert (code [0] == 0x8b);
178         g_assert (code [1] == 0x8b);
179
180         offset = *(guint32*)(code + 2);
181 #elif defined(__default_codegen__)
182         /* A PLT entry: jmp *<DISP>(%ebx) */
183         g_assert (code [0] == 0xff);
184         g_assert (code [1] == 0xa3);
185
186         offset = *(guint32*)(code + 2);
187 #endif  /* __native_client_codegen__ */
188         if (!got)
189                 got = (gpointer*)(gsize) regs [MONO_ARCH_GOT_REG];
190         *(guint8**)((guint8*)got + offset) = addr;
191 }
192
193 static gpointer
194 get_vcall_slot (guint8 *code, mgreg_t *regs, int *displacement)
195 {
196         const int kBufSize = NACL_SIZE (8, 16);
197         guint8 buf [64];
198         guint8 reg = 0;
199         gint32 disp = 0;
200
201         mono_breakpoint_clean_code (NULL, code, kBufSize, buf, kBufSize);
202         code = buf + 8;
203
204         *displacement = 0;
205
206         if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
207                 reg = code [1] & 0x07;
208                 disp = *((gint32*)(code + 2));
209 #if defined(__native_client_codegen__) || defined(__native_client__)
210         } else if ((code[1] == 0x83) && (code[2] == 0xe1) && (code[4] == 0xff) &&
211                            (code[5] == 0xd1) && (code[-5] == 0x8b)) {
212                 disp = *((gint32*)(code - 3));
213                 reg = code[-4] & 0x07;
214         } else if ((code[-2] == 0x8b) && (code[1] == 0x83) && (code[4] == 0xff)) {
215                 reg = code[-1] & 0x07;
216                 disp = (signed char)code[0];
217 #endif
218         } else {
219                 g_assert_not_reached ();
220                 return NULL;
221         }
222
223         *displacement = disp;
224         return (gpointer)regs [reg];
225 }
226
227 static gpointer*
228 get_vcall_slot_addr (guint8* code, mgreg_t *regs)
229 {
230         gpointer vt;
231         int displacement;
232         vt = get_vcall_slot (code, regs, &displacement);
233         if (!vt)
234                 return NULL;
235         return (gpointer*)((char*)vt + displacement);
236 }
237
238 void
239 mono_arch_nullify_class_init_trampoline (guint8 *code, mgreg_t *regs)
240 {
241         guint8 buf [16];
242         gboolean can_write = mono_breakpoint_clean_code (NULL, code, 6, buf, sizeof (buf));
243         gpointer tramp = mini_get_nullified_class_init_trampoline ();
244
245         if (!can_write)
246                 return;
247
248         code -= 5;
249         if (code [0] == 0xe8) {
250 #if defined(__default_codegen__)
251                 if (!mono_running_on_valgrind ()) {
252                         guint32 ops;
253                         /*
254                          * Thread safe code patching using the algorithm from the paper
255                          * 'Practicing JUDO: Java Under Dynamic Optimizations'
256                          */
257                         /* 
258                          * First atomically change the the first 2 bytes of the call to a
259                          * spinning jump.
260                          */
261                         ops = 0xfeeb;
262                         InterlockedExchange ((gint32*)code, ops);
263
264                         /* Then change the other bytes to a nop */
265                         code [2] = 0x90;
266                         code [3] = 0x90;
267                         code [4] = 0x90;
268
269                         /* Then atomically change the first 4 bytes to a nop as well */
270                         ops = 0x90909090;
271                         InterlockedExchange ((gint32*)code, ops);
272                         /* FIXME: the calltree skin trips on the self modifying code above */
273
274                         /* Tell valgrind to recompile the patched code */
275                         //VALGRIND_DISCARD_TRANSLATIONS (code, 8);
276                 }
277 #elif defined(__native_client_codegen__)
278                 mono_arch_patch_callsite (code, code + 5, tramp);
279 #endif
280         } else if (code [0] == 0x90 || code [0] == 0xeb) {
281                 /* Already changed by another thread */
282                 ;
283         } else if ((code [-1] == 0xff) && (x86_modrm_reg (code [0]) == 0x2)) {
284                 /* call *<OFFSET>(<REG>) -> Call made from AOT code */
285                 gpointer *vtable_slot;
286
287                 vtable_slot = get_vcall_slot_addr (code + 5, regs);
288                 g_assert (vtable_slot);
289
290                 *vtable_slot = tramp;
291         } else {
292                         printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", code [0], code [1], code [2], code [3],
293                                 code [4], code [5], code [6]);
294                         g_assert_not_reached ();
295                 }
296 }
297
298 guchar*
299 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
300 {
301         char *tramp_name;
302         guint8 *buf, *code, *tramp;
303         GSList *unwind_ops = NULL;
304         MonoJumpInfo *ji = NULL;
305         int i, offset, frame_size, regarray_offset, lmf_offset, caller_ip_offset, arg_offset;
306
307         unwind_ops = mono_arch_get_cie_program ();
308
309         code = buf = mono_global_codeman_reserve (256);
310
311         /* Note that there is a single argument to the trampoline
312          * and it is stored at: esp + pushed_args * sizeof (gpointer)
313          * the ret address is at: esp + (pushed_args + 1) * sizeof (gpointer)
314          */
315
316         // FIXME: Unwind info
317
318         /* Compute frame offsets relative to the frame pointer %ebp */
319         arg_offset = sizeof (mgreg_t);
320         caller_ip_offset = 2 * sizeof (mgreg_t);
321         offset = 0;
322         offset += sizeof (MonoLMF);
323         lmf_offset = -offset;
324         offset += X86_NREG * sizeof (mgreg_t);
325         regarray_offset = -offset;
326         /* Argument area */
327         offset += 4 * sizeof (mgreg_t);
328         frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
329
330         /* Allocate frame */
331         x86_push_reg (code, X86_EBP);
332         x86_mov_reg_reg (code, X86_EBP, X86_ESP, sizeof (mgreg_t));
333         /* There are three words on the stack, adding + 4 aligns the stack to 16, which is needed on osx */
334         x86_alu_reg_imm (code, X86_SUB, X86_ESP, frame_size + sizeof (mgreg_t));
335
336         /* Save all registers */
337         for (i = X86_EAX; i <= X86_EDI; ++i) {
338                 int reg = i;
339
340                 if (i == X86_EBP) {
341                         /* Save original ebp */
342                         /* EAX is already saved */
343                         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 0, sizeof (mgreg_t));
344                         reg = X86_EAX;
345                 } else if (i == X86_ESP) {
346                         /* Save original esp */
347                         /* EAX is already saved */
348                         x86_mov_reg_reg (code, X86_EAX, X86_EBP, sizeof (mgreg_t));
349                         /* Saved ebp + trampoline arg + return addr */
350                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, 3 * sizeof (mgreg_t));
351                         reg = X86_EAX;
352                 }
353                 x86_mov_membase_reg (code, X86_EBP, regarray_offset + (i * sizeof (mgreg_t)), reg, sizeof (mgreg_t));
354         }
355
356         /* Setup LMF */
357         /* eip */
358         if (tramp_type == MONO_TRAMPOLINE_JUMP) {
359                 x86_mov_membase_imm (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), 0, sizeof (mgreg_t));
360         } else {
361                 x86_mov_reg_membase (code, X86_EAX, X86_EBP, caller_ip_offset, sizeof (mgreg_t));
362                 x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, eip), X86_EAX, sizeof (mgreg_t));
363         }
364         /* method */
365         if ((tramp_type == MONO_TRAMPOLINE_JIT) || (tramp_type == MONO_TRAMPOLINE_JUMP)) {
366                 x86_mov_reg_membase (code, X86_EAX, X86_EBP, arg_offset, sizeof (mgreg_t));
367                 x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), X86_EAX, sizeof (mgreg_t));
368         } else {
369                 x86_mov_membase_imm (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, method), 0, sizeof (mgreg_t));
370         }
371         /* esp */
372         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_ESP * sizeof (mgreg_t)), sizeof (mgreg_t));
373         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esp), X86_EAX, sizeof (mgreg_t));
374         /* callee save registers */
375         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EBX * sizeof (mgreg_t)), sizeof (mgreg_t));
376         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), X86_EAX, sizeof (mgreg_t));
377         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EDI * sizeof (mgreg_t)), sizeof (mgreg_t));
378         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), X86_EAX, sizeof (mgreg_t));
379         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_ESI * sizeof (mgreg_t)), sizeof (mgreg_t));
380         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), X86_EAX, sizeof (mgreg_t));
381         x86_mov_reg_membase (code, X86_EAX, X86_EBP, regarray_offset + (X86_EBP * sizeof (mgreg_t)), sizeof (mgreg_t));
382         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebp), X86_EAX, sizeof (mgreg_t));
383
384         /* Push LMF */
385         /* get the address of lmf for the current thread */
386         if (aot) {
387                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr");
388                 x86_call_reg (code, X86_EAX);
389         } else {
390                 x86_call_code (code, mono_get_lmf_addr);
391         }
392         /* lmf->lmf_addr = lmf_addr (%eax) */
393         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), X86_EAX, sizeof (mgreg_t));
394         /* lmf->previous_lmf = *(lmf_addr) */
395         x86_mov_reg_membase (code, X86_ECX, X86_EAX, 0, sizeof (mgreg_t));
396         /* Signal to mono_arch_find_jit_info () that this is a trampoline frame */
397         x86_alu_reg_imm (code, X86_ADD, X86_ECX, 1);
398         x86_mov_membase_reg (code, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), X86_ECX, sizeof (mgreg_t));
399         /* *lmf_addr = lmf */
400         x86_lea_membase (code, X86_ECX, X86_EBP, lmf_offset);
401         x86_mov_membase_reg (code, X86_EAX, 0, X86_ECX, sizeof (mgreg_t));
402
403         /* Call trampoline function */
404         /* Arg 1 - registers */
405         x86_lea_membase (code, X86_EAX, X86_EBP, regarray_offset);
406         x86_mov_membase_reg (code, X86_ESP, (0 * sizeof (mgreg_t)), X86_EAX, sizeof (mgreg_t));
407         /* Arg2 - calling code */
408         if (tramp_type == MONO_TRAMPOLINE_JUMP) {
409                 x86_mov_membase_imm (code, X86_ESP, (1 * sizeof (mgreg_t)), 0, sizeof (mgreg_t));
410         } else {
411                 x86_mov_reg_membase (code, X86_EAX, X86_EBP, caller_ip_offset, sizeof (mgreg_t));
412                 x86_mov_membase_reg (code, X86_ESP, (1 * sizeof (mgreg_t)), X86_EAX, sizeof (mgreg_t));
413         }
414         /* Arg3 - trampoline argument */
415         x86_mov_reg_membase (code, X86_EAX, X86_EBP, arg_offset, sizeof (mgreg_t));
416         x86_mov_membase_reg (code, X86_ESP, (2 * sizeof (mgreg_t)), X86_EAX, sizeof (mgreg_t));
417         /* Arg4 - trampoline address */
418         // FIXME:
419         x86_mov_membase_imm (code, X86_ESP, (3 * sizeof (mgreg_t)), 0, sizeof (mgreg_t));
420
421 #ifdef __APPLE__
422         /* check the stack is aligned after the ret ip is pushed */
423         /*
424         x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
425         x86_alu_reg_imm (code, X86_AND, X86_EDX, 15);
426         x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
427         x86_branch_disp (code, X86_CC_Z, 3, FALSE);
428         x86_breakpoint (code);
429         */
430 #endif
431
432         if (aot) {
433                 char *icall_name = g_strdup_printf ("trampoline_func_%d", tramp_type);
434                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
435                 x86_call_reg (code, X86_EAX);
436         } else {
437                 tramp = (guint8*)mono_get_trampoline_func (tramp_type);
438                 x86_call_code (code, tramp);
439         }
440
441         /*
442          * Overwrite the trampoline argument with the address we need to jump to,
443          * to free %eax.
444          */
445         x86_mov_membase_reg (code, X86_EBP, arg_offset, X86_EAX, 4);
446
447         /* Check for interruptions */
448         if (aot) {
449                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint");
450                 x86_call_reg (code, X86_EAX);
451         } else {
452                 x86_call_code (code, (guint8*)mono_thread_force_interruption_checkpoint);
453         }
454
455         /* Restore LMF */
456         x86_mov_reg_membase (code, X86_EAX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), sizeof (mgreg_t));
457         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof (mgreg_t));
458         x86_alu_reg_imm (code, X86_SUB, X86_ECX, 1);
459         x86_mov_membase_reg (code, X86_EAX, 0, X86_ECX, sizeof (mgreg_t));
460
461         /* Restore registers */
462         for (i = X86_EAX; i <= X86_EDI; ++i) {
463                 if (i == X86_ESP || i == X86_EBP)
464                         continue;
465                 if (i == X86_EAX && !((tramp_type == MONO_TRAMPOLINE_RESTORE_STACK_PROT) || (tramp_type == MONO_TRAMPOLINE_AOT_PLT)))
466                         continue;
467                 x86_mov_reg_membase (code, i, X86_EBP, regarray_offset + (i * 4), 4);
468         }
469
470         /* Restore frame */
471         x86_leave (code);
472
473         if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
474                 /* Load the value returned by the trampoline */
475                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 0, 4);
476                 /* The trampoline returns normally, pop the trampoline argument */
477                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
478                 x86_ret (code);
479         } else {
480                 /* The trampoline argument is at the top of the stack, and it contains the address we need to branch to */
481                 if (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD) {
482                         x86_pop_reg (code, X86_EAX);
483                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 0x8);
484                         x86_jump_reg (code, X86_EAX);
485                 } else {
486                         x86_ret (code);
487                 }
488         }
489
490         nacl_global_codeman_validate (&buf, 256, &code);
491         g_assert ((code - buf) <= 256);
492
493         if (info) {
494                 tramp_name = mono_get_generic_trampoline_name (tramp_type);
495                 *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
496                 g_free (tramp_name);
497         }
498
499         return buf;
500 }
501
502 gpointer
503 mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
504 {
505         guint8 *code, *buf;
506         int tramp_size = NACL_SIZE (16, kNaClAlignment);                
507
508         code = buf = mono_global_codeman_reserve (tramp_size);
509         x86_ret (code);
510
511         nacl_global_codeman_validate (&buf, tramp_size, &code);
512
513         mono_arch_flush_icache (buf, code - buf);
514
515         if (info)
516                 *info = mono_tramp_info_create ("nullified_class_init_trampoline", buf, code - buf, NULL, NULL);
517
518         return buf;
519 }
520
521 #define TRAMPOLINE_SIZE 10
522
523 gpointer
524 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
525 {
526         guint8 *code, *buf, *tramp;
527         
528         tramp = mono_get_trampoline_code (tramp_type);
529
530         code = buf = mono_domain_code_reserve_align (domain, TRAMPOLINE_SIZE, NACL_SIZE (4, kNaClAlignment));
531
532         x86_push_imm (buf, arg1);
533         x86_jump_code (buf, tramp);
534         g_assert ((buf - code) <= TRAMPOLINE_SIZE);
535
536         nacl_domain_code_validate (domain, &code, NACL_SIZE (4, kNaClAlignment), &buf);
537
538         mono_arch_flush_icache (code, buf - code);
539
540         if (code_len)
541                 *code_len = buf - code;
542
543         return code;
544 }
545
546 gpointer
547 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
548 {
549         guint8 *tramp;
550         guint8 *code, *buf;
551         guint8 **rgctx_null_jumps;
552         int tramp_size;
553         int depth, index;
554         int i;
555         gboolean mrgctx;
556         MonoJumpInfo *ji = NULL;
557         GSList *unwind_ops = NULL;
558
559         unwind_ops = mono_arch_get_cie_program ();
560
561         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
562         index = MONO_RGCTX_SLOT_INDEX (slot);
563         if (mrgctx)
564                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
565         for (depth = 0; ; ++depth) {
566                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
567
568                 if (index < size - 1)
569                         break;
570                 index -= size - 1;
571         }
572
573 #if defined(__default_codegen__)
574         tramp_size = (aot ? 64 : 36) + 6 * depth;
575 #elif defined(__native_client_codegen__)
576         tramp_size = (aot ? 64 : 36) + 2 * kNaClAlignment +
577           6 * (depth + kNaClAlignment);
578 #endif
579
580         code = buf = mono_global_codeman_reserve (tramp_size);
581
582         rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
583
584         /* load vtable/mrgctx ptr */
585         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
586         if (!mrgctx) {
587                 /* load rgctx ptr from vtable */
588                 x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context), 4);
589                 /* is the rgctx ptr null? */
590                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
591                 /* if yes, jump to actual trampoline */
592                 rgctx_null_jumps [0] = code;
593                 x86_branch8 (code, X86_CC_Z, -1, 1);
594         }
595
596         for (i = 0; i < depth; ++i) {
597                 /* load ptr to next array */
598                 if (mrgctx && i == 0)
599                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT, 4);
600                 else
601                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
602                 /* is the ptr null? */
603                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
604                 /* if yes, jump to actual trampoline */
605                 rgctx_null_jumps [i + 1] = code;
606                 x86_branch8 (code, X86_CC_Z, -1, 1);
607         }
608
609         /* fetch slot */
610         x86_mov_reg_membase (code, X86_EAX, X86_EAX, sizeof (gpointer) * (index + 1), 4);
611         /* is the slot null? */
612         x86_test_reg_reg (code, X86_EAX, X86_EAX);
613         /* if yes, jump to actual trampoline */
614         rgctx_null_jumps [depth + 1] = code;
615         x86_branch8 (code, X86_CC_Z, -1, 1);
616         /* otherwise return */
617         x86_ret (code);
618
619         for (i = mrgctx ? 1 : 0; i <= depth + 1; ++i)
620                 x86_patch (rgctx_null_jumps [i], code);
621
622         g_free (rgctx_null_jumps);
623
624         x86_mov_reg_membase (code, MONO_ARCH_VTABLE_REG, X86_ESP, 4, 4);
625
626         if (aot) {
627                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot));
628                 x86_jump_reg (code, X86_EAX);
629         } else {
630                 tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
631
632                 /* jump to the actual trampoline */
633                 x86_jump_code (code, tramp);
634         }
635
636         nacl_global_codeman_validate (&buf, tramp_size, &code);
637         mono_arch_flush_icache (buf, code - buf);
638
639         g_assert (code - buf <= tramp_size);
640
641         if (info) {
642                 char *name = mono_get_rgctx_fetch_trampoline_name (slot);
643                 *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
644                 g_free (name);
645         }
646
647         return buf;
648 }
649
650 /*
651  * mono_arch_create_general_rgctx_lazy_fetch_trampoline:
652  *
653  *   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
654  * the trampoline to call if the slot is not filled.
655  */
656 gpointer
657 mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot)
658 {
659         guint8 *code, *buf;
660         int tramp_size;
661         MonoJumpInfo *ji = NULL;
662         GSList *unwind_ops = NULL;
663
664         g_assert (aot);
665
666         unwind_ops = mono_arch_get_cie_program ();
667
668         tramp_size = 64;
669
670         code = buf = mono_global_codeman_reserve (tramp_size);
671
672         // FIXME: Currently, we always go to the slow path.
673         
674         /* Load trampoline addr */
675         x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_RGCTX_REG, 4, 4);
676         /* Load mrgctx/vtable */
677         x86_mov_reg_membase (code, MONO_ARCH_VTABLE_REG, X86_ESP, 4, 4);
678
679         x86_jump_reg (code, X86_EAX);
680
681         nacl_global_codeman_validate (&buf, tramp_size, &code);
682         mono_arch_flush_icache (buf, code - buf);
683
684         g_assert (code - buf <= tramp_size);
685
686         if (info)
687                 *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops);
688
689         return buf;
690 }
691
692 gpointer
693 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot)
694 {
695         guint8 *tramp;
696         guint8 *code, *buf;
697         static int byte_offset = -1;
698         static guint8 bitmask;
699         guint8 *jump;
700         int tramp_size;
701         GSList *unwind_ops = NULL;
702         MonoJumpInfo *ji = NULL;
703
704         tramp_size = 64;
705
706         code = buf = mono_global_codeman_reserve (tramp_size);
707
708         unwind_ops = mono_arch_get_cie_program ();
709
710         if (byte_offset < 0)
711                 mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
712
713         x86_test_membase_imm (code, MONO_ARCH_VTABLE_REG, byte_offset, bitmask);
714         jump = code;
715         x86_branch8 (code, X86_CC_Z, -1, 1);
716
717         x86_ret (code);
718
719         x86_patch (jump, code);
720
721         /* Push the vtable so the stack is the same as in a specific trampoline */
722         x86_push_reg (code, MONO_ARCH_VTABLE_REG);
723
724         if (aot) {
725                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_generic_class_init");
726                 x86_jump_reg (code, X86_EAX);
727         } else {
728                 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
729
730                 /* jump to the actual trampoline */
731                 x86_jump_code (code, tramp);
732         }
733
734         mono_arch_flush_icache (code, code - buf);
735
736         g_assert (code - buf <= tramp_size);
737 #ifdef __native_client_codegen__
738         g_assert (code - buf <= kNaClAlignment);
739 #endif
740
741         nacl_global_codeman_validate (&buf, tramp_size, &code);
742
743         if (info)
744                 *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops);
745
746         return buf;
747 }
748
749 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
750 /*
751  * The code produced by this trampoline is equivalent to this:
752  *
753  * if (obj) {
754  *      if (obj->synchronisation) {
755  *              if (obj->synchronisation->owner == 0) {
756  *                      if (cmpxch (&obj->synchronisation->owner, TID, 0) == 0)
757  *                              return;
758  *              }
759  *              if (obj->synchronisation->owner == TID) {
760  *                      ++obj->synchronisation->nest;
761  *                      return;
762  *              }
763  *      }
764  * }
765  * return full_monitor_enter ();
766  *
767  */
768 gpointer
769 mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot)
770 {
771         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
772         guint8 *code, *buf;
773         guint8 *jump_obj_null, *jump_sync_null, *jump_other_owner, *jump_cmpxchg_failed, *jump_tid, *jump_sync_thin_hash = NULL;
774         int tramp_size;
775         int owner_offset, nest_offset, dummy;
776         MonoJumpInfo *ji = NULL;
777         GSList *unwind_ops = NULL;
778
779         g_assert (MONO_ARCH_MONITOR_OBJECT_REG == X86_EAX);
780
781         mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &dummy);
782         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer));
783         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
784         owner_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (owner_offset);
785         nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
786
787         tramp_size = NACL_SIZE (96, 128);
788
789         code = buf = mono_global_codeman_reserve (tramp_size);
790
791         if (mono_thread_get_tls_offset () != -1) {
792                 /* MonoObject* obj is in EAX */
793                 /* is obj null? */
794                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
795                 /* if yes, jump to actual trampoline */
796                 jump_obj_null = code;
797                 x86_branch8 (code, X86_CC_Z, -1, 1);
798
799                 /* load obj->synchronization to ECX */
800                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 4);
801
802                 if (mono_gc_is_moving ()) {
803                         /*if bit zero is set it's a thin hash*/
804                         /*FIXME use testb encoding*/
805                         x86_test_reg_imm (code, X86_ECX, 0x01);
806                         jump_sync_thin_hash = code;
807                         x86_branch8 (code, X86_CC_NE, -1, 1);
808
809                         /*clear bits used by the gc*/
810                         x86_alu_reg_imm (code, X86_AND, X86_ECX, ~0x3);
811                 }
812
813                 /* is synchronization null? */
814                 x86_test_reg_reg (code, X86_ECX, X86_ECX);
815
816                 /* if yes, jump to actual trampoline */
817                 jump_sync_null = code;
818                 x86_branch8 (code, X86_CC_Z, -1, 1);
819
820                 /* load MonoInternalThread* into EDX */
821                 if (aot) {
822                         /* load_aotconst () puts the result into EAX */
823                         x86_mov_reg_reg (code, X86_EDX, X86_EAX, sizeof (mgreg_t));
824                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_TLS_OFFSET, GINT_TO_POINTER (TLS_KEY_THREAD));
825                         code = mono_x86_emit_tls_get_reg (code, X86_EAX, X86_EAX);
826                         x86_xchg_reg_reg (code, X86_EAX, X86_EDX, sizeof (mgreg_t));
827                 } else {
828                         code = mono_x86_emit_tls_get (code, X86_EDX, mono_thread_get_tls_offset ());
829                 }
830                 /* load TID into EDX */
831                 x86_mov_reg_membase (code, X86_EDX, X86_EDX, MONO_STRUCT_OFFSET (MonoInternalThread, tid), 4);
832
833                 /* is synchronization->owner null? */
834                 x86_alu_membase_imm (code, X86_CMP, X86_ECX, owner_offset, 0);
835                 /* if not, jump to next case */
836                 jump_tid = code;
837                 x86_branch8 (code, X86_CC_NZ, -1, 1);
838
839                 /* if yes, try a compare-exchange with the TID */
840                 /* free up register EAX, needed for the zero */
841                 x86_push_reg (code, X86_EAX);
842                 /* zero EAX */
843                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
844                 /* compare and exchange */
845                 x86_prefix (code, X86_LOCK_PREFIX);
846                 x86_cmpxchg_membase_reg (code, X86_ECX, owner_offset, X86_EDX);
847                 /* if not successful, jump to actual trampoline */
848                 jump_cmpxchg_failed = code;
849                 x86_branch8 (code, X86_CC_NZ, -1, 1);
850                 /* if successful, pop and return */
851                 x86_pop_reg (code, X86_EAX);
852                 x86_ret (code);
853
854                 /* next case: synchronization->owner is not null */
855                 x86_patch (jump_tid, code);
856                 /* is synchronization->owner == TID? */
857                 x86_alu_membase_reg (code, X86_CMP, X86_ECX, owner_offset, X86_EDX);
858                 /* if not, jump to actual trampoline */
859                 jump_other_owner = code;
860                 x86_branch8 (code, X86_CC_NZ, -1, 1);
861                 /* if yes, increment nest */
862                 x86_inc_membase (code, X86_ECX, nest_offset);
863                 /* return */
864                 x86_ret (code);
865
866                 /* push obj */
867                 x86_patch (jump_obj_null, code);
868                 if (jump_sync_thin_hash)
869                         x86_patch (jump_sync_thin_hash, code);
870                 x86_patch (jump_sync_null, code);
871                 x86_patch (jump_other_owner, code);
872                 x86_push_reg (code, X86_EAX);
873                 /* jump to the actual trampoline */
874                 x86_patch (jump_cmpxchg_failed, code);
875                 if (aot) {
876                         /* We are calling the generic trampoline directly, the argument is pushed
877                          * on the stack just like a specific trampoline.
878                          */
879                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_enter");
880                         x86_jump_reg (code, X86_EAX);
881                 } else {
882                         x86_jump_code (code, tramp);
883                 }
884         } else {
885                 /* push obj and jump to the actual trampoline */
886                 x86_push_reg (code, X86_EAX);
887                 if (aot) {
888                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_enter");
889                         x86_jump_reg (code, X86_EAX);
890                 } else {
891                         x86_jump_code (code, tramp);
892                 }
893         }
894
895         mono_arch_flush_icache (buf, code - buf);
896         g_assert (code - buf <= tramp_size);
897
898         nacl_global_codeman_validate (&buf, tramp_size, &code);
899
900         if (info)
901                 *info = mono_tramp_info_create ("monitor_enter_trampoline", buf, code - buf, ji, unwind_ops);
902
903         return buf;
904 }
905
906 gpointer
907 mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
908 {
909         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
910         guint8 *code, *buf;
911         guint8 *jump_obj_null, *jump_have_waiters, *jump_sync_null, *jump_not_owned, *jump_sync_thin_hash = NULL;
912         guint8 *jump_next;
913         int tramp_size;
914         int owner_offset, nest_offset, entry_count_offset;
915         MonoJumpInfo *ji = NULL;
916         GSList *unwind_ops = NULL;
917
918         g_assert (MONO_ARCH_MONITOR_OBJECT_REG == X86_EAX);
919
920         mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &entry_count_offset);
921         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer));
922         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
923         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (entry_count_offset) == sizeof (gint32));
924         owner_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (owner_offset);
925         nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
926         entry_count_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (entry_count_offset);
927
928         tramp_size = NACL_SIZE (96, 128);
929
930         code = buf = mono_global_codeman_reserve (tramp_size);
931
932         if (mono_thread_get_tls_offset () != -1) {
933                 /* MonoObject* obj is in EAX */
934                 /* is obj null? */
935                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
936                 /* if yes, jump to actual trampoline */
937                 jump_obj_null = code;
938                 x86_branch8 (code, X86_CC_Z, -1, 1);
939
940                 /* load obj->synchronization to ECX */
941                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, MONO_STRUCT_OFFSET (MonoObject, synchronisation), 4);
942
943                 if (mono_gc_is_moving ()) {
944                         /*if bit zero is set it's a thin hash*/
945                         /*FIXME use testb encoding*/
946                         x86_test_reg_imm (code, X86_ECX, 0x01);
947                         jump_sync_thin_hash = code;
948                         x86_branch8 (code, X86_CC_NE, -1, 1);
949
950                         /*clear bits used by the gc*/
951                         x86_alu_reg_imm (code, X86_AND, X86_ECX, ~0x3);
952                 }
953
954                 /* is synchronization null? */
955                 x86_test_reg_reg (code, X86_ECX, X86_ECX);
956                 /* if yes, jump to actual trampoline */
957                 jump_sync_null = code;
958                 x86_branch8 (code, X86_CC_Z, -1, 1);
959
960                 /* next case: synchronization is not null */
961                 /* load MonoInternalThread* into EDX */
962                 if (aot) {
963                         /* load_aotconst () puts the result into EAX */
964                         x86_mov_reg_reg (code, X86_EDX, X86_EAX, sizeof (mgreg_t));
965                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_TLS_OFFSET, GINT_TO_POINTER (TLS_KEY_THREAD));
966                         code = mono_x86_emit_tls_get_reg (code, X86_EAX, X86_EAX);
967                         x86_xchg_reg_reg (code, X86_EAX, X86_EDX, sizeof (mgreg_t));
968                 } else {
969                         code = mono_x86_emit_tls_get (code, X86_EDX, mono_thread_get_tls_offset ());
970                 }
971                 /* load TID into EDX */
972                 x86_mov_reg_membase (code, X86_EDX, X86_EDX, MONO_STRUCT_OFFSET (MonoInternalThread, tid), 4);
973                 /* is synchronization->owner == TID */
974                 x86_alu_membase_reg (code, X86_CMP, X86_ECX, owner_offset, X86_EDX);
975                 /* if no, jump to actual trampoline */
976                 jump_not_owned = code;
977                 x86_branch8 (code, X86_CC_NZ, -1, 1);
978
979                 /* next case: synchronization->owner == TID */
980                 /* is synchronization->nest == 1 */
981                 x86_alu_membase_imm (code, X86_CMP, X86_ECX, nest_offset, 1);
982                 /* if not, jump to next case */
983                 jump_next = code;
984                 x86_branch8 (code, X86_CC_NZ, -1, 1);
985                 /* if yes, is synchronization->entry_count zero? */
986                 x86_alu_membase_imm (code, X86_CMP, X86_ECX, entry_count_offset, 0);
987                 /* if not, jump to actual trampoline */
988                 jump_have_waiters = code;
989                 x86_branch8 (code, X86_CC_NZ, -1 , 1);
990                 /* if yes, set synchronization->owner to null and return */
991                 x86_mov_membase_imm (code, X86_ECX, owner_offset, 0, 4);
992                 x86_ret (code);
993
994                 /* next case: synchronization->nest is not 1 */
995                 x86_patch (jump_next, code);
996                 /* decrease synchronization->nest and return */
997                 x86_dec_membase (code, X86_ECX, nest_offset);
998                 x86_ret (code);
999
1000                 /* push obj and jump to the actual trampoline */
1001                 x86_patch (jump_obj_null, code);
1002                 if (jump_sync_thin_hash)
1003                         x86_patch (jump_sync_thin_hash, code);
1004                 x86_patch (jump_have_waiters, code);
1005                 x86_patch (jump_not_owned, code);
1006                 x86_patch (jump_sync_null, code);
1007         }
1008
1009         /* push obj and jump to the actual trampoline */
1010         x86_push_reg (code, X86_EAX);
1011         if (aot) {
1012                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_exit");
1013                 x86_jump_reg (code, X86_EAX);
1014         } else {
1015                 x86_jump_code (code, tramp);
1016         }
1017
1018         nacl_global_codeman_validate (&buf, tramp_size, &code);
1019
1020         mono_arch_flush_icache (buf, code - buf);
1021         g_assert (code - buf <= tramp_size);
1022
1023         if (info)
1024                 *info = mono_tramp_info_create ("monitor_exit_trampoline", buf, code - buf, ji, unwind_ops);
1025
1026         return buf;
1027 }
1028
1029 #else
1030
1031 gpointer
1032 mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot)
1033 {
1034         g_assert_not_reached ();
1035         return NULL;
1036 }
1037
1038 gpointer
1039 mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
1040 {
1041         g_assert_not_reached ();
1042         return NULL;
1043 }
1044
1045 #endif
1046
1047 void
1048 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
1049 {
1050         /* FIXME: This is not thread safe */
1051         guint8 *code = ji->code_start;
1052
1053         x86_push_imm (code, func_arg);
1054         x86_call_code (code, (guint8*)func);
1055 }
1056
1057 static gpointer
1058 handler_block_trampoline_helper (void)
1059 {
1060         MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1061         return jit_tls->handler_block_return_address;
1062 }
1063
1064 gpointer
1065 mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
1066 {
1067         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
1068         guint8 *code, *buf;
1069         int tramp_size = 64;
1070         MonoJumpInfo *ji = NULL;
1071         GSList *unwind_ops = NULL;
1072
1073         g_assert (!aot);
1074
1075         code = buf = mono_global_codeman_reserve (tramp_size);
1076
1077         /*
1078         This trampoline restore the call chain of the handler block then jumps into the code that deals with it.
1079         */
1080
1081         /*
1082          * We are in a method frame after the call emitted by OP_CALL_HANDLER.
1083          */
1084
1085         if (mono_get_jit_tls_offset () != -1) {
1086                 code = mono_x86_emit_tls_get (code, X86_EAX, mono_get_jit_tls_offset ());
1087                 x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_STRUCT_OFFSET (MonoJitTlsData, handler_block_return_address), 4);
1088         } else {
1089                 /*Slow path uses a c helper*/
1090                 x86_call_code (code, handler_block_trampoline_helper);
1091         }
1092         /* Simulate a call */
1093         /*Fix stack alignment*/
1094         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x4);
1095         /* This is the address the trampoline will return to */
1096         x86_push_reg (code, X86_EAX);
1097         /* Dummy trampoline argument, since we call the generic trampoline directly */
1098         x86_push_imm (code, 0);
1099         x86_jump_code (code, tramp);
1100
1101         nacl_global_codeman_validate (&buf, tramp_size, &code);
1102
1103         mono_arch_flush_icache (buf, code - buf);
1104         g_assert (code - buf <= tramp_size);
1105
1106         if (info)
1107                 *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
1108
1109         return buf;
1110 }
1111
1112 guint8*
1113 mono_arch_get_call_target (guint8 *code)
1114 {
1115         if (code [-5] == 0xe8) {
1116                 gint32 disp = *(gint32*)(code - 4);
1117                 guint8 *target = code + disp;
1118
1119                 return target;
1120         } else {
1121                 return NULL;
1122         }
1123 }
1124
1125 guint32
1126 mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code)
1127 {
1128         return *(guint32*)(plt_entry + NACL_SIZE (6, 12));
1129 }
1130
1131 /*
1132  * mono_arch_get_gsharedvt_arg_trampoline:
1133  *
1134  *   Return a trampoline which passes ARG to the gsharedvt in/out trampoline ADDR.
1135  */
1136 gpointer
1137 mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
1138 {
1139         guint8 *code, *start;
1140         int buf_len;
1141
1142         buf_len = 10;
1143
1144         start = code = mono_domain_code_reserve (domain, buf_len);
1145
1146         x86_mov_reg_imm (code, X86_EAX, arg);
1147         x86_jump_code (code, addr);
1148         g_assert ((code - start) <= buf_len);
1149
1150         nacl_domain_code_validate (domain, &start, buf_len, &code);
1151         mono_arch_flush_icache (start, code - start);
1152
1153         return start;
1154 }
1155
1156 #if defined(ENABLE_GSHAREDVT)
1157
1158 #include "../../../mono-extensions/mono/mini/tramp-x86-gsharedvt.c"
1159
1160 #else
1161
1162 gpointer
1163 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
1164 {
1165         if (info)
1166                 *info = NULL;
1167         return NULL;
1168 }
1169
1170 #endif /* !MONOTOUCH */