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