Merge pull request #942 from ermshiperete/MessageBoxBugs
[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 guchar*
296 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
297 {
298         char *tramp_name;
299         guint8 *buf, *code, *tramp;
300         int pushed_args, pushed_args_caller_saved;
301         GSList *unwind_ops = NULL;
302         MonoJumpInfo *ji = NULL;
303
304         unwind_ops = mono_arch_get_cie_program ();
305
306         code = buf = mono_global_codeman_reserve (256);
307
308         /* Note that there is a single argument to the trampoline
309          * and it is stored at: esp + pushed_args * sizeof (gpointer)
310          * the ret address is at: esp + (pushed_args + 1) * sizeof (gpointer)
311          */
312
313         /* Put all registers into an array on the stack
314          * If this code is changed, make sure to update the offset value in
315          * mono_arch_get_this_arg_from_call () in mini-x86.c.
316          */
317         x86_push_reg (code, X86_EDI);
318         x86_push_reg (code, X86_ESI);
319         x86_push_reg (code, X86_EBP);
320         x86_push_reg (code, X86_ESP);
321         x86_push_reg (code, X86_EBX);
322         x86_push_reg (code, X86_EDX);
323         x86_push_reg (code, X86_ECX);
324         x86_push_reg (code, X86_EAX);
325
326         pushed_args_caller_saved = pushed_args = 8;
327
328         /* Align stack on apple */
329         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
330
331         pushed_args ++;
332
333         /* save LMF begin */
334
335         /* save the IP (caller ip) */
336         if (tramp_type == MONO_TRAMPOLINE_JUMP)
337                 x86_push_imm (code, 0);
338         else
339                 x86_push_membase (code, X86_ESP, (pushed_args + 1) * sizeof (gpointer));
340
341         pushed_args++;
342
343         x86_push_reg (code, X86_EBP);
344         x86_push_reg (code, X86_ESI);
345         x86_push_reg (code, X86_EDI);
346         x86_push_reg (code, X86_EBX);
347
348         pushed_args += 4;
349
350         /* save ESP */
351         x86_push_reg (code, X86_ESP);
352         /* Adjust ESP so it points to the previous frame */
353         x86_alu_membase_imm (code, X86_ADD, X86_ESP, 0, (pushed_args + 2) * 4);
354
355         pushed_args ++;
356
357         /* save method info */
358         if ((tramp_type == MONO_TRAMPOLINE_JIT) || (tramp_type == MONO_TRAMPOLINE_JUMP))
359                 x86_push_membase (code, X86_ESP, pushed_args * sizeof (gpointer));
360         else
361                 x86_push_imm (code, 0);
362
363         pushed_args++;
364
365         /* On apple, the stack is correctly aligned to 16 bytes because pushed_args is
366          * 16 and there is the extra trampoline arg + the return ip pushed by call
367          * FIXME: Note that if an exception happens while some args are pushed
368          * on the stack, the stack will be misaligned.
369          */
370         g_assert (pushed_args == 16);
371
372         /* get the address of lmf for the current thread */
373         if (aot) {
374                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr");
375                 x86_call_reg (code, X86_EAX);
376         } else {
377                 x86_call_code (code, mono_get_lmf_addr);
378         }
379         /* push lmf */
380         x86_push_reg (code, X86_EAX); 
381         /* push *lfm (previous_lmf) */
382         x86_push_membase (code, X86_EAX, 0);
383         /* Signal to mono_arch_find_jit_info () that this is a trampoline frame */
384         x86_alu_membase_imm (code, X86_ADD, X86_ESP, 0, 1);
385         /* *(lmf) = ESP */
386         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
387         /* save LFM end */
388
389         pushed_args += 2;
390
391         /* starting the call sequence */
392
393         /* FIXME: Push the trampoline address */
394         x86_push_imm (code, 0);
395
396         pushed_args++;
397
398         /* push the method info */
399         x86_push_membase (code, X86_ESP, pushed_args * sizeof (gpointer));
400
401         pushed_args++;
402
403         /* push the return address onto the stack */
404         if (tramp_type == MONO_TRAMPOLINE_JUMP)
405                 x86_push_imm (code, 0);
406         else
407                 x86_push_membase (code, X86_ESP, (pushed_args + 1) * sizeof (gpointer));
408         pushed_args++;
409         /* push the address of the register array */
410         x86_lea_membase (code, X86_EAX, X86_ESP, (pushed_args - 8) * sizeof (gpointer));
411         x86_push_reg (code, X86_EAX);
412
413         pushed_args++;
414
415 #ifdef __APPLE__
416         /* check the stack is aligned after the ret ip is pushed */
417         /*x86_mov_reg_reg (buf, X86_EDX, X86_ESP, 4);
418         x86_alu_reg_imm (buf, X86_AND, X86_EDX, 15);
419         x86_alu_reg_imm (buf, X86_CMP, X86_EDX, 0);
420         x86_branch_disp (buf, X86_CC_Z, 3, FALSE);
421         x86_breakpoint (buf);*/
422 #endif
423
424         mono_add_unwind_op_def_cfa (unwind_ops, code, buf, X86_ESP, ((pushed_args + 2) * 4));
425
426         if (aot) {
427                 char *icall_name = g_strdup_printf ("trampoline_func_%d", tramp_type);
428                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
429                 x86_call_reg (code, X86_EAX);
430         } else {
431                 tramp = (guint8*)mono_get_trampoline_func (tramp_type);
432                 x86_call_code (code, tramp);
433         }
434
435         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4*4);
436
437         pushed_args -= 4;
438
439         /* Check for thread interruption */
440         /* This is not perf critical code so no need to check the interrupt flag */
441         /* Align the stack on osx */
442         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 3 * 4);
443         x86_push_reg (code, X86_EAX);
444         if (aot) {
445                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint");
446                 x86_call_reg (code, X86_EAX);
447         } else {
448                 x86_call_code (code, (guint8*)mono_thread_force_interruption_checkpoint);
449         }
450         x86_pop_reg (code, X86_EAX);
451         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3 * 4);
452
453         /* Restore LMF */
454
455         /* ebx = previous_lmf */
456         x86_pop_reg (code, X86_EBX);
457         pushed_args--;
458         x86_alu_reg_imm (code, X86_SUB, X86_EBX, 1);
459
460         /* edi = lmf */
461         x86_pop_reg (code, X86_EDI);
462         pushed_args--;
463
464         /* *(lmf) = previous_lmf */
465         x86_mov_membase_reg (code, X86_EDI, 0, X86_EBX, 4);
466
467         /* discard method info */
468         x86_pop_reg (code, X86_ESI);
469         pushed_args--;
470
471         /* discard ESP */
472         x86_pop_reg (code, X86_ESI);
473         pushed_args--;
474
475         /* restore caller saved regs */
476         x86_pop_reg (code, X86_EBX);
477         x86_pop_reg (code, X86_EDI);
478         x86_pop_reg (code, X86_ESI);
479         x86_pop_reg (code, X86_EBP);
480
481         pushed_args -= 4;
482
483         /* discard save IP */
484         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
485         pushed_args--;
486
487         /* restore LMF end */
488
489         if (!MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
490                 /* 
491                  * Overwrite the method ptr with the address we need to jump to,
492                  * to free %eax.
493                  */
494                 x86_mov_membase_reg (code, X86_ESP, pushed_args * sizeof (gpointer), X86_EAX, 4);
495         }
496
497         /* Restore caller saved registers */
498         x86_mov_reg_membase (code, X86_ECX, X86_ESP, (pushed_args - pushed_args_caller_saved + X86_ECX) * 4, 4);
499         x86_mov_reg_membase (code, X86_EDX, X86_ESP, (pushed_args - pushed_args_caller_saved + X86_EDX) * 4, 4);
500         if ((tramp_type == MONO_TRAMPOLINE_RESTORE_STACK_PROT) || (tramp_type == MONO_TRAMPOLINE_AOT_PLT))
501                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, (pushed_args - pushed_args_caller_saved + X86_EAX) * 4, 4);
502
503         if (!MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
504                 /* Pop saved reg array + stack align */
505                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 9 * 4);
506                 pushed_args -= 9;
507                 g_assert (pushed_args == 0);
508         } else {
509                 /* Pop saved reg array + stack align + method ptr */
510                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 10 * 4);
511                 pushed_args -= 10;
512
513                 /* We've popped one more stack item than we've pushed (the
514                    method ptr argument), so we must end up at -1. */
515                 g_assert (pushed_args == -1);
516         }
517
518         /*block guard trampolines are called with the stack aligned but must exit with the stack unaligned. */
519         if (tramp_type == MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD) {
520                 x86_pop_reg (code, X86_EAX);
521                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 0x8);
522                 x86_jump_reg (code, X86_EAX);
523         } else {
524                 x86_ret (code);
525         }
526
527         nacl_global_codeman_validate (&buf, 256, &code);
528         g_assert ((code - buf) <= 256);
529
530         if (info) {
531                 tramp_name = mono_get_generic_trampoline_name (tramp_type);
532                 *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
533                 g_free (tramp_name);
534         }
535
536         return buf;
537 }
538
539 gpointer
540 mono_arch_get_nullified_class_init_trampoline (MonoTrampInfo **info)
541 {
542         guint8 *code, *buf;
543         int tramp_size = NACL_SIZE (16, kNaClAlignment);                
544
545         code = buf = mono_global_codeman_reserve (tramp_size);
546         x86_ret (code);
547
548         nacl_global_codeman_validate (&buf, tramp_size, &code);
549
550         mono_arch_flush_icache (buf, code - buf);
551
552         if (info)
553                 *info = mono_tramp_info_create ("nullified_class_init_trampoline", buf, code - buf, NULL, NULL);
554
555         return buf;
556 }
557
558 #define TRAMPOLINE_SIZE 10
559
560 gpointer
561 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
562 {
563         guint8 *code, *buf, *tramp;
564         
565         tramp = mono_get_trampoline_code (tramp_type);
566
567         code = buf = mono_domain_code_reserve_align (domain, TRAMPOLINE_SIZE, NACL_SIZE (4, kNaClAlignment));
568
569         x86_push_imm (buf, arg1);
570         x86_jump_code (buf, tramp);
571         g_assert ((buf - code) <= TRAMPOLINE_SIZE);
572
573         nacl_domain_code_validate (domain, &code, NACL_SIZE (4, kNaClAlignment), &buf);
574
575         mono_arch_flush_icache (code, buf - code);
576
577         if (code_len)
578                 *code_len = buf - code;
579
580         return code;
581 }
582
583 gpointer
584 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
585 {
586         guint8 *tramp;
587         guint8 *code, *buf;
588         guint8 **rgctx_null_jumps;
589         int tramp_size;
590         int depth, index;
591         int i;
592         gboolean mrgctx;
593         MonoJumpInfo *ji = NULL;
594         GSList *unwind_ops = NULL;
595
596         unwind_ops = mono_arch_get_cie_program ();
597
598         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
599         index = MONO_RGCTX_SLOT_INDEX (slot);
600         if (mrgctx)
601                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
602         for (depth = 0; ; ++depth) {
603                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
604
605                 if (index < size - 1)
606                         break;
607                 index -= size - 1;
608         }
609
610 #if defined(__default_codegen__)
611         tramp_size = (aot ? 64 : 36) + 6 * depth;
612 #elif defined(__native_client_codegen__)
613         tramp_size = (aot ? 64 : 36) + 2 * kNaClAlignment +
614           6 * (depth + kNaClAlignment);
615 #endif
616
617         code = buf = mono_global_codeman_reserve (tramp_size);
618
619         rgctx_null_jumps = g_malloc (sizeof (guint8*) * (depth + 2));
620
621         /* load vtable/mrgctx ptr */
622         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
623         if (!mrgctx) {
624                 /* load rgctx ptr from vtable */
625                 x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoVTable, runtime_generic_context), 4);
626                 /* is the rgctx ptr null? */
627                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
628                 /* if yes, jump to actual trampoline */
629                 rgctx_null_jumps [0] = code;
630                 x86_branch8 (code, X86_CC_Z, -1, 1);
631         }
632
633         for (i = 0; i < depth; ++i) {
634                 /* load ptr to next array */
635                 if (mrgctx && i == 0)
636                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT, 4);
637                 else
638                         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0, 4);
639                 /* is the ptr null? */
640                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
641                 /* if yes, jump to actual trampoline */
642                 rgctx_null_jumps [i + 1] = code;
643                 x86_branch8 (code, X86_CC_Z, -1, 1);
644         }
645
646         /* fetch slot */
647         x86_mov_reg_membase (code, X86_EAX, X86_EAX, sizeof (gpointer) * (index + 1), 4);
648         /* is the slot null? */
649         x86_test_reg_reg (code, X86_EAX, X86_EAX);
650         /* if yes, jump to actual trampoline */
651         rgctx_null_jumps [depth + 1] = code;
652         x86_branch8 (code, X86_CC_Z, -1, 1);
653         /* otherwise return */
654         x86_ret (code);
655
656         for (i = mrgctx ? 1 : 0; i <= depth + 1; ++i)
657                 x86_patch (rgctx_null_jumps [i], code);
658
659         g_free (rgctx_null_jumps);
660
661         x86_mov_reg_membase (code, MONO_ARCH_VTABLE_REG, X86_ESP, 4, 4);
662
663         if (aot) {
664                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot));
665                 x86_jump_reg (code, X86_EAX);
666         } else {
667                 tramp = mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
668
669                 /* jump to the actual trampoline */
670                 x86_jump_code (code, tramp);
671         }
672
673         nacl_global_codeman_validate (&buf, tramp_size, &code);
674         mono_arch_flush_icache (buf, code - buf);
675
676         g_assert (code - buf <= tramp_size);
677
678         if (info) {
679                 char *name = mono_get_rgctx_fetch_trampoline_name (slot);
680                 *info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
681                 g_free (name);
682         }
683
684         return buf;
685 }
686
687 /*
688  * mono_arch_create_general_rgctx_lazy_fetch_trampoline:
689  *
690  *   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
691  * the trampoline to call if the slot is not filled.
692  */
693 gpointer
694 mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot)
695 {
696         guint8 *code, *buf;
697         int tramp_size;
698         MonoJumpInfo *ji = NULL;
699         GSList *unwind_ops = NULL;
700
701         g_assert (aot);
702
703         unwind_ops = mono_arch_get_cie_program ();
704
705         tramp_size = 64;
706
707         code = buf = mono_global_codeman_reserve (tramp_size);
708
709         // FIXME: Currently, we always go to the slow path.
710         
711         /* Load trampoline addr */
712         x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_RGCTX_REG, 4, 4);
713         /* Load mrgctx/vtable */
714         x86_mov_reg_membase (code, MONO_ARCH_VTABLE_REG, X86_ESP, 4, 4);
715
716         x86_jump_reg (code, X86_EAX);
717
718         nacl_global_codeman_validate (&buf, tramp_size, &code);
719         mono_arch_flush_icache (buf, code - buf);
720
721         g_assert (code - buf <= tramp_size);
722
723         if (info)
724                 *info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops);
725
726         return buf;
727 }
728
729 gpointer
730 mono_arch_create_generic_class_init_trampoline (MonoTrampInfo **info, gboolean aot)
731 {
732         guint8 *tramp;
733         guint8 *code, *buf;
734         static int byte_offset = -1;
735         static guint8 bitmask;
736         guint8 *jump;
737         int tramp_size;
738         GSList *unwind_ops = NULL;
739         MonoJumpInfo *ji = NULL;
740
741         tramp_size = 64;
742
743         code = buf = mono_global_codeman_reserve (tramp_size);
744
745         unwind_ops = mono_arch_get_cie_program ();
746
747         if (byte_offset < 0)
748                 mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
749
750         x86_test_membase_imm (code, MONO_ARCH_VTABLE_REG, byte_offset, bitmask);
751         jump = code;
752         x86_branch8 (code, X86_CC_Z, -1, 1);
753
754         x86_ret (code);
755
756         x86_patch (jump, code);
757
758         /* Push the vtable so the stack is the same as in a specific trampoline */
759         x86_push_reg (code, MONO_ARCH_VTABLE_REG);
760
761         if (aot) {
762                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_generic_class_init");
763                 x86_jump_reg (code, X86_EAX);
764         } else {
765                 tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
766
767                 /* jump to the actual trampoline */
768                 x86_jump_code (code, tramp);
769         }
770
771         mono_arch_flush_icache (code, code - buf);
772
773         g_assert (code - buf <= tramp_size);
774 #ifdef __native_client_codegen__
775         g_assert (code - buf <= kNaClAlignment);
776 #endif
777
778         nacl_global_codeman_validate (&buf, tramp_size, &code);
779
780         if (info)
781                 *info = mono_tramp_info_create ("generic_class_init_trampoline", buf, code - buf, ji, unwind_ops);
782
783         return buf;
784 }
785
786 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
787 /*
788  * The code produced by this trampoline is equivalent to this:
789  *
790  * if (obj) {
791  *      if (obj->synchronisation) {
792  *              if (obj->synchronisation->owner == 0) {
793  *                      if (cmpxch (&obj->synchronisation->owner, TID, 0) == 0)
794  *                              return;
795  *              }
796  *              if (obj->synchronisation->owner == TID) {
797  *                      ++obj->synchronisation->nest;
798  *                      return;
799  *              }
800  *      }
801  * }
802  * return full_monitor_enter ();
803  *
804  */
805 gpointer
806 mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot)
807 {
808         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
809         guint8 *code, *buf;
810         guint8 *jump_obj_null, *jump_sync_null, *jump_other_owner, *jump_cmpxchg_failed, *jump_tid, *jump_sync_thin_hash = NULL;
811         int tramp_size;
812         int owner_offset, nest_offset, dummy;
813         MonoJumpInfo *ji = NULL;
814         GSList *unwind_ops = NULL;
815
816         g_assert (MONO_ARCH_MONITOR_OBJECT_REG == X86_EAX);
817
818         mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &dummy);
819         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer));
820         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
821         owner_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (owner_offset);
822         nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
823
824         tramp_size = NACL_SIZE (96, 128);
825
826         code = buf = mono_global_codeman_reserve (tramp_size);
827
828         if (mono_thread_get_tls_offset () != -1) {
829                 /* MonoObject* obj is in EAX */
830                 /* is obj null? */
831                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
832                 /* if yes, jump to actual trampoline */
833                 jump_obj_null = code;
834                 x86_branch8 (code, X86_CC_Z, -1, 1);
835
836                 /* load obj->synchronization to ECX */
837                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoObject, synchronisation), 4);
838
839                 if (mono_gc_is_moving ()) {
840                         /*if bit zero is set it's a thin hash*/
841                         /*FIXME use testb encoding*/
842                         x86_test_reg_imm (code, X86_ECX, 0x01);
843                         jump_sync_thin_hash = code;
844                         x86_branch8 (code, X86_CC_NE, -1, 1);
845
846                         /*clear bits used by the gc*/
847                         x86_alu_reg_imm (code, X86_AND, X86_ECX, ~0x3);
848                 }
849
850                 /* is synchronization null? */
851                 x86_test_reg_reg (code, X86_ECX, X86_ECX);
852
853                 /* if yes, jump to actual trampoline */
854                 jump_sync_null = code;
855                 x86_branch8 (code, X86_CC_Z, -1, 1);
856
857                 /* load MonoInternalThread* into EDX */
858                 if (aot) {
859                         /* load_aotconst () puts the result into EAX */
860                         x86_mov_reg_reg (code, X86_EDX, X86_EAX, sizeof (mgreg_t));
861                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_TLS_OFFSET, GINT_TO_POINTER (TLS_KEY_THREAD));
862                         code = mono_x86_emit_tls_get_reg (code, X86_EAX, X86_EAX);
863                         x86_xchg_reg_reg (code, X86_EAX, X86_EDX, sizeof (mgreg_t));
864                 } else {
865                         code = mono_x86_emit_tls_get (code, X86_EDX, mono_thread_get_tls_offset ());
866                 }
867                 /* load TID into EDX */
868                 x86_mov_reg_membase (code, X86_EDX, X86_EDX, G_STRUCT_OFFSET (MonoInternalThread, tid), 4);
869
870                 /* is synchronization->owner null? */
871                 x86_alu_membase_imm (code, X86_CMP, X86_ECX, owner_offset, 0);
872                 /* if not, jump to next case */
873                 jump_tid = code;
874                 x86_branch8 (code, X86_CC_NZ, -1, 1);
875
876                 /* if yes, try a compare-exchange with the TID */
877                 /* free up register EAX, needed for the zero */
878                 x86_push_reg (code, X86_EAX);
879                 /* zero EAX */
880                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
881                 /* compare and exchange */
882                 x86_prefix (code, X86_LOCK_PREFIX);
883                 x86_cmpxchg_membase_reg (code, X86_ECX, owner_offset, X86_EDX);
884                 /* if not successful, jump to actual trampoline */
885                 jump_cmpxchg_failed = code;
886                 x86_branch8 (code, X86_CC_NZ, -1, 1);
887                 /* if successful, pop and return */
888                 x86_pop_reg (code, X86_EAX);
889                 x86_ret (code);
890
891                 /* next case: synchronization->owner is not null */
892                 x86_patch (jump_tid, code);
893                 /* is synchronization->owner == TID? */
894                 x86_alu_membase_reg (code, X86_CMP, X86_ECX, owner_offset, X86_EDX);
895                 /* if not, jump to actual trampoline */
896                 jump_other_owner = code;
897                 x86_branch8 (code, X86_CC_NZ, -1, 1);
898                 /* if yes, increment nest */
899                 x86_inc_membase (code, X86_ECX, nest_offset);
900                 /* return */
901                 x86_ret (code);
902
903                 /* push obj */
904                 x86_patch (jump_obj_null, code);
905                 if (jump_sync_thin_hash)
906                         x86_patch (jump_sync_thin_hash, code);
907                 x86_patch (jump_sync_null, code);
908                 x86_patch (jump_other_owner, code);
909                 x86_push_reg (code, X86_EAX);
910                 /* jump to the actual trampoline */
911                 x86_patch (jump_cmpxchg_failed, code);
912                 if (aot) {
913                         /* We are calling the generic trampoline directly, the argument is pushed
914                          * on the stack just like a specific trampoline.
915                          */
916                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_enter");
917                         x86_jump_reg (code, X86_EAX);
918                 } else {
919                         x86_jump_code (code, tramp);
920                 }
921         } else {
922                 /* push obj and jump to the actual trampoline */
923                 x86_push_reg (code, X86_EAX);
924                 if (aot) {
925                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_enter");
926                         x86_jump_reg (code, X86_EAX);
927                 } else {
928                         x86_jump_code (code, tramp);
929                 }
930         }
931
932         mono_arch_flush_icache (buf, code - buf);
933         g_assert (code - buf <= tramp_size);
934
935         nacl_global_codeman_validate (&buf, tramp_size, &code);
936
937         if (info)
938                 *info = mono_tramp_info_create ("monitor_enter_trampoline", buf, code - buf, ji, unwind_ops);
939
940         return buf;
941 }
942
943 gpointer
944 mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
945 {
946         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
947         guint8 *code, *buf;
948         guint8 *jump_obj_null, *jump_have_waiters, *jump_sync_null, *jump_not_owned, *jump_sync_thin_hash = NULL;
949         guint8 *jump_next;
950         int tramp_size;
951         int owner_offset, nest_offset, entry_count_offset;
952         MonoJumpInfo *ji = NULL;
953         GSList *unwind_ops = NULL;
954
955         g_assert (MONO_ARCH_MONITOR_OBJECT_REG == X86_EAX);
956
957         mono_monitor_threads_sync_members_offset (&owner_offset, &nest_offset, &entry_count_offset);
958         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (owner_offset) == sizeof (gpointer));
959         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (nest_offset) == sizeof (guint32));
960         g_assert (MONO_THREADS_SYNC_MEMBER_SIZE (entry_count_offset) == sizeof (gint32));
961         owner_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (owner_offset);
962         nest_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (nest_offset);
963         entry_count_offset = MONO_THREADS_SYNC_MEMBER_OFFSET (entry_count_offset);
964
965         tramp_size = NACL_SIZE (96, 128);
966
967         code = buf = mono_global_codeman_reserve (tramp_size);
968
969         if (mono_thread_get_tls_offset () != -1) {
970                 /* MonoObject* obj is in EAX */
971                 /* is obj null? */
972                 x86_test_reg_reg (code, X86_EAX, X86_EAX);
973                 /* if yes, jump to actual trampoline */
974                 jump_obj_null = code;
975                 x86_branch8 (code, X86_CC_Z, -1, 1);
976
977                 /* load obj->synchronization to ECX */
978                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoObject, synchronisation), 4);
979
980                 if (mono_gc_is_moving ()) {
981                         /*if bit zero is set it's a thin hash*/
982                         /*FIXME use testb encoding*/
983                         x86_test_reg_imm (code, X86_ECX, 0x01);
984                         jump_sync_thin_hash = code;
985                         x86_branch8 (code, X86_CC_NE, -1, 1);
986
987                         /*clear bits used by the gc*/
988                         x86_alu_reg_imm (code, X86_AND, X86_ECX, ~0x3);
989                 }
990
991                 /* is synchronization null? */
992                 x86_test_reg_reg (code, X86_ECX, X86_ECX);
993                 /* if yes, jump to actual trampoline */
994                 jump_sync_null = code;
995                 x86_branch8 (code, X86_CC_Z, -1, 1);
996
997                 /* next case: synchronization is not null */
998                 /* load MonoInternalThread* into EDX */
999                 if (aot) {
1000                         /* load_aotconst () puts the result into EAX */
1001                         x86_mov_reg_reg (code, X86_EDX, X86_EAX, sizeof (mgreg_t));
1002                         code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_TLS_OFFSET, GINT_TO_POINTER (TLS_KEY_THREAD));
1003                         code = mono_x86_emit_tls_get_reg (code, X86_EAX, X86_EAX);
1004                         x86_xchg_reg_reg (code, X86_EAX, X86_EDX, sizeof (mgreg_t));
1005                 } else {
1006                         code = mono_x86_emit_tls_get (code, X86_EDX, mono_thread_get_tls_offset ());
1007                 }
1008                 /* load TID into EDX */
1009                 x86_mov_reg_membase (code, X86_EDX, X86_EDX, G_STRUCT_OFFSET (MonoInternalThread, tid), 4);
1010                 /* is synchronization->owner == TID */
1011                 x86_alu_membase_reg (code, X86_CMP, X86_ECX, owner_offset, X86_EDX);
1012                 /* if no, jump to actual trampoline */
1013                 jump_not_owned = code;
1014                 x86_branch8 (code, X86_CC_NZ, -1, 1);
1015
1016                 /* next case: synchronization->owner == TID */
1017                 /* is synchronization->nest == 1 */
1018                 x86_alu_membase_imm (code, X86_CMP, X86_ECX, nest_offset, 1);
1019                 /* if not, jump to next case */
1020                 jump_next = code;
1021                 x86_branch8 (code, X86_CC_NZ, -1, 1);
1022                 /* if yes, is synchronization->entry_count zero? */
1023                 x86_alu_membase_imm (code, X86_CMP, X86_ECX, entry_count_offset, 0);
1024                 /* if not, jump to actual trampoline */
1025                 jump_have_waiters = code;
1026                 x86_branch8 (code, X86_CC_NZ, -1 , 1);
1027                 /* if yes, set synchronization->owner to null and return */
1028                 x86_mov_membase_imm (code, X86_ECX, owner_offset, 0, 4);
1029                 x86_ret (code);
1030
1031                 /* next case: synchronization->nest is not 1 */
1032                 x86_patch (jump_next, code);
1033                 /* decrease synchronization->nest and return */
1034                 x86_dec_membase (code, X86_ECX, nest_offset);
1035                 x86_ret (code);
1036
1037                 /* push obj and jump to the actual trampoline */
1038                 x86_patch (jump_obj_null, code);
1039                 if (jump_sync_thin_hash)
1040                         x86_patch (jump_sync_thin_hash, code);
1041                 x86_patch (jump_have_waiters, code);
1042                 x86_patch (jump_not_owned, code);
1043                 x86_patch (jump_sync_null, code);
1044         }
1045
1046         /* push obj and jump to the actual trampoline */
1047         x86_push_reg (code, X86_EAX);
1048         if (aot) {
1049                 code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "generic_trampoline_monitor_exit");
1050                 x86_jump_reg (code, X86_EAX);
1051         } else {
1052                 x86_jump_code (code, tramp);
1053         }
1054
1055         nacl_global_codeman_validate (&buf, tramp_size, &code);
1056
1057         mono_arch_flush_icache (buf, code - buf);
1058         g_assert (code - buf <= tramp_size);
1059
1060         if (info)
1061                 *info = mono_tramp_info_create ("monitor_exit_trampoline", buf, code - buf, ji, unwind_ops);
1062
1063         return buf;
1064 }
1065
1066 #else
1067
1068 gpointer
1069 mono_arch_create_monitor_enter_trampoline (MonoTrampInfo **info, gboolean aot)
1070 {
1071         g_assert_not_reached ();
1072         return NULL;
1073 }
1074
1075 gpointer
1076 mono_arch_create_monitor_exit_trampoline (MonoTrampInfo **info, gboolean aot)
1077 {
1078         g_assert_not_reached ();
1079         return NULL;
1080 }
1081
1082 #endif
1083
1084 void
1085 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
1086 {
1087         /* FIXME: This is not thread safe */
1088         guint8 *code = ji->code_start;
1089
1090         x86_push_imm (code, func_arg);
1091         x86_call_code (code, (guint8*)func);
1092 }
1093
1094 static gpointer
1095 handler_block_trampoline_helper (void)
1096 {
1097         MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1098         return jit_tls->handler_block_return_address;
1099 }
1100
1101 gpointer
1102 mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot)
1103 {
1104         guint8 *tramp = mono_get_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
1105         guint8 *code, *buf;
1106         int tramp_size = 64;
1107         MonoJumpInfo *ji = NULL;
1108         GSList *unwind_ops = NULL;
1109
1110         g_assert (!aot);
1111
1112         code = buf = mono_global_codeman_reserve (tramp_size);
1113
1114         /*
1115         This trampoline restore the call chain of the handler block then jumps into the code that deals with it.
1116         */
1117
1118         /*
1119          * We are in a method frame after the call emitted by OP_CALL_HANDLER.
1120          */
1121
1122         if (mono_get_jit_tls_offset () != -1) {
1123                 code = mono_x86_emit_tls_get (code, X86_EAX, mono_get_jit_tls_offset ());
1124                 x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, handler_block_return_address), 4);
1125         } else {
1126                 /*Slow path uses a c helper*/
1127                 x86_call_code (code, handler_block_trampoline_helper);
1128         }
1129         /* Simulate a call */
1130         /*Fix stack alignment*/
1131         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x4);
1132         /* This is the address the trampoline will return to */
1133         x86_push_reg (code, X86_EAX);
1134         /* Dummy trampoline argument, since we call the generic trampoline directly */
1135         x86_push_imm (code, 0);
1136         x86_jump_code (code, tramp);
1137
1138         nacl_global_codeman_validate (&buf, tramp_size, &code);
1139
1140         mono_arch_flush_icache (buf, code - buf);
1141         g_assert (code - buf <= tramp_size);
1142
1143         if (info)
1144                 *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops);
1145
1146         return buf;
1147 }
1148
1149 guint8*
1150 mono_arch_get_call_target (guint8 *code)
1151 {
1152         if (code [-5] == 0xe8) {
1153                 gint32 disp = *(gint32*)(code - 4);
1154                 guint8 *target = code + disp;
1155
1156                 return target;
1157         } else {
1158                 return NULL;
1159         }
1160 }
1161
1162 guint32
1163 mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code)
1164 {
1165         return *(guint32*)(plt_entry + NACL_SIZE (6, 12));
1166 }
1167
1168 /*
1169  * mono_arch_get_gsharedvt_arg_trampoline:
1170  *
1171  *   Return a trampoline which passes ARG to the gsharedvt in/out trampoline ADDR.
1172  */
1173 gpointer
1174 mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr)
1175 {
1176         guint8 *code, *start;
1177         int buf_len;
1178
1179         buf_len = 10;
1180
1181         start = code = mono_domain_code_reserve (domain, buf_len);
1182
1183         x86_mov_reg_imm (code, X86_EAX, arg);
1184         x86_jump_code (code, addr);
1185         g_assert ((code - start) <= buf_len);
1186
1187         nacl_domain_code_validate (domain, &start, buf_len, &code);
1188         mono_arch_flush_icache (start, code - start);
1189
1190         return start;
1191 }
1192
1193 #if defined(ENABLE_GSHAREDVT)
1194
1195 #include "../../../mono-extensions/mono/mini/tramp-x86-gsharedvt.c"
1196
1197 #else
1198
1199 gpointer
1200 mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot)
1201 {
1202         if (info)
1203                 *info = NULL;
1204         return NULL;
1205 }
1206
1207 #endif /* !MONOTOUCH */