Merge pull request #717 from mono/client_websockets_impl
[mono.git] / mono / mini / mini-trampolines.c
1 /*
2  * (C) 2003 Ximian, Inc.
3  * (C) 2003-2011 Novell, Inc.
4  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
5  */
6 #include <config.h>
7 #include <glib.h>
8
9 #include <mono/metadata/appdomain.h>
10 #include <mono/metadata/metadata-internals.h>
11 #include <mono/metadata/marshal.h>
12 #include <mono/metadata/tabledefs.h>
13 #include <mono/utils/mono-counters.h>
14 #include <mono/utils/mono-error-internals.h>
15 #include <mono/utils/mono-membar.h>
16
17 #include "mini.h"
18 #include "debug-mini.h"
19
20 /*
21  * Address of the trampoline code.  This is used by the debugger to check
22  * whether a method is a trampoline.
23  */
24 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
25
26 static GHashTable *class_init_hash_addr = NULL;
27 static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
28 static GHashTable *rgctx_lazy_fetch_trampoline_hash_addr = NULL;
29 static guint32 trampoline_calls, jit_trampolines, unbox_trampolines, static_rgctx_trampolines;
30
31 #define mono_trampolines_lock() EnterCriticalSection (&trampolines_mutex)
32 #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex)
33 static CRITICAL_SECTION trampolines_mutex;
34
35 #ifdef MONO_ARCH_GSHARED_SUPPORTED
36
37 typedef struct {
38         MonoMethod *m;
39         gpointer addr;
40 } RgctxTrampInfo;
41
42 static gint
43 rgctx_tramp_info_equal (gconstpointer ka, gconstpointer kb)
44 {
45         const RgctxTrampInfo *i1 = ka;
46         const RgctxTrampInfo *i2 = kb;
47
48         if (i1->m == i2->m && i1->addr == i2->addr)
49                 return 1;
50         else
51                 return 0;
52 }
53
54 static guint
55 rgctx_tramp_info_hash (gconstpointer data)
56 {
57         const RgctxTrampInfo *info = data;
58
59         return GPOINTER_TO_UINT (info->m) ^ GPOINTER_TO_UINT (info->addr);
60 }
61
62 /*
63  * mono_create_static_rgctx_trampoline:
64  *
65  *   Return a static rgctx trampoline for M which branches to ADDR which should
66  * point to the compiled code of M.
67  *
68  *   Static rgctx trampolines are used when a shared generic method which doesn't
69  * have a this argument is called indirectly, ie. from code which can't pass in
70  * the rgctx argument. The trampoline sets the rgctx argument and jumps to the
71  * methods code. These trampolines are similar to the unbox trampolines, they
72  * perform the same task as the static rgctx wrappers, but they are smaller/faster,
73  * and can be made to work with full AOT.
74  * On PPC addr should be an ftnptr and the return value is an ftnptr too.
75  */
76 gpointer
77 mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
78 {
79         gpointer ctx;
80         gpointer res;
81         MonoDomain *domain;
82         RgctxTrampInfo tmp_info;
83         RgctxTrampInfo *info;
84
85 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
86         g_assert (((gpointer*)addr) [2] == 0);
87 #endif
88
89         ctx = mini_method_get_rgctx (m);
90
91         domain = mono_domain_get ();
92
93         /* 
94          * In the AOT case, addr might point to either the method, or to an unbox trampoline,
95          * so make the hash keyed on the m+addr pair.
96          */
97         mono_domain_lock (domain);
98         if (!domain_jit_info (domain)->static_rgctx_trampoline_hash)
99                 domain_jit_info (domain)->static_rgctx_trampoline_hash = g_hash_table_new (rgctx_tramp_info_hash, rgctx_tramp_info_equal);
100         tmp_info.m = m;
101         tmp_info.addr = addr;
102         res = g_hash_table_lookup (domain_jit_info (domain)->static_rgctx_trampoline_hash,
103                                                            &tmp_info);
104         mono_domain_unlock (domain);
105         if (res)
106                 return res;
107
108         if (mono_aot_only)
109                 res = mono_aot_get_static_rgctx_trampoline (ctx, addr);
110         else
111                 res = mono_arch_get_static_rgctx_trampoline (m, ctx, addr);
112
113         mono_domain_lock (domain);
114         /* Duplicates inserted while we didn't hold the lock are OK */
115         info = mono_domain_alloc (domain, sizeof (RgctxTrampInfo));
116         info->m = m;
117         info->addr = addr;
118         g_hash_table_insert (domain_jit_info (domain)->static_rgctx_trampoline_hash, info, res);
119         mono_domain_unlock (domain);
120
121         static_rgctx_trampolines ++;
122
123         return res;
124 }
125 #else
126 gpointer
127 mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr)
128 {
129        /* 
130         * This shouldn't happen as all arches which support generic sharing support
131         * static rgctx trampolines as well.
132         */
133        g_assert_not_reached ();
134 }
135 #endif
136
137 #ifdef MONO_ARCH_HAVE_IMT
138
139 /*
140  * Either IMPL_METHOD or AOT_ADDR will be set on return.
141  */
142 static gpointer*
143 #ifdef __GNUC__
144 /*
145  * This works against problems when compiling with gcc 4.6 on arm. The 'then' part of
146  * this line gets executed, even when the condition is false:
147  *              if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE))
148  *                      *need_rgctx_tramp = TRUE;
149  */
150 __attribute__ ((noinline))
151 #endif
152         mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, gboolean lookup_aot, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used, gpointer *aot_addr)
153 {
154         MonoObject *this_argument = mono_arch_get_this_arg_from_call (regs, code);
155         MonoVTable *vt = this_argument->vtable;
156         int displacement = slot - ((gpointer*)vt);
157
158         if (displacement > 0) {
159                 /* slot is in the vtable, not in the IMT */
160 #if DEBUG_IMT
161                 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p is in the vtable, not in the IMT\n", slot);
162 #endif
163                 return slot;
164         } else {
165                 MonoMethod *imt_method = mono_arch_find_imt_method (regs, code);
166                 MonoMethod *impl;
167                 int interface_offset;
168                 int imt_slot = MONO_IMT_SIZE + displacement;
169
170                 /*This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement*/
171                 interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, variance_used);
172
173                 if (interface_offset < 0) {
174                         g_error ("%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));
175                 }
176                 mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
177
178                 if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst) {
179                         MonoGenericContext context = { NULL, NULL };
180
181                         /* 
182                          * Generic virtual method, imt_method contains the inflated interface 
183                          * method, need to get the inflated impl method.
184                          */
185                         /* imt_method->slot might not be set */
186                         impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_declaring_generic_method (imt_method)->slot);
187
188                         if (impl->klass->generic_class)
189                                 context.class_inst = impl->klass->generic_class->context.class_inst;
190                         context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
191                         impl = mono_class_inflate_generic_method (impl, &context);
192                 } else {
193                         /* Avoid loading metadata or creating a generic vtable if possible */
194                         if (lookup_aot && !vt->klass->valuetype)
195                                 *aot_addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, interface_offset + mono_method_get_vtable_slot (imt_method));
196                         else
197                                 *aot_addr = NULL;
198                         if (*aot_addr)
199                                 impl = NULL;
200                         else
201                                 impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_vtable_slot (imt_method));
202                 }
203
204                 if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE))
205                         *need_rgctx_tramp = TRUE;
206                 if (impl && impl->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
207                         WrapperInfo *info = mono_marshal_get_wrapper_info (impl);
208
209                         if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) {
210                                 // FIXME: This needs a gsharedvt-out trampoline, since the caller uses the gsharedvt calling conv, but the
211                                 // wrapper is a normal non-generic method.
212                                 *need_rgctx_tramp = TRUE;
213                                 //g_assert_not_reached ();
214                         }
215                 }
216
217                 *impl_method = impl;
218 #if DEBUG_IMT
219                 printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
220                                 method->klass->name_space, method->klass->name, method->name, 
221                                 imt_method->klass->name_space, imt_method->klass->name, imt_method->name);
222 #endif
223
224                 g_assert (imt_slot < MONO_IMT_SIZE);
225                 if (vt->imt_collisions_bitmap & (1 << imt_slot)) {
226                         int slot = mono_method_get_vtable_index (imt_method);
227                         int vtable_offset;
228                         gpointer *vtable_slot;
229
230                         g_assert (slot != -1);
231                         vtable_offset = interface_offset + slot;
232                         vtable_slot = & (vt->vtable [vtable_offset]);
233 #if DEBUG_IMT
234                         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);
235 #endif
236                         return vtable_slot;
237                 } else {
238 #if DEBUG_IMT
239                         printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot);
240 #endif
241                         return slot;
242                 }
243         }
244 }
245 #endif
246
247 /*
248  * This is a super-ugly hack to fix bug #616463.
249  *
250  * The problem is that we don't always set is_generic for generic
251  * method definitions.  See the comment at the end of
252  * mono_class_inflate_generic_method_full_checked() in class.c.
253  */
254 static gboolean
255 is_generic_method_definition (MonoMethod *m)
256 {
257         MonoGenericContext *context;
258         if (m->is_generic)
259                 return TRUE;
260         if (!m->is_inflated)
261                 return FALSE;
262
263         context = mono_method_get_context (m);
264         if (!context->method_inst)
265                 return FALSE;
266         if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
267                 return TRUE;
268         return FALSE;
269 }
270
271 gboolean
272 mini_jit_info_is_gsharedvt (MonoJitInfo *ji)
273 {
274         if (ji && ji->has_generic_jit_info && (mono_jit_info_get_generic_sharing_context (ji)->var_is_vt ||
275                                                                                    mono_jit_info_get_generic_sharing_context (ji)->mvar_is_vt))
276                 return TRUE;
277         else
278                 return FALSE;
279 }
280
281 /*
282  * mini_add_method_trampoline:
283  *
284  *   Add static rgctx/gsharedvt_in/unbox trampolines to M/COMPILED_METHOD if needed. Return the trampoline address, or
285  * COMPILED_METHOD if no trampoline is needed.
286  * ORIG_METHOD is the method the caller originally called i.e. an iface method, or NULL.
287  */
288 gpointer
289 mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp)
290 {
291         gpointer addr = compiled_method;
292         gboolean callee_gsharedvt, callee_array_helper;
293         MonoMethod *jmethod = NULL;
294         MonoJitInfo *ji = 
295                 mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method), NULL);
296
297         // FIXME: This loads information from AOT
298         callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
299
300         callee_array_helper = FALSE;
301         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
302                 WrapperInfo *info = mono_marshal_get_wrapper_info (m);
303
304                 /*
305                  * generic array helpers.
306                  * Have to replace the wrappers with the original generic instances.
307                  */
308                 if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) {
309                         callee_array_helper = TRUE;
310                         m = info->d.generic_array_helper.method;
311                 }
312         } else if (m->wrapper_type == MONO_WRAPPER_UNKNOWN) {
313                 WrapperInfo *info = mono_marshal_get_wrapper_info (m);
314
315                 /* Same for synchronized inner wrappers */
316                 if (info && info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) {
317                         m = info->d.synchronized_inner.method;
318                 }
319         }
320
321         if (!orig_method)
322                 orig_method = m;
323
324         if (callee_gsharedvt)
325                 g_assert (m->is_inflated);
326
327         addr = compiled_method;
328
329         if (add_unbox_tramp) {
330                 /* 
331                  * The unbox trampolines call the method directly, so need to add
332                  * an rgctx tramp before them.
333                  */
334                 if (mono_aot_only) {
335                         addr = mono_aot_get_unbox_trampoline (m);
336                 } else {
337                         unbox_trampolines ++;
338                         addr = mono_arch_get_unbox_trampoline (m, addr);
339                 }
340         }
341
342         if (ji)
343                 jmethod = jinfo_get_method (ji);
344         if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) {
345                 MonoGenericSharingContext *gsctx;
346                 MonoMethodSignature *sig, *gsig;
347
348                 /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
349
350                 /* Call from normal/gshared code to gsharedvt code with variable signature */
351                 gsctx = mono_jit_info_get_generic_sharing_context (ji);
352
353                 sig = mono_method_signature (m);
354                 gsig = mono_method_signature (jmethod);
355
356                 addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, gsctx, -1, FALSE);
357
358                 //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
359         }
360
361         if (add_static_rgctx_tramp && !callee_array_helper)
362                 addr = mono_create_static_rgctx_trampoline (m, addr);
363
364         return addr;
365 }
366
367 /**
368  * common_call_trampoline:
369  *
370  *   The code to handle normal, virtual, and interface method calls and jumps, both
371  * from JITted and LLVM compiled code.
372  */
373 static gpointer
374 common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tramp, MonoVTable *vt, gpointer *vtable_slot, gboolean need_rgctx_tramp)
375 {
376         gpointer addr, compiled_method;
377         gboolean generic_shared = FALSE;
378         gboolean need_unbox_tramp = FALSE;
379         MonoMethod *declaring = NULL;
380         MonoMethod *generic_virtual = NULL, *variant_iface = NULL, *orig_method = NULL;
381         int context_used;
382         gboolean virtual, variance_used = FALSE;
383         gpointer *orig_vtable_slot, *vtable_slot_to_patch = NULL;
384         MonoJitInfo *ji = NULL;
385
386         virtual = (gpointer)vtable_slot > (gpointer)vt;
387
388         orig_vtable_slot = vtable_slot;
389         vtable_slot_to_patch = vtable_slot;
390
391 #ifdef MONO_ARCH_HAVE_IMT
392         /* IMT call */
393         if (vt && (gpointer)vtable_slot < (gpointer)vt) {
394                 MonoMethod *impl_method = NULL;
395                 MonoObject *this_arg;
396
397                 /* we get the interface method because mono_convert_imt_slot_to_vtable_slot ()
398                  * needs the signature to be able to find the this argument
399                  */
400                 m = mono_arch_find_imt_method (regs, code);
401                 vtable_slot = orig_vtable_slot;
402                 g_assert (vtable_slot);
403
404                 orig_method = m;
405
406                 this_arg = mono_arch_get_this_arg_from_call (regs, code);
407
408                 if (mono_object_is_transparent_proxy (this_arg)) {
409                         /* Use the slow path for now */
410                     m = mono_object_get_virtual_method (this_arg, m);
411                         vtable_slot_to_patch = NULL;
412                 } else {
413                         gboolean lookup_aot;
414
415                         if (m->is_inflated && ((MonoMethodInflated*)m)->context.method_inst) {
416                                 /* Generic virtual method */
417                                 generic_virtual = m;
418                                 need_rgctx_tramp = TRUE;
419                         } else if (variance_used && mono_class_has_variant_generic_params (m->klass)) {
420                                 variant_iface = m;
421                         }
422
423                         addr = NULL;
424                         /* We can only use the AOT compiled code if we don't require further processing */
425                         lookup_aot = !generic_virtual & !variant_iface;
426                         vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, lookup_aot, &impl_method, &need_rgctx_tramp, &variance_used, &addr);
427                         /* This is the vcall slot which gets called through the IMT thunk */
428                         vtable_slot_to_patch = vtable_slot;
429                         /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
430                          * to be called, so we compile it and go ahead as usual.
431                          */
432                         /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
433
434                         if (addr) {
435                                 /*
436                                  * We found AOT compiled code for the method, skip the rest.
437                                  */
438                                 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
439                                         *vtable_slot = addr;
440
441                                 return mono_create_ftnptr (mono_domain_get (), addr);
442                         }
443
444                         m = impl_method;
445                 }
446         }
447 #endif
448
449         /*
450          * The virtual check is needed because is_generic_method_definition (m) could
451          * return TRUE for methods used in IMT calls too.
452          */
453         if (virtual && is_generic_method_definition (m)) {
454                 MonoGenericContext context = { NULL, NULL };
455                 MonoMethod *declaring;
456
457                 if (m->is_inflated)
458                         declaring = mono_method_get_declaring_generic_method (m);
459                 else
460                         declaring = m;
461
462                 if (m->klass->generic_class)
463                         context.class_inst = m->klass->generic_class->context.class_inst;
464                 else
465                         g_assert (!m->klass->generic_container);
466
467 #ifdef MONO_ARCH_HAVE_IMT
468                 generic_virtual = mono_arch_find_imt_method (regs, code);
469 #endif
470                 if (generic_virtual) {
471                         g_assert (generic_virtual->is_inflated);
472                         context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
473                 }
474
475                 m = mono_class_inflate_generic_method (declaring, &context);
476                 /* FIXME: only do this if the method is sharable */
477                 need_rgctx_tramp = TRUE;
478         } else if ((context_used = mono_method_check_context_used (m))) {
479                 MonoClass *klass = NULL;
480                 MonoMethod *actual_method = NULL;
481                 MonoVTable *vt = NULL;
482                 MonoGenericInst *method_inst = NULL;
483
484                 vtable_slot = NULL;
485                 generic_shared = TRUE;
486
487                 g_assert (code);
488
489                 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
490 #ifdef MONO_ARCH_RGCTX_REG
491                         MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext*)mono_arch_find_static_call_vtable (regs, code);
492
493                         klass = mrgctx->class_vtable->klass;
494                         method_inst = mrgctx->method_inst;
495 #else
496                         g_assert_not_reached ();
497 #endif
498                 } else if ((m->flags & METHOD_ATTRIBUTE_STATIC) || m->klass->valuetype) {
499 #ifdef MONO_ARCH_RGCTX_REG
500                         MonoVTable *vtable = mono_arch_find_static_call_vtable (regs, code);
501
502                         klass = vtable->klass;
503 #else
504                         g_assert_not_reached ();
505 #endif
506                 } else {
507 #ifdef MONO_ARCH_HAVE_IMT
508                         MonoObject *this_argument = mono_arch_get_this_arg_from_call (regs, code);
509
510                         vt = this_argument->vtable;
511                         vtable_slot = orig_vtable_slot;
512
513                         g_assert (this_argument->vtable->klass->inited);
514                         //mono_class_init (this_argument->vtable->klass);
515
516                         if (!vtable_slot) {
517                                 mono_class_setup_supertypes (this_argument->vtable->klass);
518                                 klass = this_argument->vtable->klass->supertypes [m->klass->idepth - 1];
519                         }
520 #else
521                         NOT_IMPLEMENTED;
522 #endif
523                 }
524
525                 g_assert (vtable_slot || klass);
526
527                 if (vtable_slot) {
528                         int displacement = vtable_slot - ((gpointer*)vt);
529
530                         g_assert_not_reached ();
531
532                         g_assert (displacement > 0);
533
534                         actual_method = vt->klass->vtable [displacement];
535                 }
536
537                 if (method_inst || m->wrapper_type) {
538                         MonoGenericContext context = { NULL, NULL };
539
540                         if (m->is_inflated)
541                                 declaring = mono_method_get_declaring_generic_method (m);
542                         else
543                                 declaring = m;
544
545                         if (klass->generic_class)
546                                 context.class_inst = klass->generic_class->context.class_inst;
547                         else if (klass->generic_container)
548                                 context.class_inst = klass->generic_container->context.class_inst;
549                         context.method_inst = method_inst;
550
551                         actual_method = mono_class_inflate_generic_method (declaring, &context);
552                 } else {
553                         actual_method = mono_class_get_method_generic (klass, m);
554                 }
555
556                 g_assert (klass);
557                 g_assert (actual_method);
558                 g_assert (actual_method->klass == klass);
559
560                 if (actual_method->is_inflated)
561                         declaring = mono_method_get_declaring_generic_method (actual_method);
562                 else
563                         declaring = NULL;
564
565                 m = actual_method;
566         }
567
568         if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
569                 m = mono_marshal_get_synchronized_wrapper (m);
570                 need_rgctx_tramp = FALSE;
571         }
572
573         /* Calls made through delegates on platforms without delegate trampolines */
574         if (!code && mono_method_needs_static_rgctx_invoke (m, FALSE))
575                 need_rgctx_tramp = TRUE;
576
577         addr = compiled_method = mono_compile_method (m);
578         g_assert (addr);
579
580         mono_debugger_trampoline_compiled (code, m, addr);
581
582         if (generic_virtual || variant_iface) {
583                 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
584                         need_unbox_tramp = TRUE;
585         } else if (orig_vtable_slot) {
586                 if (m->klass->valuetype)
587                         need_unbox_tramp = TRUE;
588         }
589
590         addr = mini_add_method_trampoline (orig_method, m, compiled_method, need_rgctx_tramp, need_unbox_tramp);
591
592         if (generic_virtual || variant_iface) {
593                 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
594
595                 vtable_slot = orig_vtable_slot;
596                 g_assert (vtable_slot);
597
598                 mono_method_add_generic_virtual_invocation (mono_domain_get (), 
599                                                                                                         vt, vtable_slot,
600                                                                                                         target, addr);
601
602                 return addr;
603         }
604
605         /* the method was jumped to */
606         if (!code) {
607                 MonoDomain *domain = mono_domain_get ();
608
609                 /* Patch the got entries pointing to this method */
610                 /* 
611                  * We do this here instead of in mono_codegen () to cover the case when m
612                  * was loaded from an aot image.
613                  */
614                 if (domain_jit_info (domain)->jump_target_got_slot_hash) {
615                         GSList *list, *tmp;
616
617                         mono_domain_lock (domain);
618                         list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_got_slot_hash, m);
619                         if (list) {
620                                 for (tmp = list; tmp; tmp = tmp->next) {
621                                         gpointer *got_slot = tmp->data;
622                                         *got_slot = addr;
623                                 }
624                                 g_hash_table_remove (domain_jit_info (domain)->jump_target_got_slot_hash, m);
625                                 g_slist_free (list);
626                         }
627                         mono_domain_unlock (domain);
628                 }
629
630                 return addr;
631         }
632
633         vtable_slot = orig_vtable_slot;
634
635         if (vtable_slot) {
636                 if (vtable_slot_to_patch && (mono_aot_is_got_entry (code, (guint8*)vtable_slot_to_patch) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot_to_patch))) {
637                         g_assert (*vtable_slot_to_patch);
638                         *vtable_slot_to_patch = mono_get_addr_from_ftnptr (addr);
639                 }
640         }
641         else {
642                 guint8 *plt_entry = mono_aot_get_plt_entry (code);
643                 gboolean no_patch = FALSE;
644                 MonoJitInfo *target_ji;
645
646                 if (plt_entry) {
647                         if (generic_shared) {
648                                 target_ji =
649                                         mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method), NULL);
650                                 if (!ji)
651                                         ji = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
652
653                                 if (ji && target_ji && generic_shared && ji->has_generic_jit_info && !target_ji->has_generic_jit_info) {
654                                         no_patch = TRUE;
655                                 }
656                         }
657                         if (!no_patch)
658                                 mono_aot_patch_plt_entry (plt_entry, NULL, regs, addr);
659                 } else {
660                         if (generic_shared) {
661                                 if (m->wrapper_type != MONO_WRAPPER_NONE)
662                                         m = mono_marshal_method_from_wrapper (m);
663                                 //g_assert (mono_method_is_generic_sharable (m, FALSE));
664                         }
665
666                         /* Patch calling code */
667                         target_ji =
668                                 mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method), NULL);
669                         if (!ji)
670                                 ji = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL);
671
672                         if (ji && target_ji && generic_shared && ji->has_generic_jit_info && !target_ji->has_generic_jit_info) {
673                                 /* 
674                                  * Can't patch the call as the caller is gshared, but the callee is not. Happens when
675                                  * generic sharing fails.
676                                  * FIXME: Performance problem.
677                                  */
678                                 no_patch = TRUE;
679                         }
680
681                         if (!no_patch && mono_method_same_domain (ji, target_ji))
682                                 mono_arch_patch_callsite (ji->code_start, code, addr);
683                 }
684         }
685
686         return addr;
687 }
688
689 /**
690  * mono_magic_trampoline:
691  *
692  *   This trampoline handles normal calls from JITted code.
693  */
694 gpointer
695 mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp)
696 {
697         trampoline_calls ++;
698
699         return common_call_trampoline (regs, code, arg, tramp, NULL, NULL, FALSE);
700 }
701
702 /*
703  * mono_vcall_trampoline:
704  *
705  *   This trampoline handles virtual calls.
706  */
707 static gpointer
708 mono_vcall_trampoline (mgreg_t *regs, guint8 *code, int slot, guint8 *tramp)
709 {
710         MonoObject *this;
711         MonoVTable *vt;
712         gpointer *vtable_slot;
713         MonoMethod *m;
714         gboolean need_rgctx_tramp = FALSE;
715         gpointer addr;
716
717         trampoline_calls ++;
718
719         /*
720          * We need to obtain the following pieces of information:
721          * - the method which needs to be compiled.
722          * - the vtable slot.
723          * We use one vtable trampoline per vtable slot index, so we need only the vtable,
724          * the other two can be computed from the vtable + the slot index.
725          */
726 #ifndef MONO_ARCH_THIS_AS_FIRST_ARG
727         /* All architectures should support this */
728         g_assert_not_reached ();
729 #endif
730
731         /*
732          * Obtain the vtable from the 'this' arg.
733          */
734         this = mono_arch_get_this_arg_from_call (regs, code);
735         g_assert (this);
736
737         vt = this->vtable;
738
739         if (slot >= 0) {
740                 /* Normal virtual call */
741                 vtable_slot = &(vt->vtable [slot]);
742
743                 /* Avoid loading metadata or creating a generic vtable if possible */
744                 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
745                 if (addr && !vt->klass->valuetype) {
746                         if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))
747                                 *vtable_slot = addr;
748
749                         return mono_create_ftnptr (mono_domain_get (), addr);
750                 }
751
752                 /*
753                  * Bug #616463 (see
754                  * is_generic_method_definition() above) also
755                  * goes away if we do a
756                  * mono_class_setup_vtable (vt->klass) here,
757                  * because we then inflate the method
758                  * correctly, put it in the cache, and the
759                  * "wrong" inflation invocation still looks up
760                  * the correctly inflated method.
761                  *
762                  * The hack above seems more stable and
763                  * trustworthy.
764                  */
765                 m = mono_class_get_vtable_entry (vt->klass, slot);
766
767                 need_rgctx_tramp = mono_method_needs_static_rgctx_invoke (m, 0);
768         } else {
769                 /* IMT call */
770                 vtable_slot = &(((gpointer*)vt) [slot]);
771
772                 m = NULL;
773                 need_rgctx_tramp = FALSE;
774         }
775
776         return common_call_trampoline (regs, code, m, tramp, vt, vtable_slot, need_rgctx_tramp);
777 }
778
779 #ifndef DISABLE_REMOTING
780 gpointer
781 mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
782 {
783         MonoGenericContext context = { NULL, NULL };
784         MonoMethod *imt_method, *declaring;
785         gpointer addr;
786
787         trampoline_calls ++;
788
789         g_assert (m->is_generic);
790
791         if (m->is_inflated)
792                 declaring = mono_method_get_declaring_generic_method (m);
793         else
794                 declaring = m;
795
796         if (m->klass->generic_class)
797                 context.class_inst = m->klass->generic_class->context.class_inst;
798         else
799                 g_assert (!m->klass->generic_container);
800
801 #ifdef MONO_ARCH_HAVE_IMT
802         imt_method = mono_arch_find_imt_method (regs, code);
803         if (imt_method->is_inflated)
804                 context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst;
805 #endif
806         m = mono_class_inflate_generic_method (declaring, &context);
807         m = mono_marshal_get_remoting_invoke_with_check (m);
808
809         addr = mono_compile_method (m);
810         g_assert (addr);
811
812         mono_debugger_trampoline_compiled (NULL, m, addr);
813
814         return addr;
815 }
816 #endif
817
818 /*
819  * mono_aot_trampoline:
820  *
821  *   This trampoline handles calls made from AOT code. We try to bypass the 
822  * normal JIT compilation logic to avoid loading the metadata for the method.
823  */
824 #ifdef MONO_ARCH_AOT_SUPPORTED
825 gpointer
826 mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info, 
827                                          guint8* tramp)
828 {
829         MonoImage *image;
830         guint32 token;
831         MonoMethod *method = NULL;
832         gpointer addr;
833         guint8 *plt_entry;
834
835         trampoline_calls ++;
836
837         image = *(gpointer*)(gpointer)token_info;
838         token_info += sizeof (gpointer);
839         token = *(guint32*)(gpointer)token_info;
840
841         addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
842         if (!addr) {
843                 method = mono_get_method (image, token, NULL);
844                 g_assert (method);
845
846                 /* Use the generic code */
847                 return mono_magic_trampoline (regs, code, method, tramp);
848         }
849
850         addr = mono_create_ftnptr (mono_domain_get (), addr);
851
852         /* This is a normal call through a PLT entry */
853         plt_entry = mono_aot_get_plt_entry (code);
854         g_assert (plt_entry);
855
856         mono_aot_patch_plt_entry (plt_entry, NULL, regs, addr);
857
858         return addr;
859 }
860
861 /*
862  * mono_aot_plt_trampoline:
863  *
864  *   This trampoline handles calls made from AOT code through the PLT table.
865  */
866 gpointer
867 mono_aot_plt_trampoline (mgreg_t *regs, guint8 *code, guint8 *aot_module, 
868                                                  guint8* tramp)
869 {
870         guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code);
871         gpointer res;
872
873         trampoline_calls ++;
874
875         res = mono_aot_plt_resolve (aot_module, plt_info_offset, code);
876         if (!res) {
877                 if (mono_loader_get_last_error ())
878                         mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));
879                 // FIXME: Error handling (how ?)
880                 g_assert (res);
881         }
882
883         return res;
884 }
885 #endif
886
887 /**
888  * mono_class_init_trampoline:
889  *
890  * This method calls mono_runtime_class_init () to run the static constructor
891  * for the type, then patches the caller code so it is not called again.
892  */
893 void
894 mono_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
895 {
896         guint8 *plt_entry = mono_aot_get_plt_entry (code);
897
898         trampoline_calls ++;
899
900         mono_runtime_class_init (vtable);
901
902         if (plt_entry) {
903                 mono_arch_nullify_plt_entry (plt_entry, regs);
904         } else {
905                 mono_arch_nullify_class_init_trampoline (code, regs);
906         }
907 }
908
909 /**
910  * mono_generic_class_init_trampoline:
911  *
912  * This method calls mono_runtime_class_init () to run the static constructor
913  * for the type.
914  */
915 void
916 mono_generic_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
917 {
918         trampoline_calls ++;
919
920         mono_runtime_class_init (vtable);
921 }
922
923 static gpointer
924 mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, guint8 *tramp)
925 {
926 #ifdef MONO_ARCH_VTABLE_REG
927         static gboolean inited = FALSE;
928         static int num_lookups = 0;
929         guint32 slot = GPOINTER_TO_UINT (data);
930         mgreg_t *r = (mgreg_t*)regs;
931         gpointer arg = (gpointer)(gssize)r [MONO_ARCH_VTABLE_REG];
932         guint32 index = MONO_RGCTX_SLOT_INDEX (slot);
933         gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
934
935         trampoline_calls ++;
936
937         if (!inited) {
938                 mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_lookups);
939                 inited = TRUE;
940         }
941
942         num_lookups++;
943
944         if (mrgctx)
945                 return mono_method_fill_runtime_generic_context (arg, code, index);
946         else
947                 return mono_class_fill_runtime_generic_context (arg, code, index);
948 #else
949         g_assert_not_reached ();
950 #endif
951 }
952
953 void
954 mono_monitor_enter_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
955 {
956         mono_monitor_enter (obj);
957 }
958
959 void
960 mono_monitor_exit_trampoline (mgreg_t *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
961 {
962         mono_monitor_exit (obj);
963 }
964
965 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
966
967 /**
968  * mono_delegate_trampoline:
969  *
970  *   This trampoline handles calls made to Delegate:Invoke ().
971  * This is called once the first time a delegate is invoked, so it must be fast.
972  */
973 gpointer
974 mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
975 {
976         MonoDomain *domain = mono_domain_get ();
977         MonoDelegate *delegate;
978         MonoJitInfo *ji;
979         MonoMethod *m;
980         MonoMethod *method = NULL;
981         gboolean multicast, callvirt = FALSE;
982         gboolean need_rgctx_tramp = FALSE;
983         gboolean need_unbox_tramp = FALSE;
984         gboolean enable_caching = TRUE;
985         MonoMethod *invoke = tramp_data [0];
986         guint8 *impl_this = tramp_data [1];
987         guint8 *impl_nothis = tramp_data [2];
988         MonoError err;
989         MonoMethodSignature *sig;
990         gpointer addr, compiled_method;
991
992         trampoline_calls ++;
993
994         /* Obtain the delegate object according to the calling convention */
995         delegate = mono_arch_get_this_arg_from_call (regs, code);
996
997         if (delegate->method) {
998                 method = delegate->method;
999
1000                 /*
1001                  * delegate->method_ptr == NULL means the delegate was initialized by 
1002                  * mini_delegate_ctor, while != NULL means it is initialized by 
1003                  * mono_delegate_ctor_with_method (). In both cases, we need to add wrappers
1004                  * (ctor_with_method () does this, but it doesn't store the wrapper back into
1005                  * delegate->method).
1006                  */
1007 #ifndef DISABLE_REMOTING
1008                 if (delegate->target && delegate->target->vtable->klass == mono_defaults.transparent_proxy_class) {
1009 #ifndef DISABLE_COM
1010                         if (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class != mono_class_get_com_object_class () &&
1011                            !mono_class_is_com_object (((MonoTransparentProxy *)delegate->target)->remote_class->proxy_class))
1012 #endif
1013                                 method = mono_marshal_get_remoting_invoke (method);
1014                 } else
1015 #endif
1016                 {
1017                         mono_error_init (&err);
1018                         sig = mono_method_signature_checked (method, &err);
1019                         if (!sig)
1020                                 mono_error_raise_exception (&err);
1021                                 
1022                         if (sig->hasthis && method->klass->valuetype) {
1023                                 if (mono_aot_only)
1024                                         need_unbox_tramp = TRUE;
1025                                 else
1026                                         method = mono_marshal_get_unbox_wrapper (method);
1027                         }
1028                 }
1029         } else {
1030                 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr));
1031                 if (ji)
1032                         method = jinfo_get_method (ji);
1033         }
1034
1035         if (method) {
1036                 mono_error_init (&err);
1037                 sig = mono_method_signature_checked (method, &err);
1038                 if (!sig)
1039                         mono_error_raise_exception (&err);
1040
1041                 callvirt = !delegate->target && sig->hasthis;
1042                 if (delegate->target && 
1043                         method->flags & METHOD_ATTRIBUTE_VIRTUAL && 
1044                         method->flags & METHOD_ATTRIBUTE_ABSTRACT &&
1045                         method->klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1046                         method = mono_object_get_virtual_method (delegate->target, method);
1047                         enable_caching = FALSE;
1048                 }
1049         }
1050
1051         if (method && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
1052                 method = mono_marshal_get_synchronized_wrapper (method);
1053
1054         if (method && mono_method_needs_static_rgctx_invoke (method, FALSE))
1055                 need_rgctx_tramp = TRUE;
1056
1057         /* 
1058          * If the called address is a trampoline, replace it with the compiled method so
1059          * further calls don't have to go through the trampoline.
1060          */
1061         if (method && !callvirt) {
1062                 /* Avoid the overhead of looking up an already compiled method if possible */
1063                 if (enable_caching && delegate->method_code && *delegate->method_code) {
1064                         delegate->method_ptr = *delegate->method_code;
1065                 } else {
1066                         compiled_method = addr = mono_compile_method (method);
1067                         addr = mini_add_method_trampoline (NULL, method, compiled_method, need_rgctx_tramp, need_unbox_tramp);
1068                         delegate->method_ptr = addr;
1069                         if (enable_caching && delegate->method_code)
1070                                 *delegate->method_code = delegate->method_ptr;
1071                         mono_debugger_trampoline_compiled (NULL, method, delegate->method_ptr);
1072                 }
1073         } else {
1074                 if (need_rgctx_tramp)
1075                         delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr);
1076         }
1077
1078         multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL;
1079         if (!multicast && !callvirt) {
1080                 if (method && (method->flags & METHOD_ATTRIBUTE_STATIC) && mono_method_signature (method)->param_count == mono_method_signature (invoke)->param_count + 1)
1081                         /* Closed static delegate */
1082                         code = impl_this;
1083                 else
1084                         code = delegate->target ? impl_this : impl_nothis;
1085
1086                 if (code) {
1087                         delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
1088                         return code;
1089                 }
1090         }
1091
1092         /* The general, unoptimized case */
1093         m = mono_marshal_get_delegate_invoke (invoke, delegate);
1094         code = mono_compile_method (m);
1095         code = mini_add_method_trampoline (NULL, m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
1096         delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
1097         mono_debugger_trampoline_compiled (NULL, m, delegate->invoke_impl);
1098
1099         return code;
1100 }
1101
1102 #endif
1103
1104 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
1105 static gpointer
1106 mono_handler_block_guard_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
1107 {
1108         MonoContext ctx;
1109         MonoException *exc;
1110         MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
1111         gpointer resume_ip = jit_tls->handler_block_return_address;
1112
1113         memcpy (&ctx, &jit_tls->handler_block_context, sizeof (MonoContext));
1114         MONO_CONTEXT_SET_IP (&ctx, jit_tls->handler_block_return_address);
1115
1116         jit_tls->handler_block_return_address = NULL;
1117         jit_tls->handler_block = NULL;
1118
1119         if (!resume_ip) /*this should not happen, but we should avoid crashing */
1120                 exc = mono_get_exception_execution_engine ("Invalid internal state, resuming abort after handler block but no resume ip found");
1121         else
1122                 exc = mono_thread_resume_interruption ();
1123
1124         if (exc) {
1125                 static void (*restore_context) (MonoContext *);
1126
1127                 if (!restore_context)
1128                         restore_context = mono_get_restore_context ();
1129
1130                 mono_handle_exception (&ctx, exc);
1131                 restore_context (&ctx);
1132         }
1133
1134         return resume_ip;
1135 }
1136
1137 gpointer
1138 mono_create_handler_block_trampoline (void)
1139 {
1140         static gpointer code;
1141         if (code) {
1142                 mono_memory_barrier ();
1143                 return code;
1144         }
1145
1146
1147         if (mono_aot_only) {
1148                 g_assert (0);
1149                 return code;
1150         }
1151
1152         mono_trampolines_lock ();
1153
1154         if (!code) {
1155                 gpointer tmp = mono_arch_create_handler_block_trampoline ();
1156                 mono_memory_barrier ();
1157                 code = tmp;
1158         }
1159         mono_trampolines_unlock ();
1160
1161         return code;
1162 }
1163 #endif
1164
1165 /*
1166  * mono_get_trampoline_func:
1167  *
1168  *   Return the C function which needs to be called by the generic trampoline of type
1169  * TRAMP_TYPE.
1170  */
1171 gconstpointer
1172 mono_get_trampoline_func (MonoTrampolineType tramp_type)
1173 {
1174         switch (tramp_type) {
1175         case MONO_TRAMPOLINE_JIT:
1176         case MONO_TRAMPOLINE_JUMP:
1177                 return mono_magic_trampoline;
1178         case MONO_TRAMPOLINE_CLASS_INIT:
1179                 return mono_class_init_trampoline;
1180         case MONO_TRAMPOLINE_GENERIC_CLASS_INIT:
1181                 return mono_generic_class_init_trampoline;
1182         case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH:
1183                 return mono_rgctx_lazy_fetch_trampoline;
1184 #ifdef MONO_ARCH_AOT_SUPPORTED
1185         case MONO_TRAMPOLINE_AOT:
1186                 return mono_aot_trampoline;
1187         case MONO_TRAMPOLINE_AOT_PLT:
1188                 return mono_aot_plt_trampoline;
1189 #endif
1190 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
1191         case MONO_TRAMPOLINE_DELEGATE:
1192                 return mono_delegate_trampoline;
1193 #endif
1194         case MONO_TRAMPOLINE_RESTORE_STACK_PROT:
1195                 return mono_altstack_restore_prot;
1196 #ifndef DISABLE_REMOTING
1197         case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING:
1198                 return mono_generic_virtual_remoting_trampoline;
1199 #endif
1200         case MONO_TRAMPOLINE_MONITOR_ENTER:
1201                 return mono_monitor_enter_trampoline;
1202         case MONO_TRAMPOLINE_MONITOR_EXIT:
1203                 return mono_monitor_exit_trampoline;
1204         case MONO_TRAMPOLINE_VCALL:
1205                 return mono_vcall_trampoline;
1206 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
1207         case MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD:
1208                 return mono_handler_block_guard_trampoline;
1209 #endif
1210         default:
1211                 g_assert_not_reached ();
1212                 return NULL;
1213         }
1214 }
1215
1216 static guchar*
1217 create_trampoline_code (MonoTrampolineType tramp_type)
1218 {
1219         MonoTrampInfo *info;
1220         guchar *code;
1221
1222         code = mono_arch_create_generic_trampoline (tramp_type, &info, FALSE);
1223         if (info) {
1224                 mono_save_trampoline_xdebug_info (info);
1225                 if (mono_jit_map_is_enabled ())
1226                         mono_emit_jit_tramp (info->code, info->code_size, info->name);
1227                 mono_tramp_info_free (info);
1228         }
1229
1230         return code;
1231 }
1232
1233 void
1234 mono_trampolines_init (void)
1235 {
1236         InitializeCriticalSection (&trampolines_mutex);
1237
1238         if (mono_aot_only)
1239                 return;
1240
1241         mono_trampoline_code [MONO_TRAMPOLINE_JIT] = create_trampoline_code (MONO_TRAMPOLINE_JIT);
1242         mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = create_trampoline_code (MONO_TRAMPOLINE_JUMP);
1243         mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
1244         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
1245         mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
1246 #ifdef MONO_ARCH_AOT_SUPPORTED
1247         mono_trampoline_code [MONO_TRAMPOLINE_AOT] = create_trampoline_code (MONO_TRAMPOLINE_AOT);
1248         mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
1249 #endif
1250 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
1251         mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
1252 #endif
1253         mono_trampoline_code [MONO_TRAMPOLINE_RESTORE_STACK_PROT] = create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT);
1254 #ifndef DISABLE_REMOTING
1255         mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING);
1256 #endif
1257         mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
1258         mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
1259         mono_trampoline_code [MONO_TRAMPOLINE_VCALL] = create_trampoline_code (MONO_TRAMPOLINE_VCALL);
1260 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
1261         mono_trampoline_code [MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD] = create_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD);
1262         mono_create_handler_block_trampoline ();
1263 #endif
1264
1265         mono_counters_register ("Calls to trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &trampoline_calls);
1266         mono_counters_register ("JIT trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &jit_trampolines);
1267         mono_counters_register ("Unbox trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unbox_trampolines);
1268         mono_counters_register ("Static rgctx trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &static_rgctx_trampolines);
1269 }
1270
1271 void
1272 mono_trampolines_cleanup (void)
1273 {
1274         if (class_init_hash_addr)
1275                 g_hash_table_destroy (class_init_hash_addr);
1276         if (rgctx_lazy_fetch_trampoline_hash)
1277                 g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash);
1278         if (rgctx_lazy_fetch_trampoline_hash_addr)
1279                 g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash_addr);
1280
1281         DeleteCriticalSection (&trampolines_mutex);
1282 }
1283
1284 guint8 *
1285 mono_get_trampoline_code (MonoTrampolineType tramp_type)
1286 {
1287         g_assert (mono_trampoline_code [tramp_type]);
1288
1289         return mono_trampoline_code [tramp_type];
1290 }
1291
1292 gpointer
1293 mono_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
1294 {
1295         if (mono_aot_only)
1296                 return mono_aot_create_specific_trampoline (mono_defaults.corlib, arg1, tramp_type, domain, code_len);
1297         else
1298                 return mono_arch_create_specific_trampoline (arg1, tramp_type, domain, code_len);
1299 }
1300
1301 gpointer
1302 mono_create_class_init_trampoline (MonoVTable *vtable)
1303 {
1304         gpointer code, ptr;
1305         MonoDomain *domain = vtable->domain;
1306
1307         g_assert (!vtable->klass->generic_container);
1308
1309         /* previously created trampoline code */
1310         mono_domain_lock (domain);
1311         ptr = 
1312                 g_hash_table_lookup (domain_jit_info (domain)->class_init_trampoline_hash,
1313                                                                   vtable);
1314         mono_domain_unlock (domain);
1315         if (ptr)
1316                 return ptr;
1317
1318         code = mono_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, domain, NULL);
1319
1320         ptr = mono_create_ftnptr (domain, code);
1321
1322         /* store trampoline address */
1323         mono_domain_lock (domain);
1324         g_hash_table_insert (domain_jit_info (domain)->class_init_trampoline_hash,
1325                                                           vtable, ptr);
1326         mono_domain_unlock (domain);
1327
1328         mono_trampolines_lock ();
1329         if (!class_init_hash_addr)
1330                 class_init_hash_addr = g_hash_table_new (NULL, NULL);
1331         g_hash_table_insert (class_init_hash_addr, ptr, vtable);
1332         mono_trampolines_unlock ();
1333
1334         return ptr;
1335 }
1336
1337 gpointer
1338 mono_create_generic_class_init_trampoline (void)
1339 {
1340 #ifdef MONO_ARCH_VTABLE_REG
1341         static gpointer code;
1342         MonoTrampInfo *info;
1343
1344         mono_trampolines_lock ();
1345
1346         if (!code) {
1347                 if (mono_aot_only)
1348                         /* get_named_code () might return an ftnptr, but our caller expects a direct pointer */
1349                         code = mono_get_addr_from_ftnptr (mono_aot_get_trampoline ("generic_class_init_trampoline"));
1350                 else {
1351                         code = mono_arch_create_generic_class_init_trampoline (&info, FALSE);
1352
1353                         if (info) {
1354                                 mono_save_trampoline_xdebug_info (info);
1355                                 if (mono_jit_map_is_enabled ())
1356                                         mono_emit_jit_tramp (info->code, info->code_size, info->name);
1357                                 mono_tramp_info_free (info);
1358                         }
1359                 }
1360         }
1361
1362         mono_trampolines_unlock ();
1363
1364         return code;
1365 #else
1366         g_assert_not_reached ();
1367 #endif
1368 }
1369
1370 gpointer
1371 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
1372 {
1373         MonoJitInfo *ji;
1374         gpointer code;
1375         guint32 code_size = 0;
1376
1377         code = mono_jit_find_compiled_method_with_jit_info (domain, method, &ji);
1378         /*
1379          * We cannot recover the correct type of a shared generic
1380          * method from its native code address, so we use the
1381          * trampoline instead.
1382          * For synchronized methods, the trampoline adds the wrapper.
1383          */
1384         if (code && !ji->has_generic_jit_info && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED))
1385                 return code;
1386
1387         mono_domain_lock (domain);
1388         code = g_hash_table_lookup (domain_jit_info (domain)->jump_trampoline_hash, method);
1389         mono_domain_unlock (domain);
1390         if (code)
1391                 return code;
1392
1393         code = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
1394         g_assert (code_size);
1395
1396         ji = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO);
1397         ji->code_start = code;
1398         ji->code_size = code_size;
1399         ji->d.method = method;
1400
1401         /*
1402          * mono_delegate_ctor needs to find the method metadata from the 
1403          * trampoline address, so we save it here.
1404          */
1405
1406         mono_jit_info_table_add (domain, ji);
1407
1408         mono_domain_lock (domain);
1409         g_hash_table_insert (domain_jit_info (domain)->jump_trampoline_hash, method, ji->code_start);
1410         mono_domain_unlock (domain);
1411
1412         return ji->code_start;
1413 }
1414
1415 gpointer
1416 mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
1417 {
1418         gpointer tramp;
1419
1420         if (mono_aot_only) {
1421                 /* Avoid creating trampolines if possible */
1422                 gpointer code = mono_jit_find_compiled_method (domain, method);
1423                 
1424                 if (code)
1425                         return code;
1426         }
1427
1428         mono_domain_lock (domain);
1429         tramp = g_hash_table_lookup (domain_jit_info (domain)->jit_trampoline_hash, method);
1430         mono_domain_unlock (domain);
1431         if (tramp)
1432                 return tramp;
1433
1434         tramp = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JIT, domain, NULL);
1435         
1436         mono_domain_lock (domain);
1437         g_hash_table_insert (domain_jit_info (domain)->jit_trampoline_hash, method, tramp);
1438         mono_domain_unlock (domain);
1439
1440         jit_trampolines++;
1441
1442         return tramp;
1443 }       
1444
1445 gpointer
1446 mono_create_jit_trampoline (MonoMethod *method)
1447 {
1448         return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
1449 }
1450
1451 gpointer
1452 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
1453 {
1454         gpointer tramp;
1455
1456         MonoDomain *domain = mono_domain_get ();
1457         guint8 *buf, *start;
1458
1459         buf = start = mono_domain_alloc0 (domain, 2 * sizeof (gpointer));
1460
1461         *(gpointer*)(gpointer)buf = image;
1462         buf += sizeof (gpointer);
1463         *(guint32*)(gpointer)buf = token;
1464
1465         tramp = mono_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
1466
1467         jit_trampolines++;
1468
1469         return tramp;
1470 }       
1471
1472 gpointer
1473 mono_create_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
1474 {
1475 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
1476         gpointer ptr;
1477         guint32 code_size = 0;
1478         gpointer *tramp_data;
1479         MonoMethod *invoke;
1480
1481         mono_domain_lock (domain);
1482         ptr = g_hash_table_lookup (domain_jit_info (domain)->delegate_trampoline_hash, klass);
1483         mono_domain_unlock (domain);
1484         if (ptr)
1485                 return ptr;
1486
1487         // Precompute the delegate invoke impl and pass it to the delegate trampoline
1488         invoke = mono_get_delegate_invoke (klass);
1489         g_assert (invoke);
1490
1491         tramp_data = mono_domain_alloc (domain, sizeof (gpointer) * 3);
1492         tramp_data [0] = invoke;
1493         tramp_data [1] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
1494         tramp_data [2] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
1495
1496         ptr = mono_create_specific_trampoline (tramp_data, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
1497         g_assert (code_size);
1498
1499         /* store trampoline address */
1500         mono_domain_lock (domain);
1501         g_hash_table_insert (domain_jit_info (domain)->delegate_trampoline_hash,
1502                                                           klass, ptr);
1503         mono_domain_unlock (domain);
1504
1505         return ptr;
1506 #else
1507         return NULL;
1508 #endif
1509 }
1510
1511 gpointer
1512 mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
1513 {
1514         static gboolean inited = FALSE;
1515         static int num_trampolines = 0;
1516         MonoTrampInfo *info;
1517
1518         gpointer tramp, ptr;
1519
1520         if (mono_aot_only)
1521                 return mono_aot_get_lazy_fetch_trampoline (offset);
1522
1523         mono_trampolines_lock ();
1524         if (rgctx_lazy_fetch_trampoline_hash)
1525                 tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
1526         else
1527                 tramp = NULL;
1528         mono_trampolines_unlock ();
1529         if (tramp)
1530                 return tramp;
1531
1532         tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, &info, FALSE);
1533         if (info) {
1534                 mono_save_trampoline_xdebug_info (info);
1535                 if (mono_jit_map_is_enabled ())
1536                         mono_emit_jit_tramp (info->code, info->code_size, info->name);
1537                 mono_tramp_info_free (info);
1538         }
1539         ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
1540
1541         mono_trampolines_lock ();
1542         if (!rgctx_lazy_fetch_trampoline_hash) {
1543                 rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
1544                 rgctx_lazy_fetch_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
1545         }
1546         g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
1547         g_assert (offset != -1);
1548         g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr, ptr, GUINT_TO_POINTER (offset + 1));
1549         mono_trampolines_unlock ();
1550
1551         if (!inited) {
1552                 mono_counters_register ("RGCTX num lazy fetch trampolines",
1553                                 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
1554                 inited = TRUE;
1555         }
1556         num_trampolines++;
1557
1558         return ptr;
1559 }
1560
1561 gpointer
1562 mono_create_monitor_enter_trampoline (void)
1563 {
1564         static gpointer code;
1565
1566         if (mono_aot_only) {
1567                 if (!code)
1568                         code = mono_aot_get_trampoline ("monitor_enter_trampoline");
1569                 return code;
1570         }
1571
1572 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1573         mono_trampolines_lock ();
1574
1575         if (!code) {
1576                 MonoTrampInfo *info;
1577
1578                 code = mono_arch_create_monitor_enter_trampoline (&info, FALSE);
1579                 if (info) {
1580                         mono_save_trampoline_xdebug_info (info);
1581                         if (mono_jit_map_is_enabled ())
1582                                 mono_emit_jit_tramp (info->code, info->code_size, info->name);
1583                         mono_tramp_info_free (info);
1584                 }
1585         }
1586
1587         mono_trampolines_unlock ();
1588 #else
1589         code = NULL;
1590         g_assert_not_reached ();
1591 #endif
1592
1593         return code;
1594 }
1595
1596 gpointer
1597 mono_create_monitor_exit_trampoline (void)
1598 {
1599         static gpointer code;
1600
1601         if (mono_aot_only) {
1602                 if (!code)
1603                         code = mono_aot_get_trampoline ("monitor_exit_trampoline");
1604                 return code;
1605         }
1606
1607 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1608         mono_trampolines_lock ();
1609
1610         if (!code) {
1611                 MonoTrampInfo *info;
1612
1613                 code = mono_arch_create_monitor_exit_trampoline (&info, FALSE);
1614                 if (info) {
1615                         mono_save_trampoline_xdebug_info (info);
1616                         if (mono_jit_map_is_enabled ())
1617                                 mono_emit_jit_tramp (info->code, info->code_size, info->name);
1618                         mono_tramp_info_free (info);
1619                 }
1620         }
1621
1622         mono_trampolines_unlock ();
1623 #else
1624         code = NULL;
1625         g_assert_not_reached ();
1626 #endif
1627         return code;
1628 }
1629  
1630 #ifdef MONO_ARCH_LLVM_SUPPORTED
1631 /*
1632  * mono_create_llvm_imt_trampoline:
1633  *
1634  *   LLVM compiled code can't pass in the IMT argument, so we use this trampoline, which
1635  * sets the IMT argument, then branches to the contents of the vtable slot given by
1636  * vt_offset in the vtable which is obtained from the argument list.
1637  */
1638 gpointer
1639 mono_create_llvm_imt_trampoline (MonoDomain *domain, MonoMethod *m, int vt_offset)
1640 {
1641 #ifdef MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE
1642         return mono_arch_get_llvm_imt_trampoline (domain, m, vt_offset);
1643 #else
1644         g_assert_not_reached ();
1645         return NULL;
1646 #endif
1647 }
1648 #endif
1649
1650 MonoVTable*
1651 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
1652 {
1653         MonoVTable *res;
1654
1655         mono_trampolines_lock ();
1656         if (class_init_hash_addr)
1657                 res = g_hash_table_lookup (class_init_hash_addr, addr);
1658         else
1659                 res = NULL;
1660         mono_trampolines_unlock ();
1661         return res;
1662 }
1663
1664 guint32
1665 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr)
1666 {
1667         int offset;
1668
1669         mono_trampolines_lock ();
1670         if (rgctx_lazy_fetch_trampoline_hash_addr) {
1671                 /* We store the real offset + 1 so we can detect when the lookup fails */
1672                 offset = GPOINTER_TO_INT (g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash_addr, addr));
1673                 if (offset)
1674                         offset -= 1;
1675                 else
1676                         offset = -1;
1677         } else {
1678                 offset = -1;
1679         }
1680         mono_trampolines_unlock ();
1681         return offset;
1682 }
1683
1684 static const char*tramp_names [MONO_TRAMPOLINE_NUM] = {
1685         "jit",
1686         "jump",
1687         "class_init",
1688         "generic_class_init",
1689         "rgctx_lazy_fetch",
1690         "aot",
1691         "aot_plt",
1692         "delegate",
1693         "restore_stack_prot",
1694         "generic_virtual_remoting",
1695         "monitor_enter",
1696         "monitor_exit",
1697         "vcall",
1698         "handler_block_guard"
1699 };
1700
1701 /*
1702  * mono_get_generic_trampoline_name:
1703  *
1704  *   Returns a pointer to malloc-ed memory.
1705  */
1706 char*
1707 mono_get_generic_trampoline_name (MonoTrampolineType tramp_type)
1708 {
1709         return g_strdup_printf ("generic_trampoline_%s", tramp_names [tramp_type]);
1710 }
1711
1712 /*
1713  * mono_get_rgctx_fetch_trampoline_name:
1714  *
1715  *   Returns a pointer to malloc-ed memory.
1716  */
1717 char*
1718 mono_get_rgctx_fetch_trampoline_name (int slot)
1719 {
1720         gboolean mrgctx;
1721         int index;
1722
1723         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
1724         index = MONO_RGCTX_SLOT_INDEX (slot);
1725
1726         return g_strdup_printf ("rgctx_fetch_trampoline_%s_%d", mrgctx ? "mrgctx" : "rgctx", index);
1727 }
1728