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