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