3 * (C) 2003 Ximian, Inc.
4 * (C) 2003-2011 Novell, Inc.
5 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include <mono/metadata/appdomain.h>
12 #include <mono/metadata/metadata-internals.h>
13 #include <mono/metadata/marshal.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/utils/mono-counters.h>
16 #include <mono/utils/mono-error-internals.h>
17 #include <mono/utils/mono-membar.h>
18 #include <mono/utils/mono-compiler.h>
19 #include <mono/utils/mono-threads-coop.h>
20 #include <mono/utils/unlocked.h>
24 #include "aot-runtime.h"
25 #include "mini-runtime.h"
27 #include "interp/interp.h"
30 * Address of the trampoline code. This is used by the debugger to check
31 * whether a method is a trampoline.
33 guint8
* mono_trampoline_code
[MONO_TRAMPOLINE_NUM
];
35 static GHashTable
*rgctx_lazy_fetch_trampoline_hash
;
36 static GHashTable
*rgctx_lazy_fetch_trampoline_hash_addr
;
38 static gint32 trampoline_calls
;
39 static gint32 jit_trampolines
;
40 static gint32 unbox_trampolines
;
41 static gint32 static_rgctx_trampolines
;
42 static gint32 rgctx_unmanaged_lookups
;
43 static gint32 rgctx_num_lazy_fetch_trampolines
;
45 #define mono_trampolines_lock() mono_os_mutex_lock (&trampolines_mutex)
46 #define mono_trampolines_unlock() mono_os_mutex_unlock (&trampolines_mutex)
47 static mono_mutex_t trampolines_mutex
;
49 #ifdef MONO_ARCH_GSHARED_SUPPORTED
57 rgctx_tramp_info_equal (gconstpointer ka
, gconstpointer kb
)
59 const RgctxTrampInfo
*i1
= (const RgctxTrampInfo
*)ka
;
60 const RgctxTrampInfo
*i2
= (const RgctxTrampInfo
*)kb
;
62 if (i1
->m
== i2
->m
&& i1
->addr
== i2
->addr
)
69 rgctx_tramp_info_hash (gconstpointer data
)
71 const RgctxTrampInfo
*info
= (const RgctxTrampInfo
*)data
;
73 return GPOINTER_TO_UINT (info
->m
) ^ GPOINTER_TO_UINT (info
->addr
);
77 * mono_create_static_rgctx_trampoline:
78 * \param m the mono method to create a trampoline for
79 * \param addr the address to jump to (where the compiled code for M lives)
81 * Creates a static rgctx trampoline for M which branches to ADDR which should
82 * point to the compiled code of M.
84 * Static rgctx trampolines are used when a shared generic method which doesn't
85 * have a this argument is called indirectly, ie. from code which can't pass in
86 * the rgctx argument. The trampoline sets the rgctx argument and jumps to the
87 * methods code. These trampolines are similar to the unbox trampolines, they
88 * perform the same task as the static rgctx wrappers, but they are smaller/faster,
89 * and can be made to work with full AOT.
91 * On PPC addr should be an ftnptr and the return value is an ftnptr too.
93 * \returns the generated static rgctx trampoline.
96 mono_create_static_rgctx_trampoline (MonoMethod
*m
, gpointer addr
)
101 RgctxTrampInfo tmp_info
;
102 RgctxTrampInfo
*info
;
103 MonoMemoryManager
*mem_manager
;
105 #ifdef PPC_USES_FUNCTION_DESCRIPTOR
106 g_assert (((gpointer
*)addr
) [2] == 0);
109 ctx
= mini_method_get_rgctx (m
);
111 domain
= mono_domain_get ();
112 mem_manager
= m_method_get_mem_manager (domain
, m
);
115 * In the AOT case, addr might point to either the method, or to an unbox trampoline,
116 * so make the hash keyed on the m+addr pair.
118 mono_domain_lock (domain
);
119 if (!domain_jit_info (domain
)->static_rgctx_trampoline_hash
)
120 domain_jit_info (domain
)->static_rgctx_trampoline_hash
= g_hash_table_new (rgctx_tramp_info_hash
, rgctx_tramp_info_equal
);
122 tmp_info
.addr
= addr
;
123 res
= g_hash_table_lookup (domain_jit_info (domain
)->static_rgctx_trampoline_hash
,
125 mono_domain_unlock (domain
);
130 res
= mono_aot_get_static_rgctx_trampoline (ctx
, addr
);
132 res
= mono_arch_get_static_rgctx_trampoline (mem_manager
, ctx
, addr
);
134 mono_domain_lock (domain
);
135 /* Duplicates inserted while we didn't hold the lock are OK */
136 info
= (RgctxTrampInfo
*)m_method_alloc (domain
, m
, sizeof (RgctxTrampInfo
));
139 g_hash_table_insert (domain_jit_info (domain
)->static_rgctx_trampoline_hash
, info
, res
);
141 UnlockedIncrement (&static_rgctx_trampolines
);
142 mono_domain_unlock (domain
);
149 mono_create_static_rgctx_trampoline (MonoMethod
*m
, gpointer addr
)
152 * This shouldn't happen as all arches which support generic sharing support
153 * static rgctx trampolines as well.
155 g_assert_not_reached ();
160 mono_create_ftnptr_arg_trampoline (gpointer arg
, gpointer addr
)
163 MonoMemoryManager
*mem_manager
= mono_domain_ambient_memory_manager (mono_domain_get ());
165 #ifdef MONO_ARCH_HAVE_FTNPTR_ARG_TRAMPOLINE
167 res
= mono_aot_get_ftnptr_arg_trampoline (arg
, addr
);
169 res
= mono_arch_get_ftnptr_arg_trampoline (mem_manager
, arg
, addr
);
172 res
= mono_aot_get_static_rgctx_trampoline (arg
, addr
);
174 res
= mono_arch_get_static_rgctx_trampoline (mem_manager
, arg
, addr
);
182 #define DEBUG_IMT(stmt) do { stmt; } while (0)
184 #define DEBUG_IMT(stmt) do { } while (0)
188 * mini_resolve_imt_method:
190 * Resolve the actual method called when making an IMT call through VTABLE_SLOT with IMT_METHOD as the interface method.
192 * Either IMPL_METHOD or OUT_AOT_ADDR will be set on return.
195 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
)
197 MonoMethod
*impl
= NULL
, *generic_virtual
= NULL
;
198 gboolean lookup_aot
, variance_used
= FALSE
, need_rgctx_tramp
= FALSE
;
199 guint8
*aot_addr
= NULL
;
200 int displacement
= vtable_slot
- ((gpointer
*)vt
);
201 int interface_offset
;
202 int imt_slot
= MONO_IMT_SIZE
+ displacement
;
204 g_assert (imt_slot
< MONO_IMT_SIZE
);
207 /* This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement */
208 interface_offset
= mono_class_interface_offset_with_variance (vt
->klass
, imt_method
->klass
, &variance_used
);
209 if (interface_offset
< 0)
210 g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (m_class_get_byval_arg (vt
->klass
), MONO_TYPE_NAME_FORMAT_IL
), mono_type_get_name_full (m_class_get_byval_arg (imt_method
->klass
), MONO_TYPE_NAME_FORMAT_IL
));
212 *variant_iface
= NULL
;
213 if (imt_method
->is_inflated
&& ((MonoMethodInflated
*)imt_method
)->context
.method_inst
) {
214 /* Generic virtual method */
215 generic_virtual
= imt_method
;
216 need_rgctx_tramp
= TRUE
;
217 } else if (variance_used
&& mono_class_has_variant_generic_params (imt_method
->klass
)) {
218 *variant_iface
= imt_method
;
221 /* We can only use the AOT compiled code if we don't require further processing */
222 lookup_aot
= !generic_virtual
& !variant_iface
;
225 mono_vtable_build_imt_slot (vt
, mono_method_get_imt_slot (imt_method
));
227 if (imt_method
->is_inflated
&& ((MonoMethodInflated
*)imt_method
)->context
.method_inst
) {
228 MonoGenericContext context
= { NULL
, NULL
};
231 * Generic virtual method, imt_method contains the inflated interface
232 * method, need to get the inflated impl method.
234 /* imt_method->slot might not be set */
235 impl
= mono_class_get_vtable_entry (vt
->klass
, interface_offset
+ mono_method_get_declaring_generic_method (imt_method
)->slot
);
237 if (mono_class_is_ginst (impl
->klass
))
238 context
.class_inst
= mono_class_get_generic_class (impl
->klass
)->context
.class_inst
;
239 context
.method_inst
= ((MonoMethodInflated
*)imt_method
)->context
.method_inst
;
240 impl
= mono_class_inflate_generic_method_checked (impl
, &context
, error
);
241 mono_error_assert_ok (error
);
244 /* Avoid loading metadata or creating a generic vtable if possible */
245 if (lookup_aot
&& !m_class_is_valuetype (vt
->klass
)) {
246 aot_addr
= (guint8
*)mono_aot_get_method_from_vt_slot (mono_domain_get (), vt
, interface_offset
+ mono_method_get_vtable_slot (imt_method
), error
);
247 return_val_if_nok (error
, NULL
);
254 impl
= mono_class_get_vtable_entry (vt
->klass
, interface_offset
+ mono_method_get_vtable_slot (imt_method
));
257 if (impl
&& mono_method_needs_static_rgctx_invoke (impl
, FALSE
))
258 need_rgctx_tramp
= TRUE
;
259 if (impl
&& impl
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_MANAGED
) {
260 WrapperInfo
*info
= mono_marshal_get_wrapper_info (impl
);
262 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
)
263 need_rgctx_tramp
= TRUE
;
266 *out_need_rgctx_tramp
= need_rgctx_tramp
;
267 *out_aot_addr
= aot_addr
;
269 DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
270 method
->klass
->name_space
, method
->klass
->name
, method
->name
,
271 imt_method
->klass
->name_space
, imt_method
->klass
->name
, imt_method
->name
));
273 if (vt
->imt_collisions_bitmap
& (1 << imt_slot
)) {
274 int slot
= mono_method_get_vtable_index (imt_method
);
277 g_assert (slot
!= -1);
278 vtable_offset
= interface_offset
+ slot
;
279 vtable_slot
= & (vt
->vtable
[vtable_offset
]);
280 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
));
283 DEBUG_IMT (printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot
, imt_slot
));
289 * This is a super-ugly hack to fix bug #616463.
291 * The problem is that we don't always set is_generic for generic
292 * method definitions. See the comment at the end of
293 * mono_class_inflate_generic_method_full_checked() in class.c.
296 is_generic_method_definition (MonoMethod
*m
)
298 MonoGenericContext
*context
;
304 context
= mono_method_get_context (m
);
305 if (!context
->method_inst
)
307 if (context
->method_inst
== mono_method_get_generic_container (((MonoMethodInflated
*)m
)->declaring
)->context
.method_inst
)
313 mini_jit_info_is_gsharedvt (MonoJitInfo
*ji
)
315 if (ji
&& ji
->has_generic_jit_info
&& (mono_jit_info_get_generic_sharing_context (ji
)->is_gsharedvt
))
322 * mini_add_method_trampoline:
325 * @add_static_rgctx_tramp: adds a static rgctx trampoline
326 * @add_unbox_tramp: adds an unboxing trampoline
328 * Add static rgctx/gsharedvt_in/unbox trampolines to
329 * M/COMPILED_METHOD if needed.
331 * Returns the trampoline address, or COMPILED_METHOD if no trampoline
335 mini_add_method_trampoline (MonoMethod
*m
, gpointer compiled_method
, gboolean add_static_rgctx_tramp
, gboolean add_unbox_tramp
)
337 gpointer addr
= compiled_method
;
338 gboolean callee_gsharedvt
= FALSE
, callee_array_helper
;
339 MonoMethod
*jmethod
= NULL
;
340 MonoJitInfo
*ji
= NULL
;
342 callee_array_helper
= FALSE
;
343 if (m
->wrapper_type
== MONO_WRAPPER_MANAGED_TO_MANAGED
) {
344 WrapperInfo
*info
= mono_marshal_get_wrapper_info (m
);
347 * generic array helpers.
348 * Have to replace the wrappers with the original generic instances.
350 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER
) {
351 callee_array_helper
= TRUE
;
352 m
= info
->d
.generic_array_helper
.method
;
354 } else if (m
->wrapper_type
== MONO_WRAPPER_OTHER
) {
355 WrapperInfo
*info
= mono_marshal_get_wrapper_info (m
);
357 /* Same for synchronized inner wrappers */
358 if (info
&& info
->subtype
== WRAPPER_SUBTYPE_SYNCHRONIZED_INNER
) {
359 m
= info
->d
.synchronized_inner
.method
;
363 if (m
->is_inflated
|| callee_array_helper
) {
364 // This loads information from AOT so try to avoid it if possible
365 ji
= mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
366 callee_gsharedvt
= mini_jit_info_is_gsharedvt (ji
);
369 if (callee_gsharedvt
)
370 g_assert (m
->is_inflated
);
372 addr
= compiled_method
;
374 if (add_unbox_tramp
) {
376 * The unbox trampolines call the method directly, so need to add
377 * an rgctx tramp before them.
380 addr
= mono_aot_get_unbox_trampoline (m
, addr
);
382 unbox_trampolines
++;
383 addr
= mono_arch_get_unbox_trampoline (m
, addr
);
387 if (ji
&& !ji
->is_trampoline
)
388 jmethod
= jinfo_get_method (ji
);
389 if (callee_gsharedvt
&& mini_is_gsharedvt_variable_signature (mono_method_signature_internal (jmethod
))) {
390 MonoMethodSignature
*sig
, *gsig
;
392 /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */
394 /* Call from normal/gshared code to gsharedvt code with variable signature */
395 sig
= mono_method_signature_internal (m
);
396 gsig
= mono_method_signature_internal (jmethod
);
398 addr
= mini_get_gsharedvt_wrapper (TRUE
, addr
, sig
, gsig
, -1, FALSE
);
401 g_assert_not_reached ();
402 //printf ("IN: %s\n", mono_method_full_name (m, TRUE));
405 if (callee_array_helper
) {
406 add_static_rgctx_tramp
= FALSE
;
407 /* In AOT mode, compiled_method points to one of the InternalArray methods in Array. */
408 if (ji
&& !mono_llvm_only
&& mono_method_needs_static_rgctx_invoke (jinfo_get_method (ji
), TRUE
))
409 add_static_rgctx_tramp
= TRUE
;
413 add_static_rgctx_tramp
= FALSE
;
415 if (add_static_rgctx_tramp
)
416 addr
= mono_create_static_rgctx_trampoline (m
, addr
);
422 * common_call_trampoline:
424 * The code to handle normal, virtual, and interface method calls and jumps, both
425 * from JITted and LLVM compiled code.
428 common_call_trampoline (host_mgreg_t
*regs
, guint8
*code
, MonoMethod
*m
, MonoVTable
*vt
, gpointer
*vtable_slot
, MonoError
*error
)
430 gpointer addr
, compiled_method
;
431 gboolean generic_shared
= FALSE
;
432 gboolean need_unbox_tramp
= FALSE
;
433 gboolean need_rgctx_tramp
= FALSE
;
434 MonoMethod
*declaring
= NULL
;
435 MonoMethod
*generic_virtual
= NULL
, *variant_iface
= NULL
;
437 gboolean imt_call
, virtual_
;
438 gpointer
*orig_vtable_slot
, *vtable_slot_to_patch
= NULL
;
439 MonoJitInfo
*ji
= NULL
;
440 MonoDomain
*domain
= mono_domain_get ();
441 MonoMethod
*orig_method
= m
;
445 virtual_
= vt
&& (gpointer
)vtable_slot
> (gpointer
)vt
;
446 imt_call
= vt
&& (gpointer
)vtable_slot
< (gpointer
)vt
;
449 * rgctx trampolines are needed when the call is indirect so the caller can't pass
450 * the rgctx argument needed by the callee.
453 need_rgctx_tramp
= mono_method_needs_static_rgctx_invoke (m
, FALSE
);
455 orig_vtable_slot
= vtable_slot
;
456 vtable_slot_to_patch
= vtable_slot
;
460 MonoMethod
*imt_method
= NULL
, *impl_method
= NULL
;
461 MonoObject
*this_arg
;
463 g_assert (vtable_slot
);
465 imt_method
= mono_arch_find_imt_method (regs
, code
);
466 this_arg
= (MonoObject
*)mono_arch_get_this_arg_from_call (regs
, code
);
468 if (mono_object_is_transparent_proxy (this_arg
)) {
469 /* Use the slow path for now */
470 m
= mono_object_get_virtual_method_internal (this_arg
, imt_method
);
471 vtable_slot_to_patch
= NULL
;
473 if (imt_method
->is_inflated
&& ((MonoMethodInflated
*)imt_method
)->context
.method_inst
) {
474 /* Generic virtual method */
475 generic_virtual
= imt_method
;
476 need_rgctx_tramp
= TRUE
;
479 vtable_slot
= mini_resolve_imt_method (vt
, vtable_slot
, imt_method
, &impl_method
, &addr
, &need_rgctx_tramp
, &variant_iface
, error
);
480 return_val_if_nok (error
, NULL
);
482 if (mono_class_has_dim_conflicts (vt
->klass
)) {
483 GSList
*conflicts
= mono_class_get_dim_conflicts (vt
->klass
);
485 MonoMethod
*decl
= imt_method
;
487 if (decl
->is_inflated
)
488 decl
= mono_method_get_declaring_generic_method (decl
);
490 gboolean in_conflict
= FALSE
;
491 for (l
= conflicts
; l
; l
= l
->next
) {
492 if (decl
== l
->data
) {
498 char *class_name
= mono_class_full_name (vt
->klass
);
499 char *method_name
= mono_method_full_name (decl
, TRUE
);
500 mono_error_set_ambiguous_implementation (error
, "Could not call method '%s' with type '%s' because there are multiple incompatible interface methods overriding this method.", method_name
, class_name
);
502 g_free (method_name
);
507 /* We must handle magic interfaces on rank 1 arrays of ref types as if they were variant */
508 if (!variant_iface
&& m_class_get_rank (vt
->klass
) == 1 && !m_class_is_valuetype (m_class_get_element_class (vt
->klass
)) && m_class_is_array_special_interface (imt_method
->klass
))
509 variant_iface
= imt_method
;
511 /* This is the vcall slot which gets called through the IMT trampoline */
512 vtable_slot_to_patch
= vtable_slot
;
516 * We found AOT compiled code for the method, skip the rest.
518 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot
))
521 return mono_create_ftnptr (mono_domain_get (), addr
);
529 * The virtual check is needed because is_generic_method_definition (m) could
530 * return TRUE for methods used in IMT calls too.
532 if (virtual_
&& is_generic_method_definition (m
)) {
533 MonoGenericContext context
= { NULL
, NULL
};
534 MonoMethod
*declaring
;
537 declaring
= mono_method_get_declaring_generic_method (m
);
541 if (mono_class_is_ginst (m
->klass
))
542 context
.class_inst
= mono_class_get_generic_class (m
->klass
)->context
.class_inst
;
544 g_assert (!mono_class_is_gtd (m
->klass
));
546 generic_virtual
= mono_arch_find_imt_method (regs
, code
);
547 g_assert (generic_virtual
);
548 g_assert (generic_virtual
->is_inflated
);
549 context
.method_inst
= ((MonoMethodInflated
*)generic_virtual
)->context
.method_inst
;
551 m
= mono_class_inflate_generic_method_checked (declaring
, &context
, error
);
552 mono_error_assert_ok (error
);
553 /* FIXME: only do this if the method is sharable */
554 need_rgctx_tramp
= TRUE
;
555 } else if ((context_used
= mono_method_check_context_used (m
))) {
556 MonoClass
*klass
= NULL
;
557 MonoMethod
*actual_method
= NULL
;
558 MonoVTable
*vt
= NULL
;
559 MonoGenericInst
*method_inst
= NULL
;
562 generic_shared
= TRUE
;
565 * The caller is gshared code, compute the actual method to call from M and this/rgctx.
567 if (m
->is_inflated
&& (mono_method_get_context (m
)->method_inst
|| mini_method_is_default_method (m
))) {
568 MonoMethodRuntimeGenericContext
*mrgctx
= (MonoMethodRuntimeGenericContext
*)mono_arch_find_static_call_vtable (regs
, code
);
570 klass
= mrgctx
->class_vtable
->klass
;
571 method_inst
= mrgctx
->method_inst
;
572 } else if ((m
->flags
& METHOD_ATTRIBUTE_STATIC
) || m_class_is_valuetype (m
->klass
)) {
573 MonoVTable
*vtable
= mono_arch_find_static_call_vtable (regs
, code
);
575 klass
= vtable
->klass
;
577 MonoObject
*this_argument
= (MonoObject
*)mono_arch_get_this_arg_from_call (regs
, code
);
579 vt
= this_argument
->vtable
;
580 vtable_slot
= orig_vtable_slot
;
582 g_assert (m_class_is_inited (this_argument
->vtable
->klass
));
585 mono_class_setup_supertypes (this_argument
->vtable
->klass
);
586 klass
= m_class_get_supertypes (this_argument
->vtable
->klass
) [m_class_get_idepth (m
->klass
) - 1];
590 g_assert (vtable_slot
|| klass
);
593 int displacement
= vtable_slot
- ((gpointer
*)vt
);
595 g_assert_not_reached ();
597 g_assert (displacement
> 0);
599 actual_method
= m_class_get_vtable (vt
->klass
) [displacement
];
602 if (method_inst
|| m
->wrapper_type
) {
603 MonoGenericContext context
= { NULL
, NULL
};
606 declaring
= mono_method_get_declaring_generic_method (m
);
610 if (mono_class_is_ginst (klass
))
611 context
.class_inst
= mono_class_get_generic_class (klass
)->context
.class_inst
;
612 else if (mono_class_is_gtd (klass
))
613 context
.class_inst
= mono_class_get_generic_container (klass
)->context
.class_inst
;
614 context
.method_inst
= method_inst
;
616 actual_method
= mono_class_inflate_generic_method_checked (declaring
, &context
, error
);
617 mono_error_assert_ok (error
);
619 actual_method
= mono_class_get_method_generic (klass
, m
, error
);
620 mono_error_assert_ok (error
);
624 g_assert (actual_method
);
625 g_assert (actual_method
->klass
== klass
);
627 if (actual_method
->is_inflated
)
628 declaring
= mono_method_get_declaring_generic_method (actual_method
);
635 if (m
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
) {
636 m
= mono_marshal_get_synchronized_wrapper (m
);
637 need_rgctx_tramp
= FALSE
;
640 addr
= compiled_method
= mono_jit_compile_method (m
, error
);
644 if (generic_virtual
|| variant_iface
) {
645 if (m_class_is_valuetype (vt
->klass
) && !mini_method_is_default_method (m
)) /*FIXME is this required variant iface?*/
646 need_unbox_tramp
= TRUE
;
647 } else if (orig_vtable_slot
) {
648 if (m_class_is_valuetype (m
->klass
)) {
649 g_assert (!mini_method_is_default_method (m
));
650 need_unbox_tramp
= TRUE
;
654 addr
= mini_add_method_trampoline (m
, compiled_method
, need_rgctx_tramp
, need_unbox_tramp
);
656 if (generic_virtual
|| variant_iface
) {
657 MonoMethod
*target
= generic_virtual
? generic_virtual
: variant_iface
;
659 vtable_slot
= orig_vtable_slot
;
660 g_assert (vtable_slot
);
662 mono_method_add_generic_virtual_invocation (mono_domain_get (),
669 /* the method was jumped to */
671 mini_patch_jump_sites (domain
, m
, mono_get_addr_from_ftnptr (addr
));
673 /* Patch the got entries pointing to this method */
675 * We do this here instead of in mono_codegen () to cover the case when m
676 * was loaded from an aot image.
678 if (domain_jit_info (domain
)->jump_target_got_slot_hash
) {
680 MonoMethod
*shared_method
= mini_method_to_shared (m
);
681 m
= shared_method
? shared_method
: m
;
683 mono_domain_lock (domain
);
684 list
= (GSList
*)g_hash_table_lookup (domain_jit_info (domain
)->jump_target_got_slot_hash
, m
);
686 for (tmp
= list
; tmp
; tmp
= tmp
->next
) {
687 gpointer
*got_slot
= (gpointer
*)tmp
->data
;
690 g_hash_table_remove (domain_jit_info (domain
)->jump_target_got_slot_hash
, m
);
693 mono_domain_unlock (domain
);
699 vtable_slot
= orig_vtable_slot
;
702 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
))) {
703 g_assert (*vtable_slot_to_patch
);
704 *vtable_slot_to_patch
= mono_get_addr_from_ftnptr (addr
);
707 guint8
*plt_entry
= mono_aot_get_plt_entry (regs
, code
);
708 gboolean no_patch
= FALSE
;
709 MonoJitInfo
*target_ji
;
712 if (generic_shared
) {
714 mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
716 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)code
, NULL
);
718 if (ji
&& ji
->has_generic_jit_info
) {
719 if (target_ji
&& !target_ji
->has_generic_jit_info
) {
721 } else if (mono_use_interpreter
&& !target_ji
) {
722 /* compiled_method might be an interp entry trampoline and the interpreter has no generic sharing */
728 mono_aot_patch_plt_entry (NULL
, code
, plt_entry
, NULL
, regs
, (guint8
*)addr
);
730 if (generic_shared
) {
731 if (m
->wrapper_type
!= MONO_WRAPPER_NONE
)
732 m
= mono_marshal_method_from_wrapper (m
);
733 //g_assert (mono_method_is_generic_sharable (m, FALSE));
736 /* Patch calling code */
738 mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method
), NULL
);
740 ji
= mini_jit_info_table_find (mono_domain_get (), (char*)code
, NULL
);
742 if (ji
&& target_ji
&& generic_shared
&& ji
->has_generic_jit_info
&& !target_ji
->has_generic_jit_info
) {
744 * Can't patch the call as the caller is gshared, but the callee is not. Happens when
745 * generic sharing fails.
746 * FIXME: Performance problem.
751 mini_patch_llvm_jit_callees (domain
, orig_method
, addr
);
752 /* LLVM code doesn't make direct calls */
753 if (ji
&& ji
->from_llvm
)
755 if (!no_patch
&& mono_method_same_domain (ji
, target_ji
))
756 mono_arch_patch_callsite ((guint8
*)ji
->code_start
, code
, (guint8
*)addr
);
764 * mono_magic_trampoline:
766 * This trampoline handles normal calls from JITted code.
769 mono_magic_trampoline (host_mgreg_t
*regs
, guint8
*code
, gpointer arg
, guint8
* tramp
)
774 MONO_ENTER_GC_UNSAFE
;
776 g_assert (mono_thread_is_gc_unsafe_mode ());
778 UnlockedIncrement (&trampoline_calls
);
780 res
= common_call_trampoline (regs
, code
, (MonoMethod
*)arg
, NULL
, NULL
, error
);
781 if (!is_ok (error
)) {
782 mono_error_set_pending_exception (error
);
791 * mono_vcall_trampoline:
793 * This trampoline handles virtual calls.
796 mono_vcall_trampoline (host_mgreg_t
*regs
, guint8
*code
, int slot
, guint8
*tramp
)
799 MONO_ENTER_GC_UNSAFE
;
801 MonoObject
*this_arg
;
803 gpointer
*vtable_slot
;
809 UnlockedIncrement (&trampoline_calls
);
812 * We need to obtain the following pieces of information:
813 * - the method which needs to be compiled.
815 * We use one vtable trampoline per vtable slot index, so we need only the vtable,
816 * the other two can be computed from the vtable + the slot index.
820 * Obtain the vtable from the 'this' arg.
822 this_arg
= (MonoObject
*)mono_arch_get_this_arg_from_call (regs
, code
);
825 vt
= this_arg
->vtable
;
828 /* Normal virtual call */
829 vtable_slot
= &(vt
->vtable
[slot
]);
831 /* Avoid loading metadata or creating a generic vtable if possible */
832 addr
= mono_aot_get_method_from_vt_slot (mono_domain_get (), vt
, slot
, error
);
833 goto_if_nok (error
, leave
);
834 if (addr
&& !m_class_is_valuetype (vt
->klass
)) {
835 if (mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot
))
838 res
= mono_create_ftnptr (mono_domain_get (), addr
);
844 * is_generic_method_definition() above) also
845 * goes away if we do a
846 * mono_class_setup_vtable (vt->klass) here,
847 * because we then inflate the method
848 * correctly, put it in the cache, and the
849 * "wrong" inflation invocation still looks up
850 * the correctly inflated method.
852 * The hack above seems more stable and
855 m
= mono_class_get_vtable_entry (vt
->klass
, slot
);
858 vtable_slot
= &(((gpointer
*)vt
) [slot
]);
863 res
= common_call_trampoline (regs
, code
, m
, vt
, vtable_slot
, error
);
865 if (!is_ok (error
)) {
866 mono_error_set_pending_exception (error
);
873 #ifndef DISABLE_REMOTING
875 mono_generic_virtual_remoting_trampoline (host_mgreg_t
*regs
, guint8
*code
, MonoMethod
*m
, guint8
*tramp
)
877 MONO_REQ_GC_UNSAFE_MODE
;
880 MonoGenericContext context
= { NULL
, NULL
};
881 MonoMethod
*imt_method
, *declaring
;
884 UnlockedIncrement (&trampoline_calls
);
886 g_assert (m
->is_generic
);
889 declaring
= mono_method_get_declaring_generic_method (m
);
893 if (mono_class_is_ginst (m
->klass
))
894 context
.class_inst
= mono_class_get_generic_class (m
->klass
)->context
.class_inst
;
896 g_assert (!mono_class_is_gtd (m
->klass
));
898 imt_method
= mono_arch_find_imt_method (regs
, code
);
899 if (imt_method
->is_inflated
)
900 context
.method_inst
= ((MonoMethodInflated
*)imt_method
)->context
.method_inst
;
901 m
= mono_class_inflate_generic_method_checked (declaring
, &context
, error
);
902 g_assert (is_ok (error
)); /* FIXME don't swallow the error */;
903 m
= mono_marshal_get_remoting_invoke_with_check (m
, error
);
904 if (!is_ok (error
)) {
905 mono_error_set_pending_exception (error
);
909 addr
= mono_jit_compile_method (m
, error
);
910 if (!is_ok (error
)) {
911 mono_error_set_pending_exception (error
);
921 * mono_aot_trampoline:
923 * This trampoline handles calls made from AOT code. We try to bypass the
924 * normal JIT compilation logic to avoid loading the metadata for the method.
926 #ifdef MONO_ARCH_AOT_SUPPORTED
928 mono_aot_trampoline (host_mgreg_t
*regs
, guint8
*code
, guint8
*token_info
,
931 MONO_REQ_GC_UNSAFE_MODE
;
935 MonoMethod
*method
= NULL
;
940 UnlockedIncrement (&trampoline_calls
);
942 image
= (MonoImage
*)*(gpointer
*)token_info
;
943 token_info
+= sizeof (gpointer
);
944 token
= *(guint32
*)token_info
;
946 addr
= mono_aot_get_method_from_token (mono_domain_get (), image
, token
, error
);
948 mono_error_cleanup (error
);
950 method
= mono_get_method_checked (image
, token
, NULL
, NULL
, error
);
952 g_error ("Could not load AOT trampoline due to %s", mono_error_get_message (error
));
954 /* Use the generic code */
955 return mono_magic_trampoline (regs
, code
, method
, tramp
);
958 addr
= mono_create_ftnptr (mono_domain_get (), addr
);
960 /* This is a normal call through a PLT entry */
961 plt_entry
= mono_aot_get_plt_entry (regs
, code
);
962 g_assert (plt_entry
);
964 mono_aot_patch_plt_entry (NULL
, code
, plt_entry
, NULL
, regs
, (guint8
*)addr
);
970 * mono_aot_plt_trampoline:
972 * This trampoline handles calls made from AOT code through the PLT table.
975 mono_aot_plt_trampoline (host_mgreg_t
*regs
, guint8
*code
, guint8
*aot_module
,
981 MONO_ENTER_GC_UNSAFE
;
982 UnlockedIncrement (&trampoline_calls
);
984 res
= mono_aot_plt_resolve (aot_module
, regs
, code
, error
);
986 if (!is_ok (error
)) {
987 mono_error_set_pending_exception (error
);
990 // FIXME: Error handling (how ?)
1001 mono_rgctx_lazy_fetch_trampoline (host_mgreg_t
*regs
, guint8
*code
, gpointer data
, guint8
*tramp
)
1003 MONO_REQ_GC_UNSAFE_MODE
;
1005 guint32 slot
= GPOINTER_TO_UINT (data
);
1006 gpointer arg
= (gpointer
)(gssize
)regs
[MONO_ARCH_VTABLE_REG
];
1007 guint32 index
= MONO_RGCTX_SLOT_INDEX (slot
);
1008 gboolean mrgctx
= MONO_RGCTX_SLOT_IS_MRGCTX (slot
);
1012 UnlockedIncrement (&trampoline_calls
);
1013 UnlockedIncrement (&rgctx_unmanaged_lookups
);
1016 res
= mono_method_fill_runtime_generic_context ((MonoMethodRuntimeGenericContext
*)arg
, index
, error
);
1018 res
= mono_class_fill_runtime_generic_context ((MonoVTable
*)arg
, index
, error
);
1019 if (!is_ok (error
)) {
1020 mono_error_set_pending_exception (error
);
1027 * mono_delegate_trampoline:
1029 * This trampoline handles calls made to Delegate:Invoke ().
1030 * This is called once the first time a delegate is invoked, so it must be fast.
1033 mono_delegate_trampoline (host_mgreg_t
*regs
, guint8
*code
, gpointer
*arg
, guint8
* tramp
)
1035 MONO_REQ_GC_UNSAFE_MODE
;
1037 MonoDomain
*domain
= mono_domain_get ();
1038 MonoDelegate
*delegate
;
1041 MonoMethod
*method
= NULL
;
1043 gboolean multicast
, callvirt
= FALSE
, closed_over_null
= FALSE
;
1044 gboolean need_rgctx_tramp
= FALSE
;
1045 gboolean need_unbox_tramp
= FALSE
;
1046 gboolean enable_caching
= TRUE
;
1047 MonoDelegateTrampInfo
*tramp_info
= (MonoDelegateTrampInfo
*)arg
;
1048 MonoMethod
*invoke
= tramp_info
->invoke
;
1049 guint8
*impl_this
= (guint8
*)tramp_info
->impl_this
;
1050 guint8
*impl_nothis
= (guint8
*)tramp_info
->impl_nothis
;
1052 MonoMethodSignature
*sig
;
1053 gpointer addr
, compiled_method
;
1054 gboolean is_remote
= FALSE
;
1056 UnlockedIncrement (&trampoline_calls
);
1058 /* Obtain the delegate object according to the calling convention */
1059 delegate
= (MonoDelegate
*)mono_arch_get_this_arg_from_call (regs
, code
);
1060 g_assert (mono_class_has_parent (mono_object_class (delegate
), mono_defaults
.multicastdelegate_class
));
1062 if (delegate
->method
) {
1063 method
= delegate
->method
;
1066 * delegate->method_ptr == NULL means the delegate was initialized by
1067 * mini_delegate_ctor, while != NULL means it is initialized by
1068 * mono_delegate_ctor_with_method (). In both cases, we need to add wrappers
1069 * (ctor_with_method () does this, but it doesn't store the wrapper back into
1070 * delegate->method).
1072 #ifndef DISABLE_REMOTING
1073 if (delegate
->target
&& mono_object_is_transparent_proxy (delegate
->target
)) {
1077 if (((MonoTransparentProxy
*)delegate
->target
)->remote_class
->proxy_class
!= mono_class_get_com_object_class () &&
1078 !mono_class_is_com_object (((MonoTransparentProxy
*)delegate
->target
)->remote_class
->proxy_class
))
1080 method
= mono_marshal_get_remoting_invoke (method
, err
);
1082 mono_error_set_pending_exception (err
);
1088 sig
= tramp_info
->sig
;
1089 if (!(sig
&& method
== tramp_info
->method
)) {
1091 sig
= mono_method_signature_checked (method
, err
);
1093 mono_error_set_pending_exception (err
);
1098 if (sig
->hasthis
&& m_class_is_valuetype (method
->klass
)) {
1099 gboolean need_unbox
= TRUE
;
1101 if (tramp_info
->invoke_sig
->param_count
> sig
->param_count
&& tramp_info
->invoke_sig
->params
[0]->byref
)
1106 need_unbox_tramp
= TRUE
;
1108 method
= mono_marshal_get_unbox_wrapper (method
);
1112 // If "delegate->method_ptr" is null mono_get_addr_from_ftnptr will fail if
1113 // ftnptrs are being used. "method" would end up null on archtitectures without
1114 // ftnptrs so we can just skip this.
1115 } else if (delegate
->method_ptr
) {
1116 ji
= mono_jit_info_table_find (domain
, mono_get_addr_from_ftnptr (delegate
->method_ptr
));
1118 method
= jinfo_get_method (ji
);
1122 sig
= tramp_info
->sig
;
1123 if (!(sig
&& method
== tramp_info
->method
)) {
1125 sig
= mono_method_signature_checked (method
, err
);
1127 mono_error_set_pending_exception (err
);
1132 callvirt
= !delegate
->target
&& sig
->hasthis
;
1134 closed_over_null
= tramp_info
->invoke_sig
->param_count
== sig
->param_count
;
1136 if (callvirt
&& !closed_over_null
) {
1138 * The delegate needs to make a virtual call to the target method using its
1139 * first argument as the receiver. This is hard to support in full-aot, so
1140 * optimize it in some cases if possible.
1141 * If the target method is not virtual or is in a sealed class,
1142 * the vcall will call it directly.
1143 * If the call doesn't return a valuetype, then the vcall uses the same calling
1144 * convention as a normal call.
1146 if ((mono_class_is_sealed (method
->klass
) || !(method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) && !MONO_TYPE_ISSTRUCT (sig
->ret
)) {
1148 enable_caching
= FALSE
;
1152 if (delegate
->method_ptr
== NULL
&& tramp_info
->method
== NULL
&& delegate
->target
!= NULL
&& method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) {
1153 /* tramp_info->method == NULL happens when someone asks us to JIT some delegate's
1154 * Invoke method (see compile_special). In that case if method is virtual, the target
1155 * could be some derived class, so we need to find the correct override.
1157 /* FIXME: does it make sense that we get called with tramp_info for the Invoke? */
1158 method
= mono_object_get_virtual_method_internal (delegate
->target
, method
);
1159 enable_caching
= FALSE
;
1160 } else if (delegate
->target
&&
1161 method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
&&
1162 method
->flags
& METHOD_ATTRIBUTE_ABSTRACT
&&
1163 mono_class_is_abstract (method
->klass
)) {
1164 method
= mono_object_get_virtual_method_internal (delegate
->target
, method
);
1165 enable_caching
= FALSE
;
1168 if (method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1169 method
= mono_marshal_get_synchronized_wrapper (method
);
1171 if (method
== tramp_info
->method
)
1172 need_rgctx_tramp
= tramp_info
->need_rgctx_tramp
;
1173 else if (mono_method_needs_static_rgctx_invoke (method
, FALSE
))
1174 need_rgctx_tramp
= TRUE
;
1178 * If the called address is a trampoline, replace it with the compiled method so
1179 * further calls don't have to go through the trampoline.
1181 if (method
&& !callvirt
) {
1182 /* Avoid the overhead of looking up an already compiled method if possible */
1183 if (enable_caching
&& delegate
->method_code
&& *delegate
->method_code
) {
1184 delegate
->method_ptr
= *delegate
->method_code
;
1186 compiled_method
= addr
= mono_jit_compile_method (method
, error
);
1187 if (!is_ok (error
)) {
1188 mono_error_set_pending_exception (error
);
1191 addr
= mini_add_method_trampoline (method
, compiled_method
, need_rgctx_tramp
, need_unbox_tramp
);
1192 delegate
->method_ptr
= addr
;
1193 if (enable_caching
&& delegate
->method_code
)
1194 *delegate
->method_code
= (guint8
*)delegate
->method_ptr
;
1197 if (need_rgctx_tramp
)
1198 delegate
->method_ptr
= mono_create_static_rgctx_trampoline (method
, delegate
->method_ptr
);
1201 /* Necessary for !code condition to fallback to slow path */
1204 multicast
= ((MonoMulticastDelegate
*)delegate
)->delegates
!= NULL
;
1205 if (!multicast
&& !callvirt
) {
1206 if (method
&& (method
->flags
& METHOD_ATTRIBUTE_STATIC
) && mono_method_signature_internal (method
)->param_count
== mono_method_signature_internal (invoke
)->param_count
+ 1)
1207 /* Closed static delegate */
1210 code
= delegate
->target
? impl_this
: impl_nothis
;
1214 /* The general, unoptimized case */
1215 m
= mono_marshal_get_delegate_invoke (invoke
, delegate
);
1216 code
= (guint8
*)mono_jit_compile_method (m
, error
);
1217 if (!is_ok (error
)) {
1218 mono_error_set_pending_exception (error
);
1221 code
= (guint8
*)mini_add_method_trampoline (m
, code
, mono_method_needs_static_rgctx_invoke (m
, FALSE
), FALSE
);
1224 delegate
->invoke_impl
= mono_get_addr_from_ftnptr (code
);
1225 if (enable_caching
&& !callvirt
&& tramp_info
->method
) {
1226 tramp_info
->method_ptr
= delegate
->method_ptr
;
1227 tramp_info
->invoke_impl
= delegate
->invoke_impl
;
1234 * mono_get_trampoline_func:
1236 * Return the C function which needs to be called by the generic trampoline of type
1240 mono_get_trampoline_func (MonoTrampolineType tramp_type
)
1242 switch (tramp_type
) {
1243 case MONO_TRAMPOLINE_JIT
:
1244 case MONO_TRAMPOLINE_JUMP
:
1245 return (gconstpointer
)mono_magic_trampoline
;
1246 case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
:
1247 return (gconstpointer
)mono_rgctx_lazy_fetch_trampoline
;
1248 #ifdef MONO_ARCH_AOT_SUPPORTED
1249 case MONO_TRAMPOLINE_AOT
:
1250 return (gconstpointer
)mono_aot_trampoline
;
1251 case MONO_TRAMPOLINE_AOT_PLT
:
1252 return (gconstpointer
)mono_aot_plt_trampoline
;
1254 case MONO_TRAMPOLINE_DELEGATE
:
1255 return (gconstpointer
)mono_delegate_trampoline
;
1256 #ifndef DISABLE_REMOTING
1257 case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
:
1258 return (gconstpointer
)mono_generic_virtual_remoting_trampoline
;
1260 case MONO_TRAMPOLINE_VCALL
:
1261 return (gconstpointer
)mono_vcall_trampoline
;
1263 g_assert_not_reached ();
1269 create_trampoline_code (MonoTrampolineType tramp_type
)
1271 MonoTrampInfo
*info
;
1274 code
= mono_arch_create_generic_trampoline (tramp_type
, &info
, FALSE
);
1275 mono_tramp_info_register (info
, NULL
);
1281 mono_trampolines_init (void)
1283 mono_os_mutex_init_recursive (&trampolines_mutex
);
1284 gboolean disable_tramps
= FALSE
;
1286 disable_tramps
= TRUE
;
1289 if (mono_aot_only
|| disable_tramps
)
1292 mono_trampoline_code
[MONO_TRAMPOLINE_JIT
] = create_trampoline_code (MONO_TRAMPOLINE_JIT
);
1293 mono_trampoline_code
[MONO_TRAMPOLINE_JUMP
] = create_trampoline_code (MONO_TRAMPOLINE_JUMP
);
1294 mono_trampoline_code
[MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
] = create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH
);
1295 #ifdef MONO_ARCH_AOT_SUPPORTED
1296 mono_trampoline_code
[MONO_TRAMPOLINE_AOT
] = create_trampoline_code (MONO_TRAMPOLINE_AOT
);
1297 mono_trampoline_code
[MONO_TRAMPOLINE_AOT_PLT
] = create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT
);
1299 mono_trampoline_code
[MONO_TRAMPOLINE_DELEGATE
] = create_trampoline_code (MONO_TRAMPOLINE_DELEGATE
);
1300 #ifndef DISABLE_REMOTING
1301 mono_trampoline_code
[MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING
);
1303 mono_trampoline_code
[MONO_TRAMPOLINE_VCALL
] = create_trampoline_code (MONO_TRAMPOLINE_VCALL
);
1305 mono_counters_register ("Calls to trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &trampoline_calls
);
1306 mono_counters_register ("JIT trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &jit_trampolines
);
1307 mono_counters_register ("Unbox trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &unbox_trampolines
);
1308 mono_counters_register ("Static rgctx trampolines", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &static_rgctx_trampolines
);
1309 mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_unmanaged_lookups
);
1310 mono_counters_register ("RGCTX num lazy fetch trampolines", MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &rgctx_num_lazy_fetch_trampolines
);
1314 mono_trampolines_cleanup (void)
1316 g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash
);
1317 g_hash_table_destroy (rgctx_lazy_fetch_trampoline_hash_addr
);
1318 mono_os_mutex_destroy (&trampolines_mutex
);
1322 mono_get_trampoline_code (MonoTrampolineType tramp_type
)
1324 g_assert (mono_trampoline_code
[tramp_type
]);
1326 return mono_trampoline_code
[tramp_type
];
1330 mono_create_specific_trampoline (gpointer arg1
, MonoTrampolineType tramp_type
, MonoDomain
*domain
, guint32
*code_len
)
1334 MonoMemoryManager
*mem_manager
= mono_domain_ambient_memory_manager (domain
);
1337 code
= mono_aot_create_specific_trampoline (arg1
, tramp_type
, domain
, &len
);
1339 code
= mono_arch_create_specific_trampoline (arg1
, tramp_type
, mem_manager
, &len
);
1340 mono_lldb_save_specific_trampoline_info (arg1
, tramp_type
, domain
, code
, len
);
1347 mono_create_jump_trampoline (MonoDomain
*domain
, MonoMethod
*method
, gboolean add_sync_wrapper
, MonoError
*error
)
1351 guint32 code_size
= 0;
1355 if (mono_use_interpreter
&& !mono_aot_only
) {
1356 gpointer ret
= mini_get_interp_callbacks ()->create_method_pointer (method
, FALSE
, error
);
1362 code
= mono_jit_find_compiled_method_with_jit_info (domain
, method
, &ji
);
1364 * We cannot recover the correct type of a shared generic
1365 * method from its native code address, so we use the
1366 * trampoline instead.
1367 * For synchronized methods, the trampoline adds the wrapper.
1369 if (code
&& !ji
->has_generic_jit_info
&& !(method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
))
1372 if (mono_llvm_only
) {
1373 code
= mono_jit_compile_method (method
, error
);
1379 mono_domain_lock (domain
);
1380 code
= g_hash_table_lookup (domain_jit_info (domain
)->jump_trampoline_hash
, method
);
1381 mono_domain_unlock (domain
);
1385 code
= mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_JUMP
, mono_domain_get (), &code_size
);
1386 g_assert (code_size
);
1388 ji
= (MonoJitInfo
*)m_method_alloc0 (domain
, method
, MONO_SIZEOF_JIT_INFO
);
1389 ji
->code_start
= MINI_FTNPTR_TO_ADDR (code
);
1390 ji
->code_size
= code_size
;
1391 ji
->d
.method
= method
;
1394 * mono_delegate_ctor needs to find the method metadata from the
1395 * trampoline address, so we save it here.
1398 mono_jit_info_table_add (domain
, ji
);
1400 mono_domain_lock (domain
);
1401 g_hash_table_insert (domain_jit_info (domain
)->jump_trampoline_hash
, method
, code
);
1402 mono_domain_unlock (domain
);
1408 method_not_found (void)
1410 g_assert_not_reached ();
1414 mono_create_jit_trampoline (MonoDomain
*domain
, MonoMethod
*method
, MonoError
*error
)
1420 if (mono_aot_only
) {
1421 if (mono_llvm_only
&& method
->iflags
& METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED
)
1422 method
= mono_marshal_get_synchronized_wrapper (method
);
1424 /* Avoid creating trampolines if possible */
1425 gpointer code
= mono_jit_find_compiled_method (domain
, method
);
1429 if (mono_llvm_only
) {
1430 if (method
->wrapper_type
== MONO_WRAPPER_PROXY_ISINST
)
1431 /* These wrappers are not generated */
1432 return (gpointer
)method_not_found
;
1433 /* Methods are lazily initialized on first call, so this can't lead recursion */
1434 code
= mono_jit_compile_method (method
, error
);
1441 mono_domain_lock (domain
);
1442 tramp
= g_hash_table_lookup (domain_jit_info (domain
)->jit_trampoline_hash
, method
);
1443 mono_domain_unlock (domain
);
1447 tramp
= mono_create_specific_trampoline (method
, MONO_TRAMPOLINE_JIT
, domain
, NULL
);
1449 mono_domain_lock (domain
);
1450 g_hash_table_insert (domain_jit_info (domain
)->jit_trampoline_hash
, method
, tramp
);
1451 UnlockedIncrement (&jit_trampolines
);
1452 mono_domain_unlock (domain
);
1458 mono_create_jit_trampoline_from_token (MonoImage
*image
, guint32 token
)
1462 MonoDomain
*domain
= mono_domain_get ();
1463 guint8
*buf
, *start
;
1465 buf
= start
= (guint8
*)mono_domain_alloc0 (domain
, 2 * sizeof (gpointer
));
1467 *(gpointer
*)buf
= image
;
1468 buf
+= sizeof (gpointer
);
1469 *(guint32
*)buf
= token
;
1471 tramp
= mono_create_specific_trampoline (start
, MONO_TRAMPOLINE_AOT
, domain
, NULL
);
1473 UnlockedIncrement (&jit_trampolines
);
1480 * mono_create_delegate_trampoline_info:
1482 * Create a trampoline info structure for the KLASS+METHOD pair.
1484 MonoDelegateTrampInfo
*
1485 mono_create_delegate_trampoline_info (MonoDomain
*domain
, MonoClass
*klass
, MonoMethod
*method
)
1489 MonoDelegateTrampInfo
*tramp_info
;
1490 MonoClassMethodPair pair
, *dpair
;
1491 guint32 code_size
= 0;
1494 pair
.method
= method
;
1495 mono_domain_lock (domain
);
1496 tramp_info
= (MonoDelegateTrampInfo
*)g_hash_table_lookup (domain_jit_info (domain
)->delegate_trampoline_hash
, &pair
);
1497 mono_domain_unlock (domain
);
1501 invoke
= mono_get_delegate_invoke_internal (klass
);
1504 tramp_info
= (MonoDelegateTrampInfo
*)mono_domain_alloc0 (domain
, sizeof (MonoDelegateTrampInfo
));
1505 tramp_info
->invoke
= invoke
;
1506 tramp_info
->invoke_sig
= mono_method_signature_internal (invoke
);
1507 tramp_info
->impl_this
= mono_arch_get_delegate_invoke_impl (mono_method_signature_internal (invoke
), TRUE
);
1508 tramp_info
->impl_nothis
= mono_arch_get_delegate_invoke_impl (mono_method_signature_internal (invoke
), FALSE
);
1509 tramp_info
->method
= method
;
1512 tramp_info
->sig
= mono_method_signature_checked (method
, error
);
1513 tramp_info
->need_rgctx_tramp
= mono_method_needs_static_rgctx_invoke (method
, FALSE
);
1515 tramp_info
->invoke_impl
= mono_create_specific_trampoline (tramp_info
, MONO_TRAMPOLINE_DELEGATE
, domain
, &code_size
);
1516 g_assert (code_size
);
1518 dpair
= (MonoClassMethodPair
*)mono_domain_alloc0 (domain
, sizeof (MonoClassMethodPair
));
1519 memcpy (dpair
, &pair
, sizeof (MonoClassMethodPair
));
1521 /* store trampoline address */
1522 mono_domain_lock (domain
);
1523 g_hash_table_insert (domain_jit_info (domain
)->delegate_trampoline_hash
, dpair
, tramp_info
);
1524 mono_domain_unlock (domain
);
1530 no_delegate_trampoline (void)
1532 g_assert_not_reached ();
1536 mono_create_delegate_trampoline (MonoDomain
*domain
, MonoClass
*klass
)
1538 if (mono_llvm_only
|| (mono_use_interpreter
&& !mono_aot_only
))
1539 return (gpointer
)no_delegate_trampoline
;
1541 return mono_create_delegate_trampoline_info (domain
, klass
, NULL
)->invoke_impl
;
1545 mono_create_delegate_virtual_trampoline (MonoDomain
*domain
, MonoClass
*klass
, MonoMethod
*method
)
1547 MonoMethod
*invoke
= mono_get_delegate_invoke_internal (klass
);
1550 return mono_get_delegate_virtual_invoke_impl (mono_method_signature_internal (invoke
), method
);
1554 mono_create_rgctx_lazy_fetch_trampoline (guint32 offset
)
1556 MonoTrampInfo
*info
;
1557 gpointer tramp
, ptr
;
1559 mono_trampolines_lock ();
1560 if (rgctx_lazy_fetch_trampoline_hash
)
1561 tramp
= g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash
, GUINT_TO_POINTER (offset
));
1564 mono_trampolines_unlock ();
1568 if (mono_aot_only
) {
1569 ptr
= mono_aot_get_lazy_fetch_trampoline (offset
);
1571 tramp
= mono_arch_create_rgctx_lazy_fetch_trampoline (offset
, &info
, FALSE
);
1572 mono_tramp_info_register (info
, NULL
);
1573 ptr
= mono_create_ftnptr (mono_get_root_domain (), tramp
);
1576 mono_trampolines_lock ();
1577 if (!rgctx_lazy_fetch_trampoline_hash
) {
1578 rgctx_lazy_fetch_trampoline_hash
= g_hash_table_new (NULL
, NULL
);
1579 rgctx_lazy_fetch_trampoline_hash_addr
= g_hash_table_new (NULL
, NULL
);
1581 g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash
, GUINT_TO_POINTER (offset
), ptr
);
1582 g_assert (offset
!= -1);
1583 g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr
, ptr
, GUINT_TO_POINTER (offset
+ 1));
1584 rgctx_num_lazy_fetch_trampolines
++;
1585 mono_trampolines_unlock ();
1591 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr
)
1595 mono_trampolines_lock ();
1596 if (rgctx_lazy_fetch_trampoline_hash_addr
) {
1597 /* We store the real offset + 1 so we can detect when the lookup fails */
1598 offset
= GPOINTER_TO_INT (g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash_addr
, addr
));
1606 mono_trampolines_unlock ();
1610 static const char* const tramp_names
[MONO_TRAMPOLINE_NUM
] = {
1611 "generic_trampoline_jit",
1612 "generic_trampoline_jump",
1613 "generic_trampoline_rgctx_lazy_fetch",
1614 "generic_trampoline_aot",
1615 "generic_trampoline_aot_plt",
1616 "generic_trampoline_delegate",
1617 "generic_trampoline_generic_virtual_remoting",
1618 "generic_trampoline_vcall"
1622 * mono_get_generic_trampoline_simple_name:
1626 mono_get_generic_trampoline_simple_name (MonoTrampolineType tramp_type
)
1628 return tramp_names
[tramp_type
] + sizeof ("generic_trampoline_") - 1;
1632 * mono_get_generic_trampoline_name:
1634 * Returns a pointer to malloc-ed memory.
1637 mono_get_generic_trampoline_name (MonoTrampolineType tramp_type
)
1639 return tramp_names
[tramp_type
];
1643 * mono_get_rgctx_fetch_trampoline_name:
1645 * Returns a pointer to malloc-ed memory.
1648 mono_get_rgctx_fetch_trampoline_name (int slot
)
1653 mrgctx
= MONO_RGCTX_SLOT_IS_MRGCTX (slot
);
1654 index
= MONO_RGCTX_SLOT_INDEX (slot
);
1656 return g_strdup_printf ("rgctx_fetch_trampoline_%s_%d", mrgctx
? "mrgctx" : "rgctx", index
);
1660 * mini_get_single_step_trampoline:
1662 * Return a trampoline which calls debugger_agent_single_step_from_context ().
1665 mini_get_single_step_trampoline (void)
1667 static gpointer trampoline
;
1672 if (mono_ee_features
.use_aot_trampolines
) {
1673 tramp
= mono_aot_get_trampoline ("sdb_single_step_trampoline");
1675 #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
1676 MonoTrampInfo
*info
;
1677 tramp
= mono_arch_create_sdb_trampoline (TRUE
, &info
, FALSE
);
1678 mono_tramp_info_register (info
, NULL
);
1681 g_assert_not_reached ();
1684 mono_memory_barrier ();
1692 * mini_get_breakpoint_trampoline:
1694 * Return a trampoline which calls mono_debugger_agent_breakpoint_from_context ().
1697 mini_get_breakpoint_trampoline (void)
1699 static gpointer trampoline
;
1704 if (mono_ee_features
.use_aot_trampolines
) {
1705 tramp
= mono_aot_get_trampoline ("sdb_breakpoint_trampoline");
1707 #ifdef MONO_ARCH_HAVE_SDB_TRAMPOLINES
1708 MonoTrampInfo
*info
;
1709 tramp
= mono_arch_create_sdb_trampoline (FALSE
, &info
, FALSE
);
1710 mono_tramp_info_register (info
, NULL
);
1713 g_assert_not_reached ();
1716 mono_memory_barrier ();