2009-12-03 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-trampolines.c
1
2 #include <config.h>
3 #include <glib.h>
4
5 #include <mono/metadata/appdomain.h>
6 #include <mono/metadata/metadata-internals.h>
7 #include <mono/metadata/marshal.h>
8 #include <mono/metadata/tabledefs.h>
9 #include <mono/utils/mono-counters.h>
10
11 #ifdef HAVE_VALGRIND_MEMCHECK_H
12 #include <valgrind/memcheck.h>
13 #endif
14
15 #include "mini.h"
16 #include "debug-mini.h"
17
18 /*
19  * Address of the trampoline code.  This is used by the debugger to check
20  * whether a method is a trampoline.
21  */
22 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
23
24 static GHashTable *class_init_hash_addr = NULL;
25 static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
26 static GHashTable *rgctx_lazy_fetch_trampoline_hash_addr = NULL;
27
28 #define mono_trampolines_lock() EnterCriticalSection (&trampolines_mutex)
29 #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex)
30 static CRITICAL_SECTION trampolines_mutex;
31
32 static gpointer
33 get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr, gboolean need_rgctx_tramp)
34 {
35         if (mono_aot_only) {
36                 if (need_rgctx_tramp)
37                         /* 
38                          * The unbox trampolines call the method directly, so need to add
39                          * an rgctx tramp before them.
40                          */
41                         return mono_create_static_rgctx_trampoline (m, mono_aot_get_unbox_trampoline (m));
42                 else
43                         return mono_aot_get_unbox_trampoline (m);
44         } else {
45                 return mono_arch_get_unbox_trampoline (gsctx, m, addr);
46         }
47 }
48
49 #ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE
50 /*
51  * mono_create_static_rgctx_trampoline:
52  *
53  *   Return a static rgctx trampoline for M which branches to ADDR which should
54  * point to the compiled code of M.
55  *
56  *   Static rgctx trampolines are used when a shared generic method which doesn't
57  * have a this argument is called indirectly, ie. from code which can't pass in
58  * the rgctx argument. The trampoline sets the rgctx argument and jumps to the
59  * methods code. These trampolines are similar to the unbox trampolines, they
60  * perform the same task as the static rgctx wrappers, but they are smaller/faster,
61  * and can be made to work with full AOT.
62  */
63 gpointer
64 mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
65 {
66         gpointer ctx;
67         gpointer res;
68         MonoDomain *domain;
69
70         if (mini_method_get_context (m)->method_inst)
71                 ctx = mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst);
72         else
73                 ctx = mono_class_vtable (mono_domain_get (), m->klass);
74
75         if (mono_aot_only)
76                 return mono_aot_get_static_rgctx_trampoline (ctx, addr);
77
78         domain = mono_domain_get ();
79
80         mono_domain_lock (domain);
81         res = g_hash_table_lookup (domain_jit_info (domain)->static_rgctx_trampoline_hash,
82                                                            m);
83         mono_domain_unlock (domain);
84         if (res)
85                 return res;
86
87         res = mono_arch_get_static_rgctx_trampoline (m, ctx, addr);
88
89         mono_domain_lock (domain);
90         /* Duplicates inserted while we didn't hold the lock are OK */
91         g_hash_table_insert (domain_jit_info (domain)->static_rgctx_trampoline_hash, m, res);
92         mono_domain_unlock (domain);
93
94         return res;
95 }
96 #else
97 gpointer
98 mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
99 {
100         /* 
101          * This shouldn't happen as all arches which support generic sharing support
102          * static rgctx trampolines as well.
103          */
104         g_assert_not_reached ();
105 }
106 #endif
107
108 gpointer*
109 mono_get_vcall_slot_addr (guint8* code, mgreg_t *regs)
110 {
111         gpointer vt;
112         int displacement;
113         vt = mono_arch_get_vcall_slot (code, regs, &displacement);
114         if (!vt)
115                 return NULL;
116         return (gpointer*)((char*)vt + displacement);
117 }
118
119 #ifdef MONO_ARCH_HAVE_IMT
120
121 static gpointer*
122 mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method, gboolean *need_rgctx_tramp)
123 {
124         MonoGenericSharingContext *gsctx = mono_get_generic_context_from_code (code);
125         MonoObject *this_argument = mono_arch_find_this_argument (regs, method, gsctx);
126         MonoVTable *vt = this_argument->vtable;
127         int displacement = slot - ((gpointer*)vt);
128
129         if (displacement > 0) {
130                 /* slot is in the vtable, not in the IMT */
131 #if DEBUG_IMT
132                 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p is in the vtable, not in the IMT\n", slot);
133 #endif
134                 return slot;
135         } else {
136                 MonoMethod *imt_method = mono_arch_find_imt_method (regs, code);
137                 int interface_offset;
138                 int imt_slot = MONO_IMT_SIZE + displacement;
139
140                 interface_offset = mono_class_interface_offset (vt->klass, imt_method->klass);
141
142                 if (interface_offset < 0) {
143                         g_print ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, 0), mono_type_get_name_full (&imt_method->klass->byval_arg, 0));
144                         g_assert_not_reached ();
145                 }
146                 mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
147
148                 if (impl_method) {
149                         MonoMethod *impl;
150
151                         if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
152                                 MonoGenericContext context = { NULL, NULL };
153
154                                 /* 
155                                  * Generic virtual method, imt_method contains the inflated interface 
156                                  * method, need to get the inflated impl method.
157                                  */
158                                 /* imt_method->slot might not be set */
159                                 impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_declaring_generic_method (imt_method)->slot);
160
161                                 if (impl->klass->generic_class)
162                                         context.class_inst = impl->klass->generic_class->context.class_inst;
163                                 context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
164                                 impl = mono_class_inflate_generic_method (impl, &context);
165                         } else {
166                                 impl = mono_class_get_vtable_entry (vt->klass, interface_offset + imt_method->slot);
167                         }
168
169                         if (mono_method_needs_static_rgctx_invoke (impl, FALSE))
170                                 *need_rgctx_tramp = TRUE;
171
172                         *impl_method = impl;
173 #if DEBUG_IMT
174                 printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
175                                 method->klass->name_space, method->klass->name, method->name, 
176                                 imt_method->klass->name_space, imt_method->klass->name, imt_method->name);
177 #endif
178                 }
179                 g_assert (imt_slot < MONO_IMT_SIZE);
180                 if (vt->imt_collisions_bitmap & (1 << imt_slot)) {
181                         int slot = mono_method_get_vtable_index (imt_method);
182                         int vtable_offset;
183                         gpointer *vtable_slot;
184
185                         g_assert (slot != -1);
186                         vtable_offset = interface_offset + slot;
187                         vtable_slot = & (vt->vtable [vtable_offset]);
188 #if DEBUG_IMT
189                         printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, and colliding becomes %p[%d] (interface_offset = %d, method->slot = %d)\n", slot, imt_slot, vtable_slot, vtable_offset, interface_offset, imt_method->slot);
190 #endif
191                         return vtable_slot;
192                 } else {
193 #if DEBUG_IMT
194                         printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot);
195 #endif
196                         return slot;
197                 }
198         }
199 }
200 #endif
201
202 /**
203  * common_call_trampoline:
204  *
205  *   The code to handle normal, virtual, and interface method calls and jumps, both
206  * from JITted and LLVM compiled code.
207  */
208 static gpointer
209 common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp, MonoVTable *vt, gpointer *vtable_slot, gboolean need_rgctx_tramp)
210 {
211         gpointer addr;
212         gboolean generic_shared = FALSE;
213         MonoMethod *m;
214         MonoMethod *declaring = NULL;
215         MonoMethod *generic_virtual = NULL;
216         int context_used;
217         gboolean proxy = FALSE;
218         gpointer *orig_vtable_slot;
219
220         m = arg;
221
222         orig_vtable_slot = vtable_slot;
223
224         if (m == MONO_FAKE_VTABLE_METHOD) {
225                 int displacement;
226                 if (!vt) {
227                         int i;
228                         MonoJitInfo *ji;
229
230                         ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
231                         if (ji)
232                                 printf ("Caller: %s\n", mono_method_full_name (ji->method, TRUE));
233                         /* Print some debug info */
234                         for (i = 0; i < 32; ++i)
235                                 printf ("0x%x ", code [-32 + i]);
236                         printf ("\n");
237                         g_assert (vt);
238                 }
239                 displacement = (guint8*)vtable_slot - (guint8*)vt;
240                 if (displacement > 0) {
241                         int slot = (displacement - G_STRUCT_OFFSET (MonoVTable, vtable)) / sizeof (gpointer);
242                         g_assert (slot >= 0);
243
244                         /* Avoid loading metadata or creating a generic vtable if possible */
245                         addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
246                         if (addr)
247                                 addr = mono_create_ftnptr (mono_domain_get (), addr);
248                         if (addr && !vt->klass->valuetype) {
249                                 vtable_slot = mono_get_vcall_slot_addr (code, regs);
250                                 if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
251                                         *vtable_slot = mono_get_addr_from_ftnptr (addr);
252                                 }
253
254                                 return addr;
255                         }
256
257                         m = mono_class_get_vtable_entry (vt->klass, slot);
258                         if (mono_method_needs_static_rgctx_invoke (m, FALSE))
259                                 need_rgctx_tramp = TRUE;
260
261                         /*g_print ("%s with disp %d: %s at %p\n", vt->klass->name, displacement, m->name, code);*/
262                 } else {
263                         /* We got here from an interface method: redirect to IMT handling */
264                         m = MONO_FAKE_IMT_METHOD;
265                         /*g_print ("vtable with disp %d at %p\n", displacement, code);*/
266                 }
267         }
268
269         /* this is the IMT trampoline */
270 #ifdef MONO_ARCH_HAVE_IMT
271         if (m == MONO_FAKE_IMT_METHOD) {
272                 MonoMethod *impl_method;
273                 MonoGenericSharingContext *gsctx;
274                 MonoObject *this_arg;
275
276                 /* we get the interface method because mono_convert_imt_slot_to_vtable_slot ()
277                  * needs the signature to be able to find the this argument
278                  */
279                 m = mono_arch_find_imt_method (regs, code);
280                 vtable_slot = orig_vtable_slot;
281                 g_assert (vtable_slot);
282
283                 gsctx = mono_get_generic_context_from_code (code);
284                 this_arg = mono_arch_find_this_argument (regs, m, gsctx);
285
286                 if (this_arg->vtable->klass == mono_defaults.transparent_proxy_class) {
287                         /* Use the slow path for now */
288                         proxy = TRUE;
289                     m = mono_object_get_virtual_method (this_arg, m);
290                 } else {
291                         vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, &impl_method, &need_rgctx_tramp);
292                         /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
293                          * to be called, so we compile it and go ahead as usual.
294                          */
295                         /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
296                         if (m->is_inflated && ((MonoMethodInflated*)m)->context.method_inst) {
297                                 /* Generic virtual method */
298                                 generic_virtual = m;
299                                 m = impl_method;
300                                 need_rgctx_tramp = TRUE;
301                         } else {
302                                 m = impl_method;
303                         }
304                 }
305         }
306 #endif
307
308         if (m->is_generic) {
309                 MonoGenericContext context = { NULL, NULL };
310                 MonoMethod *declaring;
311
312                 if (m->is_inflated)
313                         declaring = mono_method_get_declaring_generic_method (m);
314                 else
315                         declaring = m;
316
317                 if (m->klass->generic_class)
318                         context.class_inst = m->klass->generic_class->context.class_inst;
319                 else
320                         g_assert (!m->klass->generic_container);
321
322 #ifdef MONO_ARCH_HAVE_IMT
323                 generic_virtual = mono_arch_find_imt_method (regs, code);
324 #endif
325                 if (generic_virtual) {
326                         g_assert (generic_virtual->is_inflated);
327                         context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
328                 }
329
330                 m = mono_class_inflate_generic_method (declaring, &context);
331                 /* FIXME: only do this if the method is sharable */
332                 need_rgctx_tramp = TRUE;
333         } else if ((context_used = mono_method_check_context_used (m))) {
334                 MonoClass *klass = NULL;
335                 MonoMethod *actual_method = NULL;
336                 MonoVTable *vt = NULL;
337                 MonoGenericInst *method_inst = NULL;
338
339                 vtable_slot = NULL;
340                 generic_shared = TRUE;
341
342                 g_assert (code);
343
344                 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
345 #ifdef MONO_ARCH_RGCTX_REG
346                         MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext*)mono_arch_find_static_call_vtable (regs, code);
347
348                         klass = mrgctx->class_vtable->klass;
349                         method_inst = mrgctx->method_inst;
350 #else
351                         g_assert_not_reached ();
352 #endif
353                 } else if ((m->flags & METHOD_ATTRIBUTE_STATIC) || m->klass->valuetype) {
354 #ifdef MONO_ARCH_RGCTX_REG
355                         MonoVTable *vtable = mono_arch_find_static_call_vtable (regs, code);
356
357                         klass = vtable->klass;
358 #else
359                         g_assert_not_reached ();
360 #endif
361                 } else {
362 #ifdef MONO_ARCH_HAVE_IMT
363                         MonoObject *this_argument = mono_arch_find_this_argument (regs, m,
364                                 mono_get_generic_context_from_code (code));
365
366                         vt = this_argument->vtable;
367                         vtable_slot = orig_vtable_slot;
368
369                         g_assert (this_argument->vtable->klass->inited);
370                         //mono_class_init (this_argument->vtable->klass);
371
372                         if (!vtable_slot)
373                                 klass = this_argument->vtable->klass->supertypes [m->klass->idepth - 1];
374 #else
375                         NOT_IMPLEMENTED;
376 #endif
377                 }
378
379                 g_assert (vtable_slot || klass);
380
381                 if (vtable_slot) {
382                         int displacement = vtable_slot - ((gpointer*)vt);
383
384                         g_assert_not_reached ();
385
386                         g_assert (displacement > 0);
387
388                         actual_method = vt->klass->vtable [displacement];
389                 }
390
391                 if (method_inst) {
392                         MonoGenericContext context = { NULL, NULL };
393
394                         if (m->is_inflated)
395                                 declaring = mono_method_get_declaring_generic_method (m);
396                         else
397                                 declaring = m;
398
399                         if (klass->generic_class)
400                                 context.class_inst = klass->generic_class->context.class_inst;
401                         else if (klass->generic_container)
402                                 context.class_inst = klass->generic_container->context.class_inst;
403                         context.method_inst = method_inst;
404
405                         actual_method = mono_class_inflate_generic_method (declaring, &context);
406                 } else {
407                         actual_method = mono_class_get_method_generic (klass, m);
408                 }
409
410                 g_assert (klass);
411                 g_assert (actual_method->klass == klass);
412
413                 if (actual_method->is_inflated)
414                         declaring = mono_method_get_declaring_generic_method (actual_method);
415                 else
416                         declaring = NULL;
417
418                 m = actual_method;
419         }
420
421         if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
422                 MonoJitInfo *ji;
423
424                 if (code)
425                         ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
426                 else
427                         ji = NULL;
428
429                 /* Avoid recursion */
430                 if (!(ji && ji->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED))
431                         m = mono_marshal_get_synchronized_wrapper (m);
432         }
433
434         /* Calls made through delegates on platforms without delegate trampolines */
435         if (!code && mono_method_needs_static_rgctx_invoke (m, FALSE))
436                 need_rgctx_tramp = TRUE;
437
438         addr = mono_compile_method (m);
439         g_assert (addr);
440
441         mono_debugger_trampoline_compiled (code, m, addr);
442
443         if (need_rgctx_tramp)
444                 addr = mono_create_static_rgctx_trampoline (m, addr);
445
446         if (generic_virtual) {
447                 vtable_slot = orig_vtable_slot;
448                 g_assert (vtable_slot);
449
450                 if (vt->klass->valuetype)
451                         addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr, need_rgctx_tramp);
452
453                 mono_method_add_generic_virtual_invocation (mono_domain_get (), 
454                                                                                                         vt, vtable_slot,
455                                                                                                         generic_virtual, addr);
456
457                 return addr;
458         }
459
460         /* the method was jumped to */
461         if (!code) {
462                 MonoDomain *domain = mono_domain_get ();
463
464                 /* Patch the got entries pointing to this method */
465                 /* 
466                  * We do this here instead of in mono_codegen () to cover the case when m
467                  * was loaded from an aot image.
468                  */
469                 if (domain_jit_info (domain)->jump_target_got_slot_hash) {
470                         GSList *list, *tmp;
471
472                         mono_domain_lock (domain);
473                         list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_got_slot_hash, m);
474                         if (list) {
475                                 for (tmp = list; tmp; tmp = tmp->next) {
476                                         gpointer *got_slot = tmp->data;
477                                         *got_slot = addr;
478                                 }
479                                 g_hash_table_remove (domain_jit_info (domain)->jump_target_got_slot_hash, m);
480                                 g_slist_free (list);
481                         }
482                         mono_domain_unlock (domain);
483                 }
484
485                 return addr;
486         }
487
488         vtable_slot = orig_vtable_slot;
489
490         if (vtable_slot) {
491                 if (m->klass->valuetype)
492                         addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr, need_rgctx_tramp);
493                 g_assert (*vtable_slot);
494
495                 if (!proxy && (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))) {
496 #ifdef MONO_ARCH_HAVE_IMT
497                         vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, NULL, &need_rgctx_tramp);
498 #endif
499                         *vtable_slot = mono_get_addr_from_ftnptr (addr);
500                 }
501         }
502         else {
503                 guint8 *plt_entry = mono_aot_get_plt_entry (code);
504
505                 if (plt_entry) {
506                         mono_arch_patch_plt_entry (plt_entry, NULL, regs, addr);
507                 } else if (!generic_shared || (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
508                         mono_domain_lookup_shared_generic (mono_domain_get (), declaring)) {
509                         if (generic_shared) {
510                                 if (m->wrapper_type != MONO_WRAPPER_NONE)
511                                         m = mono_marshal_method_from_wrapper (m);
512                                 g_assert (mono_method_is_generic_sharable_impl (m, FALSE));
513                         }
514
515                         /* Patch calling code */
516                         if (plt_entry) {
517
518                         } else {
519                                 MonoJitInfo *ji = 
520                                         mono_jit_info_table_find (mono_domain_get (), (char*)code);
521                                 MonoJitInfo *target_ji = 
522                                         mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr));
523
524                                 if (mono_method_same_domain (ji, target_ji))
525                                         mono_arch_patch_callsite (ji->code_start, code, addr);
526                         }
527                 }
528         }
529
530         return addr;
531 }
532
533 /**
534  * mono_magic_trampoline:
535  *
536  *   This trampoline handles calls from JITted code.
537  */
538 gpointer
539 mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
540 {
541         gpointer *vtable_slot;
542         int displacement;
543         MonoVTable *vt;
544
545         if (code && !mono_use_llvm)
546                 vt = mono_arch_get_vcall_slot (code, regs, &displacement);
547         else
548                 vt = NULL;
549         if (vt)
550                 vtable_slot = (gpointer*)((char*)vt + displacement);
551         else
552                 vtable_slot = NULL;
553
554         return common_call_trampoline (regs, code, arg, tramp, vt, vtable_slot, FALSE);
555 }
556
557 #ifdef MONO_ARCH_LLVM_SUPPORTED
558 /*
559  * mono_llvm_vcall_trampoline:
560  *
561  *   This trampoline handles virtual calls when using LLVM.
562  */
563 static gpointer
564 mono_llvm_vcall_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
565 {
566         MonoObject *this;
567         MonoVTable *vt;
568         gpointer *vtable_slot;
569         int slot;
570
571         /* 
572          * We have the method which is called, we need to obtain the vtable slot without
573          * disassembly which is impossible with LLVM.
574          * So we use the this argument.
575          */
576         this = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (m), regs, code);
577         g_assert (this);
578
579         slot = mono_method_get_vtable_slot (m);
580
581         g_assert (slot != -1);
582
583         g_assert (this->vtable->klass->vtable [slot] == m);
584
585         vt = this->vtable;
586
587         g_assert (!m->is_generic);
588
589         vtable_slot = &(vt->vtable [slot]);
590
591         return common_call_trampoline (regs, code, m, tramp, vt, vtable_slot, mono_method_needs_static_rgctx_invoke (m, 0));
592 }
593 #endif
594
595 gpointer
596 mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
597 {
598         MonoGenericContext context = { NULL, NULL };
599         MonoMethod *imt_method, *declaring;
600         gpointer addr;
601
602         g_assert (m->is_generic);
603
604         if (m->is_inflated)
605                 declaring = mono_method_get_declaring_generic_method (m);
606         else
607                 declaring = m;
608
609         if (m->klass->generic_class)
610                 context.class_inst = m->klass->generic_class->context.class_inst;
611         else
612                 g_assert (!m->klass->generic_container);
613
614 #ifdef MONO_ARCH_HAVE_IMT
615         imt_method = mono_arch_find_imt_method (regs, code);
616         if (imt_method->is_inflated)
617                 context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
618 #endif
619         m = mono_class_inflate_generic_method (declaring, &context);
620         m = mono_marshal_get_remoting_invoke_with_check (m);
621
622         addr = mono_compile_method (m);
623         g_assert (addr);
624
625         mono_debugger_trampoline_compiled (NULL, m, addr);
626
627         return addr;
628 }
629
630 /*
631  * mono_aot_trampoline:
632  *
633  *   This trampoline handles calls made from AOT code. We try to bypass the 
634  * normal JIT compilation logic to avoid loading the metadata for the method.
635  */
636 #ifdef MONO_ARCH_AOT_SUPPORTED
637 gpointer
638 mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info, 
639                                          guint8* tramp)
640 {
641         MonoImage *image;
642         guint32 token;
643         MonoMethod *method = NULL;
644         gpointer addr;
645         gpointer *vtable_slot;
646         gboolean is_got_entry;
647         guint8 *plt_entry;
648         gboolean need_rgctx_tramp = FALSE;
649
650         image = *(gpointer*)(gpointer)token_info;
651         token_info += sizeof (gpointer);
652         token = *(guint32*)(gpointer)token_info;
653
654         addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
655         if (!addr) {
656                 method = mono_get_method (image, token, NULL);
657                 g_assert (method);
658
659                 /* Use the generic code */
660                 return mono_magic_trampoline (regs, code, method, tramp);
661         }
662
663         addr = mono_create_ftnptr (mono_domain_get (), addr);
664
665         vtable_slot = mono_get_vcall_slot_addr (code, regs);
666         g_assert (!vtable_slot);
667
668         /* This is a normal call through a PLT entry */
669         plt_entry = mono_aot_get_plt_entry (code);
670         g_assert (plt_entry);
671
672         mono_arch_patch_plt_entry (plt_entry, NULL, regs, addr);
673
674         is_got_entry = FALSE;
675
676         /*
677          * Since AOT code is only used in the root domain, 
678          * mono_domain_get () != mono_get_root_domain () means the calling method
679          * is AppDomain:InvokeInDomain, so this is the same check as in 
680          * mono_method_same_domain () but without loading the metadata for the method.
681          */
682         if ((is_got_entry && (mono_domain_get () == mono_get_root_domain ())) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
683 #ifdef MONO_ARCH_HAVE_IMT
684                 if (!method)
685                         method = mono_get_method (image, token, NULL);
686                 vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, method, NULL, &need_rgctx_tramp);
687 #endif
688                 *vtable_slot = addr;
689         }
690
691         return addr;
692 }
693
694 /*
695  * mono_aot_plt_trampoline:
696  *
697  *   This trampoline handles calls made from AOT code through the PLT table.
698  */
699 gpointer
700 mono_aot_plt_trampoline (mgreg_t *regs, guint8 *code, guint8 *aot_module, 
701                                                  guint8* tramp)
702 {
703         guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code);
704
705         return mono_aot_plt_resolve (aot_module, plt_info_offset, code);
706 }
707 #endif
708
709 /**
710  * mono_class_init_trampoline:
711  *
712  * This method calls mono_runtime_class_init () to run the static constructor
713  * for the type, then patches the caller code so it is not called again.
714  */
715 void
716 mono_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
717 {
718         guint8 *plt_entry = mono_aot_get_plt_entry (code);
719
720         mono_runtime_class_init (vtable);
721
722         if (plt_entry) {
723                 mono_arch_nullify_plt_entry (plt_entry, regs);
724         } else {
725                 mono_arch_nullify_class_init_trampoline (code, regs);
726         }
727 }
728
729 /**
730  * mono_generic_class_init_trampoline:
731  *
732  * This method calls mono_runtime_class_init () to run the static constructor
733  * for the type.
734  */
735 void
736 mono_generic_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
737 {
738         mono_runtime_class_init (vtable);
739 }
740
741 static gpointer
742 mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, guint8 *tramp)
743 {
744 #ifdef MONO_ARCH_VTABLE_REG
745         static gboolean inited = FALSE;
746         static int num_lookups = 0;
747         guint32 slot = GPOINTER_TO_UINT (data);
748         mgreg_t *r = (mgreg_t*)regs;
749         gpointer arg = (gpointer)(gssize)r [MONO_ARCH_VTABLE_REG];
750         guint32 index = MONO_RGCTX_SLOT_INDEX (slot);
751         gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
752
753         if (!inited) {
754                 mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_lookups);
755                 inited = TRUE;
756         }
757
758         num_lookups++;
759
760         if (mrgctx)
761                 return mono_method_fill_runtime_generic_context (arg, index);
762         else
763                 return mono_class_fill_runtime_generic_context (arg, index);
764 #else
765         g_assert_not_reached ();
766 #endif
767 }
768
769 void
770 mono_monitor_enter_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
771 {
772         mono_monitor_enter (obj);
773 }
774
775 void
776 mono_monitor_exit_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
777 {
778         mono_monitor_exit (obj);
779 }
780
781 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
782
783 /**
784  * mono_delegate_trampoline:
785  *
786  *   This trampoline handles calls made to Delegate:Invoke ().
787  * This is called once the first time a delegate is invoked, so it must be fast.
788  */
789 gpointer
790 mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
791 {
792         MonoDomain *domain = mono_domain_get ();
793         MonoDelegate *delegate;
794         MonoJitInfo *ji;
795         MonoMethod *m;
796         MonoMethod *method = NULL;
797         gboolean multicast, callvirt;
798         gboolean need_rgctx_tramp = FALSE;
799         MonoMethod *invoke = tramp_data [0];
800         guint8 *impl_this = tramp_data [1];
801         guint8 *impl_nothis = tramp_data [2];
802
803         /* Obtain the delegate object according to the calling convention */
804
805         /* 
806          * Avoid calling mono_get_generic_context_from_code () now since it is expensive, 
807          * get_this_arg_from_call will call it if needed.
808          */
809         delegate = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (invoke), regs, code);
810
811         if (delegate->method) {
812                 method = delegate->method;
813
814                 /*
815                  * delegate->method_ptr == NULL means the delegate was initialized by 
816                  * mini_delegate_ctor, while != NULL means it is initialized by 
817                  * mono_delegate_ctor_with_method (). In both cases, we need to add wrappers
818                  * (ctor_with_method () does this, but it doesn't store the wrapper back into
819                  * delegate->method).
820                  */
821                 if (delegate->target && delegate->target->vtable->klass == mono_defaults.transparent_proxy_class) {
822 #ifndef DISABLE_COM
823                         if (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class != mono_defaults.com_object_class && 
824                            !((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class->is_com_object)
825 #endif
826                                 method = mono_marshal_get_remoting_invoke (method);
827                 }
828                 else if (mono_method_signature (method)->hasthis && method->klass->valuetype)
829                         method = mono_marshal_get_unbox_wrapper (method);
830         } else {
831                 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr));
832                 if (ji)
833                         method = ji->method;
834         }
835         callvirt = !delegate->target && method && mono_method_signature (method)->hasthis;
836
837         if (method && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
838                 method = mono_marshal_get_synchronized_wrapper (method);
839
840         if (method && mono_method_needs_static_rgctx_invoke (method, FALSE))
841                 need_rgctx_tramp = TRUE;
842
843         /* 
844          * If the called address is a trampoline, replace it with the compiled method so
845          * further calls don't have to go through the trampoline.
846          */
847         if (method && !callvirt) {
848                 /* Avoid the overhead of looking up an already compiled method if possible */
849                 if (delegate->method_code && *delegate->method_code) {
850                         delegate->method_ptr = *delegate->method_code;
851                 } else {
852                         delegate->method_ptr = mono_compile_method (method);
853                         if (delegate->method_code)
854                                 *delegate->method_code = delegate->method_ptr;
855                         mono_debugger_trampoline_compiled (NULL, method, delegate->method_ptr);
856                 }
857         }
858
859         if (need_rgctx_tramp)
860                 delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr);
861
862         multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL;
863         if (!multicast && !callvirt) {
864                 if (method && (method->flags & METHOD_ATTRIBUTE_STATIC) && mono_method_signature (method)->param_count == mono_method_signature (invoke)->param_count + 1)
865                         /* Closed static delegate */
866                         code = impl_this;
867                 else
868                         code = delegate->target ? impl_this : impl_nothis;
869
870                 if (code) {
871                         delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
872                         return code;
873                 }
874         }
875
876         /* The general, unoptimized case */
877         m = mono_marshal_get_delegate_invoke (invoke, delegate);
878         code = mono_compile_method (m);
879         delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
880         mono_debugger_trampoline_compiled (NULL, m, delegate->invoke_impl);
881
882         return code;
883 }
884
885 #endif
886
887 /*
888  * mono_get_trampoline_func:
889  *
890  *   Return the C function which needs to be called by the generic trampoline of type
891  * TRAMP_TYPE.
892  */
893 gconstpointer
894 mono_get_trampoline_func (MonoTrampolineType tramp_type)
895 {
896         switch (tramp_type) {
897         case MONO_TRAMPOLINE_JIT:
898         case MONO_TRAMPOLINE_JUMP:
899                 return mono_magic_trampoline;
900         case MONO_TRAMPOLINE_CLASS_INIT:
901                 return mono_class_init_trampoline;
902         case MONO_TRAMPOLINE_GENERIC_CLASS_INIT:
903                 return mono_generic_class_init_trampoline;
904         case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH:
905                 return mono_rgctx_lazy_fetch_trampoline;
906 #ifdef MONO_ARCH_AOT_SUPPORTED
907         case MONO_TRAMPOLINE_AOT:
908                 return mono_aot_trampoline;
909         case MONO_TRAMPOLINE_AOT_PLT:
910                 return mono_aot_plt_trampoline;
911 #endif
912 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
913         case MONO_TRAMPOLINE_DELEGATE:
914                 return mono_delegate_trampoline;
915 #endif
916         case MONO_TRAMPOLINE_RESTORE_STACK_PROT:
917                 return mono_altstack_restore_prot;
918         case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING:
919                 return mono_generic_virtual_remoting_trampoline;
920         case MONO_TRAMPOLINE_MONITOR_ENTER:
921                 return mono_monitor_enter_trampoline;
922         case MONO_TRAMPOLINE_MONITOR_EXIT:
923                 return mono_monitor_exit_trampoline;
924 #ifdef MONO_ARCH_LLVM_SUPPORTED
925         case MONO_TRAMPOLINE_LLVM_VCALL:
926                 return mono_llvm_vcall_trampoline;
927 #endif
928         default:
929                 g_assert_not_reached ();
930                 return NULL;
931         }
932 }
933
934 void
935 mono_trampolines_init (void)
936 {
937         InitializeCriticalSection (&trampolines_mutex);
938
939         if (mono_aot_only)
940                 return;
941
942         mono_trampoline_code [MONO_TRAMPOLINE_JIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JIT);
943         mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
944         mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
945         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
946         mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
947 #ifdef MONO_ARCH_AOT_SUPPORTED
948         mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
949         mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
950 #endif
951 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
952         mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
953 #endif
954         mono_trampoline_code [MONO_TRAMPOLINE_RESTORE_STACK_PROT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT);
955         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING);
956         mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
957         mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
958 #ifdef MONO_ARCH_LLVM_SUPPORTED
959         mono_trampoline_code [MONO_TRAMPOLINE_LLVM_VCALL] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_LLVM_VCALL);
960 #endif
961 }
962
963 void
964 mono_trampolines_cleanup (void)
965 {
966         if (class_init_hash_addr)
967                 g_hash_table_destroy (class_init_hash_addr);
968
969         DeleteCriticalSection (&trampolines_mutex);
970 }
971
972 guint8 *
973 mono_get_trampoline_code (MonoTrampolineType tramp_type)
974 {
975         g_assert (mono_trampoline_code [tramp_type]);
976
977         return mono_trampoline_code [tramp_type];
978 }
979
980 gpointer
981 mono_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
982 {
983         if (mono_aot_only)
984                 return mono_aot_create_specific_trampoline (mono_defaults.corlib, arg1, tramp_type, domain, code_len);
985         else
986                 return mono_arch_create_specific_trampoline (arg1, tramp_type, domain, code_len);
987 }
988
989 gpointer
990 mono_create_class_init_trampoline (MonoVTable *vtable)
991 {
992         gpointer code, ptr;
993         MonoDomain *domain = vtable->domain;
994
995         g_assert (!vtable->klass->generic_container);
996
997         /* previously created trampoline code */
998         mono_domain_lock (domain);
999         ptr = 
1000                 g_hash_table_lookup (domain_jit_info (domain)->class_init_trampoline_hash,
1001                                                                   vtable);
1002         mono_domain_unlock (domain);
1003         if (ptr)
1004                 return ptr;
1005
1006         code = mono_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, domain, NULL);
1007
1008         ptr = mono_create_ftnptr (domain, code);
1009
1010         /* store trampoline address */
1011         mono_domain_lock (domain);
1012         g_hash_table_insert (domain_jit_info (domain)->class_init_trampoline_hash,
1013                                                           vtable, ptr);
1014         mono_domain_unlock (domain);
1015
1016         mono_trampolines_lock ();
1017         if (!class_init_hash_addr)
1018                 class_init_hash_addr = g_hash_table_new (NULL, NULL);
1019         g_hash_table_insert (class_init_hash_addr, ptr, vtable);
1020         mono_trampolines_unlock ();
1021
1022         return ptr;
1023 }
1024
1025 gpointer
1026 mono_create_generic_class_init_trampoline (void)
1027 {
1028 #ifdef MONO_ARCH_VTABLE_REG
1029         static gpointer code;
1030
1031         mono_trampolines_lock ();
1032
1033         if (!code) {
1034                 if (mono_aot_only)
1035                         code = mono_aot_get_named_code ("generic_class_init_trampoline");
1036                 else
1037                         code = mono_arch_create_generic_class_init_trampoline ();
1038         }
1039
1040         mono_trampolines_unlock ();
1041
1042         return code;
1043 #else
1044         g_assert_not_reached ();
1045 #endif
1046 }
1047
1048 gpointer
1049 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
1050 {
1051         MonoJitInfo *ji;
1052         gpointer code;
1053         guint32 code_size = 0;
1054
1055         code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
1056         /*
1057          * We cannot recover the correct type of a shared generic
1058          * method from its native code address, so we use the
1059          * trampoline instead.
1060          */
1061         if (code && !ji->has_generic_jit_info)
1062                 return code;
1063
1064         mono_domain_lock (domain);
1065         code = g_hash_table_lookup (domain_jit_info (domain)->jump_trampoline_hash, method);
1066         mono_domain_unlock (domain);
1067         if (code)
1068                 return code;
1069
1070         code = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
1071         g_assert (code_size);
1072
1073         ji = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
1074         ji->code_start = code;
1075         ji->code_size = code_size;
1076         ji->method = method;
1077
1078         /*
1079          * mono_delegate_ctor needs to find the method metadata from the 
1080          * trampoline address, so we save it here.
1081          */
1082
1083         mono_jit_info_table_add (domain, ji);
1084
1085         mono_domain_lock (domain);
1086         g_hash_table_insert (domain_jit_info (domain)->jump_trampoline_hash, method, ji->code_start);
1087         mono_domain_unlock (domain);
1088
1089         return ji->code_start;
1090 }
1091
1092 gpointer
1093 mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
1094 {
1095         gpointer tramp;
1096
1097         if (mono_aot_only) {
1098                 /* Avoid creating trampolines if possible */
1099                 gpointer code = mono_jit_find_compiled_method (domain, method);
1100                 
1101                 if (code)
1102                         return code;
1103         }
1104
1105         mono_domain_lock (domain);
1106         tramp = g_hash_table_lookup (domain_jit_info (domain)->jit_trampoline_hash, method);
1107         mono_domain_unlock (domain);
1108         if (tramp)
1109                 return tramp;
1110
1111         tramp = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JIT, domain, NULL);
1112         
1113         mono_domain_lock (domain);
1114         g_hash_table_insert (domain_jit_info (domain)->jit_trampoline_hash, method, tramp);
1115         mono_domain_unlock (domain);
1116
1117         mono_jit_stats.method_trampolines++;
1118
1119         return tramp;
1120 }       
1121
1122 gpointer
1123 mono_create_jit_trampoline (MonoMethod *method)
1124 {
1125         return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
1126 }
1127
1128 gpointer
1129 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
1130 {
1131         gpointer tramp;
1132
1133         MonoDomain *domain = mono_domain_get ();
1134         guint8 *buf, *start;
1135
1136         buf = start = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
1137
1138         *(gpointer*)(gpointer)buf = image;
1139         buf += sizeof (gpointer);
1140         *(guint32*)(gpointer)buf = token;
1141
1142         tramp = mono_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
1143
1144         mono_jit_stats.method_trampolines++;
1145
1146         return tramp;
1147 }       
1148
1149 gpointer
1150 mono_create_delegate_trampoline (MonoClass *klass)
1151 {
1152 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
1153         MonoDomain *domain = mono_domain_get ();
1154         gpointer ptr;
1155         guint32 code_size = 0;
1156         gpointer *tramp_data;
1157         MonoMethod *invoke;
1158
1159         mono_domain_lock (domain);
1160         ptr = g_hash_table_lookup (domain_jit_info (domain)->delegate_trampoline_hash, klass);
1161         mono_domain_unlock (domain);
1162         if (ptr)
1163                 return ptr;
1164
1165         // Precompute the delegate invoke impl and pass it to the delegate trampoline
1166         invoke = mono_get_delegate_invoke (klass);
1167         g_assert (invoke);
1168
1169         tramp_data = mono_domain_alloc (domain, sizeof (gpointer) * 3);
1170         tramp_data [0] = invoke;
1171         tramp_data [1] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
1172         tramp_data [2] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
1173
1174         ptr = mono_create_specific_trampoline (tramp_data, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
1175         g_assert (code_size);
1176
1177         /* store trampoline address */
1178         mono_domain_lock (domain);
1179         g_hash_table_insert (domain_jit_info (domain)->delegate_trampoline_hash,
1180                                                           klass, ptr);
1181         mono_domain_unlock (domain);
1182
1183         return ptr;
1184 #else
1185         return NULL;
1186 #endif
1187 }
1188
1189 gpointer
1190 mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
1191 {
1192         static gboolean inited = FALSE;
1193         static int num_trampolines = 0;
1194
1195         gpointer tramp, ptr;
1196
1197         if (mono_aot_only)
1198                 return mono_aot_get_lazy_fetch_trampoline (offset);
1199
1200         mono_trampolines_lock ();
1201         if (rgctx_lazy_fetch_trampoline_hash)
1202                 tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
1203         else
1204                 tramp = NULL;
1205         mono_trampolines_unlock ();
1206         if (tramp)
1207                 return tramp;
1208
1209         tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset);
1210         ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
1211
1212         mono_trampolines_lock ();
1213         if (!rgctx_lazy_fetch_trampoline_hash) {
1214                 rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
1215                 rgctx_lazy_fetch_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
1216         }
1217         g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
1218         g_assert (offset != -1);
1219         g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr, ptr, GUINT_TO_POINTER (offset + 1));
1220         mono_trampolines_unlock ();
1221
1222         if (!inited) {
1223                 mono_counters_register ("RGCTX num lazy fetch trampolines",
1224                                 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
1225                 inited = TRUE;
1226         }
1227         num_trampolines++;
1228
1229         return ptr;
1230 }
1231
1232 gpointer
1233 mono_create_monitor_enter_trampoline (void)
1234 {
1235         static gpointer code;
1236
1237         if (mono_aot_only) {
1238                 if (!code)
1239                         code = mono_aot_get_named_code ("monitor_enter_trampoline");
1240                 return code;
1241         }
1242
1243 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1244         mono_trampolines_lock ();
1245
1246         if (!code)
1247                 code = mono_arch_create_monitor_enter_trampoline ();
1248
1249         mono_trampolines_unlock ();
1250 #else
1251         code = NULL;
1252         g_assert_not_reached ();
1253 #endif
1254
1255         return code;
1256 }
1257
1258 gpointer
1259 mono_create_monitor_exit_trampoline (void)
1260 {
1261         static gpointer code;
1262
1263         if (mono_aot_only) {
1264                 if (!code)
1265                         code = mono_aot_get_named_code ("monitor_exit_trampoline");
1266                 return code;
1267         }
1268
1269 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1270         mono_trampolines_lock ();
1271
1272         if (!code)
1273                 code = mono_arch_create_monitor_exit_trampoline ();
1274
1275         mono_trampolines_unlock ();
1276 #else
1277         code = NULL;
1278         g_assert_not_reached ();
1279 #endif
1280         return code;
1281 }
1282  
1283 #ifdef MONO_ARCH_LLVM_SUPPORTED
1284 /*
1285  * mono_create_llvm_vcall_trampoline:
1286  *
1287  *  LLVM emits code for virtual calls which mono_get_vcall_slot is unable to
1288  * decode, i.e. only the final branch address is available:
1289  * mov <offset>(%rax), %rax
1290  * <random code inserted by instruction scheduling>
1291  * call *%rax
1292  *
1293  * To work around this problem, we don't use the common vtable trampoline when
1294  * llvm is enabled. Instead, we use one trampoline per method.
1295  */
1296 gpointer
1297 mono_create_llvm_vcall_trampoline (MonoMethod *method)
1298 {
1299         MonoDomain *domain;
1300         gpointer res;
1301
1302         domain = mono_domain_get ();
1303
1304         mono_domain_lock (domain);
1305         res = g_hash_table_lookup (domain_jit_info (domain)->llvm_vcall_trampoline_hash, method);
1306         mono_domain_unlock (domain);
1307         if (res)
1308                 return res;
1309
1310         res = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_LLVM_VCALL, domain, NULL);
1311
1312         mono_domain_lock (domain);
1313         g_hash_table_insert (domain_jit_info (domain)->llvm_vcall_trampoline_hash, method, res);
1314         mono_domain_unlock (domain);
1315
1316         return res;
1317 }
1318
1319 /*
1320  * mono_create_llvm_imt_trampoline:
1321  *
1322  *   LLVM compiled code can't pass in the IMT argument, so we use this trampoline, which
1323  * sets the IMT argument, then branches to the contents of the vtable slot given by
1324  * vt_offset in the vtable which is obtained from the argument list.
1325  */
1326 gpointer
1327 mono_create_llvm_imt_trampoline (MonoDomain *domain, MonoMethod *m, int vt_offset)
1328 {
1329 #ifdef MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE
1330         return mono_arch_get_llvm_imt_trampoline (domain, m, vt_offset);
1331 #else
1332         g_assert_not_reached ();
1333         return NULL;
1334 #endif
1335 }
1336 #endif
1337
1338 MonoVTable*
1339 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
1340 {
1341         MonoVTable *res;
1342
1343         mono_trampolines_lock ();
1344         if (class_init_hash_addr)
1345                 res = g_hash_table_lookup (class_init_hash_addr, addr);
1346         else
1347                 res = NULL;
1348         mono_trampolines_unlock ();
1349         return res;
1350 }
1351
1352 guint32
1353 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr)
1354 {
1355         int offset;
1356
1357         mono_trampolines_lock ();
1358         if (rgctx_lazy_fetch_trampoline_hash_addr) {
1359                 /* We store the real offset + 1 so we can detect when the lookup fails */
1360                 offset = GPOINTER_TO_INT (g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash_addr, addr));
1361                 if (offset)
1362                         offset -= 1;
1363                 else
1364                         offset = -1;
1365         } else {
1366                 offset = -1;
1367         }
1368         mono_trampolines_unlock ();
1369         return offset;
1370 }