2 * (C) 2003 Ximian, Inc.
3 * (C) 2003-2011 Novell, Inc.
4 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
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>
20 * Address of the trampoline code. This is used by the debugger to check
21 * whether a method is a trampoline.
23 guint8
* mono_trampoline_code
[MONO_TRAMPOLINE_NUM
];
25 static GHashTable
*class_init_hash_addr
= NULL
;
26 static GHashTable
*rgctx_lazy_fetch_trampoline_hash
= NULL
;
27 static GHashTable
*rgctx_lazy_fetch_trampoline_hash_addr
= NULL
;
28 static guint32 trampoline_calls
, jit_trampolines
, unbox_trampolines
, static_rgctx_trampolines
;
30 #define mono_trampolines_lock() EnterCriticalSection (&trampolines_mutex)
31 #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex)
32 static CRITICAL_SECTION trampolines_mutex
;
34 #ifdef MONO_ARCH_GSHARED_SUPPORTED
42 rgctx_tramp_info_equal (gconstpointer ka
, gconstpointer kb
)
44 const RgctxTrampInfo
*i1
= ka
;
45 const RgctxTrampInfo
*i2
= kb
;
47 if (i1
->m
== i2
->m
&& i1
->addr
== i2
->addr
)
54 rgctx_tramp_info_hash (gconstpointer data
)
56 const RgctxTrampInfo
*info
= data
;
58 return GPOINTER_TO_UINT (info
->m
) ^ GPOINTER_TO_UINT (info
->addr
);
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)
66 * Creates a static rgctx trampoline for M which branches to ADDR which should
67 * point to the compiled code of M.
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.
76 * On PPC addr should be an ftnptr and the return value is an ftnptr too.
78 * Returns the generated static rgctx trampoline.
81 mono_create_static_rgctx_trampoline (MonoMethod
*m
, gpointer addr
)
86 RgctxTrampInfo tmp_info
;
89 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
90 g_assert (((gpointer
*)addr
) [2] == 0);
93 ctx
= mini_method_get_rgctx (m
);
95 domain
= mono_domain_get ();
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.
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
);
105 tmp_info
.addr
= addr
;
106 res
= g_hash_table_lookup (domain_jit_info (domain
)->static_rgctx_trampoline_hash
,
108 mono_domain_unlock (domain
);
113 res
= mono_aot_get_static_rgctx_trampoline (ctx
, addr
);
115 res
= mono_arch_get_static_rgctx_trampoline (m
, ctx
, addr
);
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
));
122 g_hash_table_insert (domain_jit_info (domain
)->static_rgctx_trampoline_hash
, info
, res
);
123 mono_domain_unlock (domain
);
125 static_rgctx_trampolines
++;
131 mono_create_static_rgctx_trampoline (MonoMethod
*m
, gpointer addr
)
134 * This shouldn't happen as all arches which support generic sharing support
135 * static rgctx trampolines as well.
137 g_assert_not_reached ();
141 #ifdef MONO_ARCH_HAVE_IMT
144 * Either IMPL_METHOD or AOT_ADDR will be set on return.
149 * This works against problems when compiling with gcc 4.6 on arm. The 'then' part of
150 * this line gets executed, even when the condition is false:
151 * if (impl && mono_method_needs_static_rgctx_invoke (impl, FALSE))
152 * *need_rgctx_tramp = TRUE;
154 __attribute__ ((noinline
))
156 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
)
158 MonoObject
*this_argument
= mono_arch_get_this_arg_from_call (regs
, code
);
159 MonoVTable
*vt
= this_argument
->vtable
;
160 int displacement
= slot
- ((gpointer
*)vt
);
162 if (displacement
> 0) {
163 /* slot is in the vtable, not in the IMT */
165 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p is in the vtable, not in the IMT\n", slot
);
169 MonoMethod
*imt_method
= mono_arch_find_imt_method (regs
, code
);
171 int interface_offset
;
172 int imt_slot
= MONO_IMT_SIZE
+ displacement
;
174 /*This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement*/
175 interface_offset
= mono_class_interface_offset_with_variance (vt
->klass
, imt_method
->klass
, variance_used
);
177 if (interface_offset
< 0) {
178 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));
180 mono_vtable_build_imt_slot (vt
, mono_method_get_imt_slot (imt_method
));
182 if (imt_method
->is_inflated
&& ((MonoMethodInflated
*)imt_method
)->context
.method_inst
) {
183 MonoGenericContext context
= { NULL
, NULL
};
186 * Generic virtual method, imt_method contains the inflated interface
187 * method, need to get the inflated impl method.
189 /* imt_method->slot might not be set */
190 impl
= mono_class_get_vtable_entry (vt
->klass
, interface_offset
+ mono_method_get_declaring_generic_method (imt_method
)->slot
);
192 if (impl
->klass
->generic_class
)
193 context
.class_inst
= impl
->klass
->generic_class
->context
.class_inst
;
194 context
.method_inst
= ((MonoMethodInflated
*)imt_method
)->context
.method_inst
;
195 impl
= mono_class_inflate_generic_method (impl
, &context
);
197 /* Avoid loading metadata or creating a generic vtable if possible */
198 if (lookup_aot
&& !vt
->klass
->valuetype
)
199 *aot_addr
= mono_aot_get_method_from_vt_slot (mono_domain_get (), vt
, interface_offset
+ mono_method_get_vtable_slot (imt_method
));
205 impl
= mono_class_get_vtable_entry (vt
->klass
, interface_offset
+ mono_method_get_vtable_slot (imt_method
));
208 if (impl
&& mono_method_needs_static_rgctx_invoke (impl
, FALSE
))
209 *need_rgctx_tramp
= TRUE
;
210 if (impl
&& impl
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_MANAGED
) {
211 WrapperInfo
*info
= mono_marshal_get_wrapper_info (impl
);
213 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
) {
214 *need_rgctx_tramp
= TRUE
;
220 printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
221 method
->klass
->name_space
, method
->klass
->name
, method
->name
,
222 imt_method
->klass
->name_space
, imt_method
->klass
->name
, imt_method
->name
);
225 g_assert (imt_slot
< MONO_IMT_SIZE
);
226 if (vt
->imt_collisions_bitmap
& (1 << imt_slot
)) {
227 int slot
= mono_method_get_vtable_index (imt_method
);
229 gpointer
*vtable_slot
;
231 g_assert (slot
!= -1);
232 vtable_offset
= interface_offset
+ slot
;
233 vtable_slot
= & (vt
->vtable
[vtable_offset
]);
235 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
);
240 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot
, imt_slot
);
249 * This is a super-ugly hack to fix bug #616463.
251 * The problem is that we don't always set is_generic for generic
252 * method definitions. See the comment at the end of
253 * mono_class_inflate_generic_method_full_checked() in class.c.
256 is_generic_method_definition (MonoMethod
*m
)
258 MonoGenericContext
*context
;
264 context
= mono_method_get_context (m
);
265 if (!context
->method_inst
)
267 if (context
->method_inst
== mono_method_get_generic_container (((MonoMethodInflated
*)m
)->declaring
)->context
.method_inst
)
273 mini_jit_info_is_gsharedvt (MonoJitInfo
*ji
)
275 if (ji
&& ji
->has_generic_jit_info
&& (mono_jit_info_get_generic_sharing_context (ji
)->var_is_vt
||
276 mono_jit_info_get_generic_sharing_context (ji
)->mvar_is_vt
))
283 * mini_add_method_trampoline:
284 * @orig_method: the method the caller originally called i.e. an iface method, or NULL.
287 * @add_static_rgctx_tramp: adds a static rgctx trampoline
288 * @add_unbox_tramp: adds an unboxing trampoline
290 * Add static rgctx/gsharedvt_in/unbox trampolines to
291 * M/COMPILED_METHOD if needed.
293 * Returns the trampoline address, or COMPILED_METHOD if no trampoline
297 mini_add_method_trampoline (MonoMethod
*orig_method
, MonoMethod
*m
, gpointer compiled_method
, gboolean add_static_rgctx_tramp
, gboolean add_unbox_tramp
)
299 gpointer addr
= compiled_method
;
300 gboolean callee_gsharedvt
, callee_array_helper
;
301 MonoMethod
*jmethod
= NULL
;
304 // FIXME: This loads information from AOT (perf problem)
305 ji
= mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method
), NULL
);
306 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
308 callee_array_helper
= FALSE
;
309 if (m
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_MANAGED
) {
310 WrapperInfo
*info
= mono_marshal_get_wrapper_info (m
);
313 * generic array helpers.
314 * Have to replace the wrappers with the original generic instances.
316 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
) {
317 callee_array_helper
= TRUE
;
318 m
= info
->d
.generic_array_helper
.method
;
320 } else if (m
->wrapper_type
== MONO_WRAPPER_UNKNOWN
) {
321 WrapperInfo
*info
= mono_marshal_get_wrapper_info (m
);
323 /* Same for synchronized inner wrappers */
324 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
325 m
= info
->d
.synchronized_inner
.method
;
332 if (callee_gsharedvt
)
333 g_assert (m
->is_inflated
);
335 addr
= compiled_method
;
337 if (add_unbox_tramp
) {
339 * The unbox trampolines call the method directly, so need to add
340 * an rgctx tramp before them.
343 addr
= mono_aot_get_unbox_trampoline (m
);
345 unbox_trampolines
++;
346 addr
= mono_arch_get_unbox_trampoline (m
, addr
);
351 jmethod
= jinfo_get_method (ji
);
352 if (callee_gsharedvt
&& mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod
))) {
353 MonoGenericSharingContext
*gsctx
;
354 MonoMethodSignature
*sig
, *gsig
;
356 /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
358 /* Call from normal/gshared code to gsharedvt code with variable signature */
359 gsctx
= mono_jit_info_get_generic_sharing_context (ji
);
361 sig
= mono_method_signature (m
);
362 gsig
= mono_method_signature (jmethod
);
364 addr
= mini_get_gsharedvt_wrapper (TRUE
, addr
, sig
, gsig
, gsctx
, -1, FALSE
);
366 //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
369 if (callee_array_helper
) {
370 add_static_rgctx_tramp
= FALSE
;
371 /* FIXME: ji->from_aot is not set for llvm methods */
372 if (ji
&& (ji
->from_aot
|| mono_aot_only
)) {
373 /* In AOT mode, compiled_method points to one of the InternalArray methods in Array. */
374 if (mono_method_needs_static_rgctx_invoke (jinfo_get_method (ji
), TRUE
))
375 add_static_rgctx_tramp
= TRUE
;
379 if (add_static_rgctx_tramp
)
380 addr
= mono_create_static_rgctx_trampoline (m
, addr
);
386 * common_call_trampoline:
388 * The code to handle normal, virtual, and interface method calls and jumps, both
389 * from JITted and LLVM compiled code.
392 common_call_trampoline (mgreg_t
*regs
, guint8
*code
, MonoMethod
*m
, guint8
* tramp
, MonoVTable
*vt
, gpointer
*vtable_slot
, gboolean need_rgctx_tramp
)
394 gpointer addr
, compiled_method
;
395 gboolean generic_shared
= FALSE
;
396 gboolean need_unbox_tramp
= FALSE
;
397 MonoMethod
*declaring
= NULL
;
398 MonoMethod
*generic_virtual
= NULL
, *variant_iface
= NULL
, *orig_method
= NULL
;
400 gboolean
virtual, variance_used
= FALSE
;
401 gpointer
*orig_vtable_slot
, *vtable_slot_to_patch
= NULL
;
402 MonoJitInfo
*ji
= NULL
;
404 virtual = (gpointer
)vtable_slot
> (gpointer
)vt
;
406 orig_vtable_slot
= vtable_slot
;
407 vtable_slot_to_patch
= vtable_slot
;
409 #ifdef MONO_ARCH_HAVE_IMT
411 if (vt
&& (gpointer
)vtable_slot
< (gpointer
)vt
) {
412 MonoMethod
*impl_method
= NULL
;
413 MonoObject
*this_arg
;
415 /* we get the interface method because mono_convert_imt_slot_to_vtable_slot ()
416 * needs the signature to be able to find the this argument
418 m
= mono_arch_find_imt_method (regs
, code
);
419 vtable_slot
= orig_vtable_slot
;
420 g_assert (vtable_slot
);
424 this_arg
= mono_arch_get_this_arg_from_call (regs
, code
);
426 if (mono_object_is_transparent_proxy (this_arg
)) {
427 /* Use the slow path for now */
428 m
= mono_object_get_virtual_method (this_arg
, m
);
429 vtable_slot_to_patch
= NULL
;
433 mono_class_interface_offset_with_variance (vt
->klass
, m
->klass
, &variance_used
);
435 if (m
->is_inflated
&& ((MonoMethodInflated
*)m
)->context
.method_inst
) {
436 /* Generic virtual method */
438 need_rgctx_tramp
= TRUE
;
439 } else if (variance_used
&& mono_class_has_variant_generic_params (m
->klass
)) {
444 /* We can only use the AOT compiled code if we don't require further processing */
445 lookup_aot
= !generic_virtual
& !variant_iface
;
446 vtable_slot
= mono_convert_imt_slot_to_vtable_slot (vtable_slot
, regs
, code
, m
, lookup_aot
, &impl_method
, &need_rgctx_tramp
, &variance_used
, &addr
);
447 /* This is the vcall slot which gets called through the IMT thunk */
448 vtable_slot_to_patch
= vtable_slot
;
449 /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
450 * to be called, so we compile it and go ahead as usual.
452 /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
456 * We found AOT compiled code for the method, skip the rest.
458 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot
))
461 return mono_create_ftnptr (mono_domain_get (), addr
);
470 * The virtual check is needed because is_generic_method_definition (m) could
471 * return TRUE for methods used in IMT calls too.
473 if (virtual && is_generic_method_definition (m
)) {
474 MonoGenericContext context
= { NULL
, NULL
};
475 MonoMethod
*declaring
;
478 declaring
= mono_method_get_declaring_generic_method (m
);
482 if (m
->klass
->generic_class
)
483 context
.class_inst
= m
->klass
->generic_class
->context
.class_inst
;
485 g_assert (!m
->klass
->generic_container
);
487 #ifdef MONO_ARCH_HAVE_IMT
488 generic_virtual
= mono_arch_find_imt_method (regs
, code
);
490 if (generic_virtual
) {
491 g_assert (generic_virtual
->is_inflated
);
492 context
.method_inst
= ((MonoMethodInflated
*)generic_virtual
)->context
.method_inst
;
495 m
= mono_class_inflate_generic_method (declaring
, &context
);
496 /* FIXME: only do this if the method is sharable */
497 need_rgctx_tramp
= TRUE
;
498 } else if ((context_used
= mono_method_check_context_used (m
))) {
499 MonoClass
*klass
= NULL
;
500 MonoMethod
*actual_method
= NULL
;
501 MonoVTable
*vt
= NULL
;
502 MonoGenericInst
*method_inst
= NULL
;
505 generic_shared
= TRUE
;
509 if (m
->is_inflated
&& mono_method_get_context (m
)->method_inst
) {
510 #ifdef MONO_ARCH_RGCTX_REG
511 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)mono_arch_find_static_call_vtable (regs
, code
);
513 klass
= mrgctx
->class_vtable
->klass
;
514 method_inst
= mrgctx
->method_inst
;
516 g_assert_not_reached ();
518 } else if ((m
->flags
& METHOD_ATTRIBUTE_STATIC
) || m
->klass
->valuetype
) {
519 #ifdef MONO_ARCH_RGCTX_REG
520 MonoVTable
*vtable
= mono_arch_find_static_call_vtable (regs
, code
);
522 klass
= vtable
->klass
;
524 g_assert_not_reached ();
527 #ifdef MONO_ARCH_HAVE_IMT
528 MonoObject
*this_argument
= mono_arch_get_this_arg_from_call (regs
, code
);
530 vt
= this_argument
->vtable
;
531 vtable_slot
= orig_vtable_slot
;
533 g_assert (this_argument
->vtable
->klass
->inited
);
534 //mono_class_init (this_argument->vtable->klass);
537 mono_class_setup_supertypes (this_argument
->vtable
->klass
);
538 klass
= this_argument
->vtable
->klass
->supertypes
[m
->klass
->idepth
- 1];
545 g_assert (vtable_slot
|| klass
);
548 int displacement
= vtable_slot
- ((gpointer
*)vt
);
550 g_assert_not_reached ();
552 g_assert (displacement
> 0);
554 actual_method
= vt
->klass
->vtable
[displacement
];
557 if (method_inst
|| m
->wrapper_type
) {
558 MonoGenericContext context
= { NULL
, NULL
};
561 declaring
= mono_method_get_declaring_generic_method (m
);
565 if (klass
->generic_class
)
566 context
.class_inst
= klass
->generic_class
->context
.class_inst
;
567 else if (klass
->generic_container
)
568 context
.class_inst
= klass
->generic_container
->context
.class_inst
;
569 context
.method_inst
= method_inst
;
571 actual_method
= mono_class_inflate_generic_method (declaring
, &context
);
573 actual_method
= mono_class_get_method_generic (klass
, m
);
577 g_assert (actual_method
);
578 g_assert (actual_method
->klass
== klass
);
580 if (actual_method
->is_inflated
)
581 declaring
= mono_method_get_declaring_generic_method (actual_method
);
588 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
589 m
= mono_marshal_get_synchronized_wrapper (m
);
590 need_rgctx_tramp
= FALSE
;
593 /* Calls made through delegates on platforms without delegate trampolines */
594 if (!code
&& mono_method_needs_static_rgctx_invoke (m
, FALSE
))
595 need_rgctx_tramp
= TRUE
;
597 addr
= compiled_method
= mono_compile_method (m
);
600 if (generic_virtual
|| variant_iface
) {
601 if (vt
->klass
->valuetype
) /*FIXME is this required variant iface?*/
602 need_unbox_tramp
= TRUE
;
603 } else if (orig_vtable_slot
) {
604 if (m
->klass
->valuetype
)
605 need_unbox_tramp
= TRUE
;
608 addr
= mini_add_method_trampoline (orig_method
, m
, compiled_method
, need_rgctx_tramp
, need_unbox_tramp
);
610 if (generic_virtual
|| variant_iface
) {
611 MonoMethod
*target
= generic_virtual
? generic_virtual
: variant_iface
;
613 vtable_slot
= orig_vtable_slot
;
614 g_assert (vtable_slot
);
616 mono_method_add_generic_virtual_invocation (mono_domain_get (),
623 /* the method was jumped to */
625 MonoDomain
*domain
= mono_domain_get ();
627 /* Patch the got entries pointing to this method */
629 * We do this here instead of in mono_codegen () to cover the case when m
630 * was loaded from an aot image.
632 if (domain_jit_info (domain
)->jump_target_got_slot_hash
) {
635 mono_domain_lock (domain
);
636 list
= g_hash_table_lookup (domain_jit_info (domain
)->jump_target_got_slot_hash
, m
);
638 for (tmp
= list
; tmp
; tmp
= tmp
->next
) {
639 gpointer
*got_slot
= tmp
->data
;
642 g_hash_table_remove (domain_jit_info (domain
)->jump_target_got_slot_hash
, m
);
645 mono_domain_unlock (domain
);
651 vtable_slot
= orig_vtable_slot
;
654 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
))) {
655 g_assert (*vtable_slot_to_patch
);
656 *vtable_slot_to_patch
= mono_get_addr_from_ftnptr (addr
);
660 guint8
*plt_entry
= mono_aot_get_plt_entry (code
);
661 gboolean no_patch
= FALSE
;
662 MonoJitInfo
*target_ji
;
665 if (generic_shared
) {
667 mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method
), NULL
);
669 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)code
, NULL
);
671 if (ji
&& target_ji
&& generic_shared
&& ji
->has_generic_jit_info
&& !target_ji
->has_generic_jit_info
) {
676 mono_aot_patch_plt_entry (code
, plt_entry
, NULL
, regs
, addr
);
678 if (generic_shared
) {
679 if (m
->wrapper_type
!= MONO_WRAPPER_NONE
)
680 m
= mono_marshal_method_from_wrapper (m
);
681 //g_assert (mono_method_is_generic_sharable (m, FALSE));
684 /* Patch calling code */
686 mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method
), NULL
);
688 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)code
, NULL
);
690 if (ji
&& target_ji
&& generic_shared
&& ji
->has_generic_jit_info
&& !target_ji
->has_generic_jit_info
) {
692 * Can't patch the call as the caller is gshared, but the callee is not. Happens when
693 * generic sharing fails.
694 * FIXME: Performance problem.
699 if (!no_patch
&& mono_method_same_domain (ji
, target_ji
))
700 mono_arch_patch_callsite (ji
->code_start
, code
, addr
);
708 * mono_magic_trampoline:
710 * This trampoline handles normal calls from JITted code.
713 mono_magic_trampoline (mgreg_t
*regs
, guint8
*code
, gpointer arg
, guint8
* tramp
)
717 return common_call_trampoline (regs
, code
, arg
, tramp
, NULL
, NULL
, FALSE
);
721 * mono_vcall_trampoline:
723 * This trampoline handles virtual calls.
726 mono_vcall_trampoline (mgreg_t
*regs
, guint8
*code
, int slot
, guint8
*tramp
)
730 gpointer
*vtable_slot
;
732 gboolean need_rgctx_tramp
= FALSE
;
738 * We need to obtain the following pieces of information:
739 * - the method which needs to be compiled.
741 * We use one vtable trampoline per vtable slot index, so we need only the vtable,
742 * the other two can be computed from the vtable + the slot index.
744 #ifndef MONO_ARCH_THIS_AS_FIRST_ARG
745 /* All architectures should support this */
746 g_assert_not_reached ();
750 * Obtain the vtable from the 'this' arg.
752 this = mono_arch_get_this_arg_from_call (regs
, code
);
758 /* Normal virtual call */
759 vtable_slot
= &(vt
->vtable
[slot
]);
761 /* Avoid loading metadata or creating a generic vtable if possible */
762 addr
= mono_aot_get_method_from_vt_slot (mono_domain_get (), vt
, slot
);
763 if (addr
&& !vt
->klass
->valuetype
) {
764 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot
))
767 return mono_create_ftnptr (mono_domain_get (), addr
);
772 * is_generic_method_definition() above) also
773 * goes away if we do a
774 * mono_class_setup_vtable (vt->klass) here,
775 * because we then inflate the method
776 * correctly, put it in the cache, and the
777 * "wrong" inflation invocation still looks up
778 * the correctly inflated method.
780 * The hack above seems more stable and
783 m
= mono_class_get_vtable_entry (vt
->klass
, slot
);
785 need_rgctx_tramp
= mono_method_needs_static_rgctx_invoke (m
, 0);
788 vtable_slot
= &(((gpointer
*)vt
) [slot
]);
791 need_rgctx_tramp
= FALSE
;
794 return common_call_trampoline (regs
, code
, m
, tramp
, vt
, vtable_slot
, need_rgctx_tramp
);
797 #ifndef DISABLE_REMOTING
799 mono_generic_virtual_remoting_trampoline (mgreg_t
*regs
, guint8
*code
, MonoMethod
*m
, guint8
*tramp
)
801 MonoGenericContext context
= { NULL
, NULL
};
802 MonoMethod
*imt_method
, *declaring
;
807 g_assert (m
->is_generic
);
810 declaring
= mono_method_get_declaring_generic_method (m
);
814 if (m
->klass
->generic_class
)
815 context
.class_inst
= m
->klass
->generic_class
->context
.class_inst
;
817 g_assert (!m
->klass
->generic_container
);
819 #ifdef MONO_ARCH_HAVE_IMT
820 imt_method
= mono_arch_find_imt_method (regs
, code
);
821 if (imt_method
->is_inflated
)
822 context
.method_inst
= ((MonoMethodInflated
*)imt_method
)->context
.method_inst
;
824 m
= mono_class_inflate_generic_method (declaring
, &context
);
825 m
= mono_marshal_get_remoting_invoke_with_check (m
);
827 addr
= mono_compile_method (m
);
835 * mono_aot_trampoline:
837 * This trampoline handles calls made from AOT code. We try to bypass the
838 * normal JIT compilation logic to avoid loading the metadata for the method.
840 #ifdef MONO_ARCH_AOT_SUPPORTED
842 mono_aot_trampoline (mgreg_t
*regs
, guint8
*code
, guint8
*token_info
,
847 MonoMethod
*method
= NULL
;
853 image
= *(gpointer
*)(gpointer
)token_info
;
854 token_info
+= sizeof (gpointer
);
855 token
= *(guint32
*)(gpointer
)token_info
;
857 addr
= mono_aot_get_method_from_token (mono_domain_get (), image
, token
);
859 method
= mono_get_method (image
, token
, NULL
);
862 /* Use the generic code */
863 return mono_magic_trampoline (regs
, code
, method
, tramp
);
866 addr
= mono_create_ftnptr (mono_domain_get (), addr
);
868 /* This is a normal call through a PLT entry */
869 plt_entry
= mono_aot_get_plt_entry (code
);
870 g_assert (plt_entry
);
872 mono_aot_patch_plt_entry (code
, plt_entry
, NULL
, regs
, addr
);
878 * mono_aot_plt_trampoline:
880 * This trampoline handles calls made from AOT code through the PLT table.
883 mono_aot_plt_trampoline (mgreg_t
*regs
, guint8
*code
, guint8
*aot_module
,
886 guint32 plt_info_offset
= mono_aot_get_plt_info_offset (regs
, code
);
891 res
= mono_aot_plt_resolve (aot_module
, plt_info_offset
, code
);
893 if (mono_loader_get_last_error ())
894 mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ()));
895 // FIXME: Error handling (how ?)
904 * mono_class_init_trampoline:
906 * This method calls mono_runtime_class_init () to run the static constructor
907 * for the type, then patches the caller code so it is not called again.
910 mono_class_init_trampoline (mgreg_t
*regs
, guint8
*code
, MonoVTable
*vtable
, guint8
*tramp
)
912 guint8
*plt_entry
= mono_aot_get_plt_entry (code
);
916 mono_runtime_class_init (vtable
);
918 if (vtable
->initialized
) {
920 mono_aot_patch_plt_entry (code
, plt_entry
, NULL
, regs
, mini_get_nullified_class_init_trampoline ());
922 mono_arch_nullify_class_init_trampoline (code
, regs
);
927 * mono_generic_class_init_trampoline:
929 * This method calls mono_runtime_class_init () to run the static constructor
933 mono_generic_class_init_trampoline (mgreg_t
*regs
, guint8
*code
, MonoVTable
*vtable
, guint8
*tramp
)
937 mono_runtime_class_init (vtable
);
941 mono_rgctx_lazy_fetch_trampoline (mgreg_t
*regs
, guint8
*code
, gpointer data
, guint8
*tramp
)
943 #ifdef MONO_ARCH_VTABLE_REG
944 static gboolean inited
= FALSE
;
945 static int num_lookups
= 0;
946 guint32 slot
= GPOINTER_TO_UINT (data
);
947 mgreg_t
*r
= (mgreg_t
*)regs
;
948 gpointer arg
= (gpointer
)(gssize
)r
[MONO_ARCH_VTABLE_REG
];
949 guint32 index
= MONO_RGCTX_SLOT_INDEX (slot
);
950 gboolean mrgctx
= MONO_RGCTX_SLOT_IS_MRGCTX (slot
);
955 mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_lookups
);
962 return mono_method_fill_runtime_generic_context (arg
, code
, index
);
964 return mono_class_fill_runtime_generic_context (arg
, code
, index
);
966 g_assert_not_reached ();
971 mono_monitor_enter_trampoline (mgreg_t
*regs
, guint8
*code
, MonoObject
*obj
, guint8
*tramp
)
973 mono_monitor_enter (obj
);
977 mono_monitor_exit_trampoline (mgreg_t
*regs
, guint8
*code
, MonoObject
*obj
, guint8
*tramp
)
979 mono_monitor_exit (obj
);
982 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
987 gpointer impl_nothis
;
989 MonoMethodSignature
*invoke_sig
;
990 MonoMethodSignature
*sig
;
991 gboolean need_rgctx_tramp
;
995 * Precompute data to speed up mono_delegate_trampoline ().
996 * METHOD might be NULL.
999 create_delegate_trampoline_data (MonoDomain
*domain
, MonoClass
*klass
, MonoMethod
*method
)
1001 DelegateTrampInfo
*tramp_data
;
1005 // Precompute the delegate invoke impl and pass it to the delegate trampoline
1006 invoke
= mono_get_delegate_invoke (klass
);
1009 tramp_data
= mono_domain_alloc (domain
, sizeof (DelegateTrampInfo
));
1010 tramp_data
->invoke
= invoke
;
1011 tramp_data
->invoke_sig
= mono_method_signature (invoke
);
1012 tramp_data
->impl_this
= mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke
), TRUE
);
1013 tramp_data
->impl_nothis
= mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke
), FALSE
);
1014 tramp_data
->method
= method
;
1016 mono_error_init (&err
);
1017 tramp_data
->sig
= mono_method_signature_checked (method
, &err
);
1018 tramp_data
->need_rgctx_tramp
= mono_method_needs_static_rgctx_invoke (method
, FALSE
);
1025 * mono_delegate_trampoline:
1027 * This trampoline handles calls made to Delegate:Invoke ().
1028 * This is called once the first time a delegate is invoked, so it must be fast.
1031 mono_delegate_trampoline (mgreg_t
*regs
, guint8
*code
, gpointer
*arg
, guint8
* tramp
)
1033 MonoDomain
*domain
= mono_domain_get ();
1034 MonoDelegate
*delegate
;
1037 MonoMethod
*method
= NULL
;
1038 gboolean multicast
, callvirt
= FALSE
, closed_over_null
= FALSE
;
1039 gboolean need_rgctx_tramp
= FALSE
;
1040 gboolean need_unbox_tramp
= FALSE
;
1041 gboolean enable_caching
= TRUE
;
1042 DelegateTrampInfo
*tramp_info
= (DelegateTrampInfo
*)arg
;
1043 MonoMethod
*invoke
= tramp_info
->invoke
;
1044 guint8
*impl_this
= tramp_info
->impl_this
;
1045 guint8
*impl_nothis
= tramp_info
->impl_nothis
;
1047 MonoMethodSignature
*sig
;
1048 gpointer addr
, compiled_method
;
1049 gboolean is_remote
= FALSE
;
1051 trampoline_calls
++;
1053 /* Obtain the delegate object according to the calling convention */
1054 delegate
= mono_arch_get_this_arg_from_call (regs
, code
);
1056 if (delegate
->method
) {
1057 method
= delegate
->method
;
1060 * delegate->method_ptr == NULL means the delegate was initialized by
1061 * mini_delegate_ctor, while != NULL means it is initialized by
1062 * mono_delegate_ctor_with_method (). In both cases, we need to add wrappers
1063 * (ctor_with_method () does this, but it doesn't store the wrapper back into
1064 * delegate->method).
1066 #ifndef DISABLE_REMOTING
1067 if (delegate
->target
&& delegate
->target
->vtable
->klass
== mono_defaults
.transparent_proxy_class
) {
1070 if (((MonoTransparentProxy
*)delegate
->target
)->remote_class
->proxy_class
!= mono_class_get_com_object_class () &&
1071 !mono_class_is_com_object (((MonoTransparentProxy
*)delegate
->target
)->remote_class
->proxy_class
))
1073 method
= mono_marshal_get_remoting_invoke (method
);
1077 sig
= tramp_info
->sig
;
1078 if (!(sig
&& method
== tramp_info
->method
)) {
1079 mono_error_init (&err
);
1080 sig
= mono_method_signature_checked (method
, &err
);
1082 mono_error_raise_exception (&err
);
1085 if (sig
->hasthis
&& method
->klass
->valuetype
) {
1087 need_unbox_tramp
= TRUE
;
1089 method
= mono_marshal_get_unbox_wrapper (method
);
1093 ji
= mono_jit_info_table_find (domain
, mono_get_addr_from_ftnptr (delegate
->method_ptr
));
1095 method
= jinfo_get_method (ji
);
1099 sig
= tramp_info
->sig
;
1100 if (!(sig
&& method
== tramp_info
->method
)) {
1101 mono_error_init (&err
);
1102 sig
= mono_method_signature_checked (method
, &err
);
1104 mono_error_raise_exception (&err
);
1107 callvirt
= !delegate
->target
&& sig
->hasthis
;
1109 closed_over_null
= tramp_info
->invoke_sig
->param_count
== sig
->param_count
;
1111 if (callvirt
&& !closed_over_null
) {
1113 * The delegate needs to make a virtual call to the target method using its
1114 * first argument as the receiver. This is hard to support in full-aot, so
1115 * optimize it in some cases if possible.
1116 * If the target method is not virtual or is in a sealed class,
1117 * the vcall will call it directly.
1118 * If the call doesn't return a valuetype, then the vcall uses the same calling
1119 * convention as a normal call.
1121 if (((method
->klass
->flags
& TYPE_ATTRIBUTE_SEALED
) || !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) && !MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1123 enable_caching
= FALSE
;
1127 if (delegate
->target
&&
1128 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1129 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1130 method
->klass
->flags
& TYPE_ATTRIBUTE_ABSTRACT
) {
1131 method
= mono_object_get_virtual_method (delegate
->target
, method
);
1132 enable_caching
= FALSE
;
1135 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1136 method
= mono_marshal_get_synchronized_wrapper (method
);
1138 if (method
== tramp_info
->method
)
1139 need_rgctx_tramp
= tramp_info
->need_rgctx_tramp
;
1140 else if (mono_method_needs_static_rgctx_invoke (method
, FALSE
))
1141 need_rgctx_tramp
= TRUE
;
1145 * If the called address is a trampoline, replace it with the compiled method so
1146 * further calls don't have to go through the trampoline.
1148 if (method
&& !callvirt
) {
1149 /* Avoid the overhead of looking up an already compiled method if possible */
1150 if (enable_caching
&& delegate
->method_code
&& *delegate
->method_code
) {
1151 delegate
->method_ptr
= *delegate
->method_code
;
1153 compiled_method
= addr
= mono_compile_method (method
);
1154 addr
= mini_add_method_trampoline (NULL
, method
, compiled_method
, need_rgctx_tramp
, need_unbox_tramp
);
1155 delegate
->method_ptr
= addr
;
1156 if (enable_caching
&& delegate
->method_code
)
1157 *delegate
->method_code
= delegate
->method_ptr
;
1160 if (need_rgctx_tramp
)
1161 delegate
->method_ptr
= mono_create_static_rgctx_trampoline (method
, delegate
->method_ptr
);
1164 multicast
= ((MonoMulticastDelegate
*)delegate
)->prev
!= NULL
;
1165 if (!multicast
&& !callvirt
) {
1166 if (method
&& (method
->flags
& METHOD_ATTRIBUTE_STATIC
) && mono_method_signature (method
)->param_count
== mono_method_signature (invoke
)->param_count
+ 1)
1167 /* Closed static delegate */
1170 code
= delegate
->target
? impl_this
: impl_nothis
;
1173 delegate
->invoke_impl
= mono_get_addr_from_ftnptr (code
);
1178 /* The general, unoptimized case */
1179 m
= mono_marshal_get_delegate_invoke (invoke
, delegate
);
1180 code
= mono_compile_method (m
);
1181 code
= mini_add_method_trampoline (NULL
, m
, code
, mono_method_needs_static_rgctx_invoke (m
, FALSE
), FALSE
);
1182 delegate
->invoke_impl
= mono_get_addr_from_ftnptr (code
);
1189 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
1191 mono_handler_block_guard_trampoline (mgreg_t
*regs
, guint8
*code
, gpointer
*tramp_info
, guint8
* tramp
)
1195 MonoJitTlsData
*jit_tls
= mono_native_tls_get_value (mono_jit_tls_id
);
1196 gpointer resume_ip
= jit_tls
->handler_block_return_address
;
1198 memcpy (&ctx
, &jit_tls
->handler_block_context
, sizeof (MonoContext
));
1199 MONO_CONTEXT_SET_IP (&ctx
, jit_tls
->handler_block_return_address
);
1201 jit_tls
->handler_block_return_address
= NULL
;
1202 jit_tls
->handler_block
= NULL
;
1204 if (!resume_ip
) /*this should not happen, but we should avoid crashing */
1205 exc
= mono_get_exception_execution_engine ("Invalid internal state, resuming abort after handler block but no resume ip found");
1207 exc
= mono_thread_resume_interruption ();
1210 mono_handle_exception (&ctx
, exc
);
1211 mono_restore_context (&ctx
);
1218 mono_create_handler_block_trampoline (void)
1220 static gpointer code
;
1222 mono_memory_barrier ();
1226 g_assert (!mono_aot_only
);
1228 mono_trampolines_lock ();
1231 MonoTrampInfo
*info
;
1234 tmp
= mono_arch_create_handler_block_trampoline (&info
, FALSE
);
1235 mono_tramp_info_register (info
);
1236 mono_memory_barrier ();
1239 mono_trampolines_unlock ();
1246 * mono_get_trampoline_func:
1248 * Return the C function which needs to be called by the generic trampoline of type
1252 mono_get_trampoline_func (MonoTrampolineType tramp_type
)
1254 switch (tramp_type
) {
1255 case MONO_TRAMPOLINE_JIT
:
1256 case MONO_TRAMPOLINE_JUMP
:
1257 return mono_magic_trampoline
;
1258 case MONO_TRAMPOLINE_CLASS_INIT
:
1259 return mono_class_init_trampoline
;
1260 case MONO_TRAMPOLINE_GENERIC_CLASS_INIT
:
1261 return mono_generic_class_init_trampoline
;
1262 case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
:
1263 return mono_rgctx_lazy_fetch_trampoline
;
1264 #ifdef MONO_ARCH_AOT_SUPPORTED
1265 case MONO_TRAMPOLINE_AOT
:
1266 return mono_aot_trampoline
;
1267 case MONO_TRAMPOLINE_AOT_PLT
:
1268 return mono_aot_plt_trampoline
;
1270 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
1271 case MONO_TRAMPOLINE_DELEGATE
:
1272 return mono_delegate_trampoline
;
1274 case MONO_TRAMPOLINE_RESTORE_STACK_PROT
:
1275 return mono_altstack_restore_prot
;
1276 #ifndef DISABLE_REMOTING
1277 case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
:
1278 return mono_generic_virtual_remoting_trampoline
;
1280 case MONO_TRAMPOLINE_MONITOR_ENTER
:
1281 return mono_monitor_enter_trampoline
;
1282 case MONO_TRAMPOLINE_MONITOR_EXIT
:
1283 return mono_monitor_exit_trampoline
;
1284 case MONO_TRAMPOLINE_VCALL
:
1285 return mono_vcall_trampoline
;
1286 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
1287 case MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD
:
1288 return mono_handler_block_guard_trampoline
;
1291 g_assert_not_reached ();
1297 create_trampoline_code (MonoTrampolineType tramp_type
)
1299 MonoTrampInfo
*info
;
1302 code
= mono_arch_create_generic_trampoline (tramp_type
, &info
, FALSE
);
1303 mono_tramp_info_register (info
);
1309 mono_trampolines_init (void)
1311 InitializeCriticalSection (&trampolines_mutex
);
1316 mono_trampoline_code
[MONO_TRAMPOLINE_JIT
] = create_trampoline_code (MONO_TRAMPOLINE_JIT
);
1317 mono_trampoline_code
[MONO_TRAMPOLINE_JUMP
] = create_trampoline_code (MONO_TRAMPOLINE_JUMP
);
1318 mono_trampoline_code
[MONO_TRAMPOLINE_CLASS_INIT
] = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT
);
1319 mono_trampoline_code
[MONO_TRAMPOLINE_GENERIC_CLASS_INIT
] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT
);
1320 mono_trampoline_code
[MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
] = create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
);
1321 #ifdef MONO_ARCH_AOT_SUPPORTED
1322 mono_trampoline_code
[MONO_TRAMPOLINE_AOT
] = create_trampoline_code (MONO_TRAMPOLINE_AOT
);
1323 mono_trampoline_code
[MONO_TRAMPOLINE_AOT_PLT
] = create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT
);
1325 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
1326 mono_trampoline_code
[MONO_TRAMPOLINE_DELEGATE
] = create_trampoline_code (MONO_TRAMPOLINE_DELEGATE
);
1328 mono_trampoline_code
[MONO_TRAMPOLINE_RESTORE_STACK_PROT
] = create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT
);
1329 #ifndef DISABLE_REMOTING
1330 mono_trampoline_code
[MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
);
1332 mono_trampoline_code
[MONO_TRAMPOLINE_MONITOR_ENTER
] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER
);
1333 mono_trampoline_code
[MONO_TRAMPOLINE_MONITOR_EXIT
] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT
);
1334 mono_trampoline_code
[MONO_TRAMPOLINE_VCALL
] = create_trampoline_code (MONO_TRAMPOLINE_VCALL
);
1335 #ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD
1336 mono_trampoline_code
[MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD
] = create_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD
);
1337 mono_create_handler_block_trampoline ();
1340 mono_counters_register ("Calls to trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &trampoline_calls
);
1341 mono_counters_register ("JIT trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &jit_trampolines
);
1342 mono_counters_register ("Unbox trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &unbox_trampolines
);
1343 mono_counters_register ("Static rgctx trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &static_rgctx_trampolines
);
1347 mono_trampolines_cleanup (void)
1349 if (class_init_hash_addr
)
1350 g_hash_table_destroy (class_init_hash_addr
);
1351 if (rgctx_lazy_fetch_trampoline_hash
)
1352 g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash
);
1353 if (rgctx_lazy_fetch_trampoline_hash_addr
)
1354 g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash_addr
);
1356 DeleteCriticalSection (&trampolines_mutex
);
1360 mono_get_trampoline_code (MonoTrampolineType tramp_type
)
1362 g_assert (mono_trampoline_code
[tramp_type
]);
1364 return mono_trampoline_code
[tramp_type
];
1368 mono_create_specific_trampoline (gpointer arg1
, MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
1371 return mono_aot_create_specific_trampoline (mono_defaults
.corlib
, arg1
, tramp_type
, domain
, code_len
);
1373 return mono_arch_create_specific_trampoline (arg1
, tramp_type
, domain
, code_len
);
1377 mono_create_class_init_trampoline (MonoVTable
*vtable
)
1380 MonoDomain
*domain
= vtable
->domain
;
1382 g_assert (!vtable
->klass
->generic_container
);
1384 /* previously created trampoline code */
1385 mono_domain_lock (domain
);
1387 g_hash_table_lookup (domain_jit_info (domain
)->class_init_trampoline_hash
,
1389 mono_domain_unlock (domain
);
1393 code
= mono_create_specific_trampoline (vtable
, MONO_TRAMPOLINE_CLASS_INIT
, domain
, NULL
);
1395 ptr
= mono_create_ftnptr (domain
, code
);
1397 /* store trampoline address */
1398 mono_domain_lock (domain
);
1399 g_hash_table_insert (domain_jit_info (domain
)->class_init_trampoline_hash
,
1401 mono_domain_unlock (domain
);
1403 mono_trampolines_lock ();
1404 if (!class_init_hash_addr
)
1405 class_init_hash_addr
= g_hash_table_new (NULL
, NULL
);
1406 g_hash_table_insert (class_init_hash_addr
, ptr
, vtable
);
1407 mono_trampolines_unlock ();
1413 mono_create_generic_class_init_trampoline (void)
1415 #ifdef MONO_ARCH_VTABLE_REG
1416 static gpointer code
;
1417 MonoTrampInfo
*info
;
1419 mono_trampolines_lock ();
1423 /* get_named_code () might return an ftnptr, but our caller expects a direct pointer */
1424 code
= mono_get_addr_from_ftnptr (mono_aot_get_trampoline ("generic_class_init_trampoline"));
1426 code
= mono_arch_create_generic_class_init_trampoline (&info
, FALSE
);
1427 mono_tramp_info_register (info
);
1431 mono_trampolines_unlock ();
1435 g_assert_not_reached ();
1440 mono_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
)
1444 guint32 code_size
= 0;
1446 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
1448 * We cannot recover the correct type of a shared generic
1449 * method from its native code address, so we use the
1450 * trampoline instead.
1451 * For synchronized methods, the trampoline adds the wrapper.
1453 if (code
&& !ji
->has_generic_jit_info
&& !(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
1456 mono_domain_lock (domain
);
1457 code
= g_hash_table_lookup (domain_jit_info (domain
)->jump_trampoline_hash
, method
);
1458 mono_domain_unlock (domain
);
1462 code
= mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_JUMP
, mono_domain_get (), &code_size
);
1463 g_assert (code_size
);
1465 ji
= mono_domain_alloc0 (domain
, MONO_SIZEOF_JIT_INFO
);
1466 ji
->code_start
= code
;
1467 ji
->code_size
= code_size
;
1468 ji
->d
.method
= method
;
1471 * mono_delegate_ctor needs to find the method metadata from the
1472 * trampoline address, so we save it here.
1475 mono_jit_info_table_add (domain
, ji
);
1477 mono_domain_lock (domain
);
1478 g_hash_table_insert (domain_jit_info (domain
)->jump_trampoline_hash
, method
, ji
->code_start
);
1479 mono_domain_unlock (domain
);
1481 return ji
->code_start
;
1485 mono_create_jit_trampoline_in_domain (MonoDomain
*domain
, MonoMethod
*method
)
1489 if (mono_aot_only
) {
1490 /* Avoid creating trampolines if possible */
1491 gpointer code
= mono_jit_find_compiled_method (domain
, method
);
1497 mono_domain_lock (domain
);
1498 tramp
= g_hash_table_lookup (domain_jit_info (domain
)->jit_trampoline_hash
, method
);
1499 mono_domain_unlock (domain
);
1503 tramp
= mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_JIT
, domain
, NULL
);
1505 mono_domain_lock (domain
);
1506 g_hash_table_insert (domain_jit_info (domain
)->jit_trampoline_hash
, method
, tramp
);
1507 mono_domain_unlock (domain
);
1515 mono_create_jit_trampoline (MonoMethod
*method
)
1517 return mono_create_jit_trampoline_in_domain (mono_domain_get (), method
);
1521 mono_create_jit_trampoline_from_token (MonoImage
*image
, guint32 token
)
1525 MonoDomain
*domain
= mono_domain_get ();
1526 guint8
*buf
, *start
;
1528 buf
= start
= mono_domain_alloc0 (domain
, 2 * sizeof (gpointer
));
1530 *(gpointer
*)(gpointer
)buf
= image
;
1531 buf
+= sizeof (gpointer
);
1532 *(guint32
*)(gpointer
)buf
= token
;
1534 tramp
= mono_create_specific_trampoline (start
, MONO_TRAMPOLINE_AOT
, domain
, NULL
);
1543 * mono_create_delegate_trampoline_with_method:
1545 * Create a delegate trampoline for the KLASS+METHOD pair.
1548 mono_create_delegate_trampoline_with_method (MonoDomain
*domain
, MonoClass
*klass
, MonoMethod
*method
)
1550 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
1552 guint32 code_size
= 0;
1553 gpointer tramp_info
;
1554 MonoClassMethodPair pair
, *dpair
;
1557 pair
.method
= method
;
1558 mono_domain_lock (domain
);
1559 ptr
= g_hash_table_lookup (domain_jit_info (domain
)->delegate_trampoline_hash
, &pair
);
1560 mono_domain_unlock (domain
);
1564 tramp_info
= create_delegate_trampoline_data (domain
, klass
, method
);
1566 ptr
= mono_create_specific_trampoline (tramp_info
, MONO_TRAMPOLINE_DELEGATE
, domain
, &code_size
);
1567 g_assert (code_size
);
1569 dpair
= mono_domain_alloc0 (domain
, sizeof (MonoClassMethodPair
));
1570 memcpy (dpair
, &pair
, sizeof (MonoClassMethodPair
));
1572 /* store trampoline address */
1573 mono_domain_lock (domain
);
1574 g_hash_table_insert (domain_jit_info (domain
)->delegate_trampoline_hash
, dpair
, ptr
);
1575 mono_domain_unlock (domain
);
1584 mono_create_delegate_trampoline (MonoDomain
*domain
, MonoClass
*klass
)
1586 return mono_create_delegate_trampoline_with_method (domain
, klass
, NULL
);
1590 mono_create_rgctx_lazy_fetch_trampoline (guint32 offset
)
1592 static gboolean inited
= FALSE
;
1593 static int num_trampolines
= 0;
1594 MonoTrampInfo
*info
;
1596 gpointer tramp
, ptr
;
1598 mono_trampolines_lock ();
1599 if (rgctx_lazy_fetch_trampoline_hash
)
1600 tramp
= g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash
, GUINT_TO_POINTER (offset
));
1603 mono_trampolines_unlock ();
1607 if (mono_aot_only
) {
1608 ptr
= mono_aot_get_lazy_fetch_trampoline (offset
);
1610 tramp
= mono_arch_create_rgctx_lazy_fetch_trampoline (offset
, &info
, FALSE
);
1611 mono_tramp_info_register (info
);
1612 ptr
= mono_create_ftnptr (mono_get_root_domain (), tramp
);
1615 mono_trampolines_lock ();
1616 if (!rgctx_lazy_fetch_trampoline_hash
) {
1617 rgctx_lazy_fetch_trampoline_hash
= g_hash_table_new (NULL
, NULL
);
1618 rgctx_lazy_fetch_trampoline_hash_addr
= g_hash_table_new (NULL
, NULL
);
1620 g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash
, GUINT_TO_POINTER (offset
), ptr
);
1621 g_assert (offset
!= -1);
1622 g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr
, ptr
, GUINT_TO_POINTER (offset
+ 1));
1623 mono_trampolines_unlock ();
1626 mono_counters_register ("RGCTX num lazy fetch trampolines",
1627 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &num_trampolines
);
1636 mono_create_monitor_enter_trampoline (void)
1638 static gpointer code
;
1640 if (mono_aot_only
) {
1642 code
= mono_aot_get_trampoline ("monitor_enter_trampoline");
1646 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1647 mono_trampolines_lock ();
1650 MonoTrampInfo
*info
;
1652 code
= mono_arch_create_monitor_enter_trampoline (&info
, FALSE
);
1653 mono_tramp_info_register (info
);
1656 mono_trampolines_unlock ();
1659 g_assert_not_reached ();
1666 mono_create_monitor_exit_trampoline (void)
1668 static gpointer code
;
1670 if (mono_aot_only
) {
1672 code
= mono_aot_get_trampoline ("monitor_exit_trampoline");
1676 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1677 mono_trampolines_lock ();
1680 MonoTrampInfo
*info
;
1682 code
= mono_arch_create_monitor_exit_trampoline (&info
, FALSE
);
1683 mono_tramp_info_register (info
);
1686 mono_trampolines_unlock ();
1689 g_assert_not_reached ();
1694 #ifdef MONO_ARCH_LLVM_SUPPORTED
1696 * mono_create_llvm_imt_trampoline:
1698 * LLVM compiled code can't pass in the IMT argument, so we use this trampoline, which
1699 * sets the IMT argument, then branches to the contents of the vtable slot given by
1700 * vt_offset in the vtable which is obtained from the argument list.
1703 mono_create_llvm_imt_trampoline (MonoDomain
*domain
, MonoMethod
*m
, int vt_offset
)
1705 #ifdef MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE
1706 return mono_arch_get_llvm_imt_trampoline (domain
, m
, vt_offset
);
1708 g_assert_not_reached ();
1715 mono_find_class_init_trampoline_by_addr (gconstpointer addr
)
1719 mono_trampolines_lock ();
1720 if (class_init_hash_addr
)
1721 res
= g_hash_table_lookup (class_init_hash_addr
, addr
);
1724 mono_trampolines_unlock ();
1729 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr
)
1733 mono_trampolines_lock ();
1734 if (rgctx_lazy_fetch_trampoline_hash_addr
) {
1735 /* We store the real offset + 1 so we can detect when the lookup fails */
1736 offset
= GPOINTER_TO_INT (g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash_addr
, addr
));
1744 mono_trampolines_unlock ();
1748 static const char*tramp_names
[MONO_TRAMPOLINE_NUM
] = {
1752 "generic_class_init",
1757 "restore_stack_prot",
1758 "generic_virtual_remoting",
1762 "handler_block_guard"
1766 * mono_get_generic_trampoline_name:
1768 * Returns a pointer to malloc-ed memory.
1771 mono_get_generic_trampoline_name (MonoTrampolineType tramp_type
)
1773 return g_strdup_printf ("generic_trampoline_%s", tramp_names
[tramp_type
]);
1777 * mono_get_rgctx_fetch_trampoline_name:
1779 * Returns a pointer to malloc-ed memory.
1782 mono_get_rgctx_fetch_trampoline_name (int slot
)
1787 mrgctx
= MONO_RGCTX_SLOT_IS_MRGCTX (slot
);
1788 index
= MONO_RGCTX_SLOT_INDEX (slot
);
1790 return g_strdup_printf ("rgctx_fetch_trampoline_%s_%d", mrgctx
? "mrgctx" : "rgctx", index
);
1794 mini_get_nullified_class_init_trampoline (void)
1796 static gpointer nullified_class_init_trampoline
;
1798 if (!nullified_class_init_trampoline
) {
1800 MonoTrampInfo
*info
;
1802 if (mono_aot_only
) {
1803 tramp
= mono_aot_get_trampoline ("nullified_class_init_trampoline");
1805 tramp
= mono_arch_get_nullified_class_init_trampoline (&info
);
1806 mono_tramp_info_register (info
);
1808 mono_memory_barrier ();
1809 nullified_class_init_trampoline
= tramp
;
1812 return nullified_class_init_trampoline
;