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