5 #include <mono/metadata/appdomain.h>
6 #include <mono/metadata/metadata-internals.h>
7 #include <mono/metadata/marshal.h>
8 #include <mono/metadata/tabledefs.h>
9 #include <mono/utils/mono-counters.h>
11 #ifdef HAVE_VALGRIND_MEMCHECK_H
12 #include <valgrind/memcheck.h>
16 #include "debug-mini.h"
19 * Address of the trampoline code. This is used by the debugger to check
20 * whether a method is a trampoline.
22 guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM];
24 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
25 guint8* mono_aot_trampoline_code [MONO_TRAMPOLINE_NUM];
28 static GHashTable *class_init_hash_addr = NULL;
29 static GHashTable *delegate_trampoline_hash_addr = NULL;
31 #define mono_trampolines_lock() EnterCriticalSection (&trampolines_mutex)
32 #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex)
33 static CRITICAL_SECTION trampolines_mutex;
35 #ifdef MONO_ARCH_HAVE_IMT
38 mono_convert_imt_slot_to_vtable_slot (gpointer* slot, gpointer *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method)
40 MonoGenericSharingContext *gsctx = mono_get_generic_context_from_code (code);
41 MonoObject *this_argument = mono_arch_find_this_argument (regs, method, gsctx);
42 MonoVTable *vt = this_argument->vtable;
43 int displacement = slot - ((gpointer*)vt);
45 if (displacement > 0) {
46 /* slot is in the vtable, not in the IMT */
48 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p is in the vtable, not in the IMT\n", slot);
52 MonoMethod *imt_method = mono_arch_find_imt_method (regs, code);
54 int imt_slot = MONO_IMT_SIZE + displacement;
56 mono_class_setup_vtable (vt->klass);
57 interface_offset = mono_class_interface_offset (vt->klass, imt_method->klass);
59 if (interface_offset < 0) {
60 g_print ("%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));
61 g_assert_not_reached ();
63 mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
66 *impl_method = vt->klass->vtable [interface_offset + imt_method->slot];
68 printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
69 method->klass->name_space, method->klass->name, method->name,
70 imt_method->klass->name_space, imt_method->klass->name, imt_method->name);
72 g_assert (imt_slot < MONO_IMT_SIZE);
73 if (vt->imt_collisions_bitmap & (1 << imt_slot)) {
74 int vtable_offset = interface_offset + imt_method->slot;
75 gpointer *vtable_slot = & (vt->vtable [vtable_offset]);
77 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);
82 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot);
91 * mono_magic_trampoline:
93 * This trampoline handles calls from JITted code.
96 mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
99 gpointer *vtable_slot;
100 gboolean generic_shared = FALSE;
101 MonoMethod *declaring = NULL;
104 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
105 if (m == MONO_FAKE_VTABLE_METHOD) {
107 MonoVTable *vt = mono_arch_get_vcall_slot (code, (gpointer*)regs, &displacement);
109 if (displacement > 0) {
110 displacement -= G_STRUCT_OFFSET (MonoVTable, vtable);
111 g_assert (displacement >= 0);
112 displacement /= sizeof (gpointer);
114 /* Avoid loading metadata or creating a generic vtable if possible */
115 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, displacement);
116 if (addr && !vt->klass->valuetype) {
117 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
118 if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
119 *vtable_slot = mono_get_addr_from_ftnptr (addr);
125 mono_class_setup_vtable (vt->klass);
126 m = vt->klass->vtable [displacement];
127 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
128 m = mono_marshal_get_synchronized_wrapper (m);
129 /*g_print ("%s with disp %d: %s at %p\n", vt->klass->name, displacement, m->name, code);*/
131 /* We got here from an interface method: redirect to IMT handling */
132 m = MONO_FAKE_IMT_METHOD;
133 /*g_print ("vtable with disp %d at %p\n", displacement, code);*/
137 /* this is the IMT trampoline */
138 #ifdef MONO_ARCH_HAVE_IMT
139 if (m == MONO_FAKE_IMT_METHOD) {
140 MonoMethod *impl_method;
141 /* we get the interface method because mono_convert_imt_slot_to_vtable_slot ()
142 * needs the signature to be able to find the this argument
144 m = mono_arch_find_imt_method ((gpointer*)regs, code);
145 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
146 g_assert (vtable_slot);
147 vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, (gpointer*)regs, code, m, &impl_method);
148 /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
149 * to be called, so we compile it and go ahead as usual.
151 /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
156 if ((context_used = mono_method_check_context_used (m))) {
157 MonoClass *klass = NULL;
158 MonoMethod *actual_method = NULL;
159 MonoVTable *vt = NULL;
160 MonoGenericInst *method_inst = NULL;
163 generic_shared = TRUE;
167 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
168 #ifdef MONO_ARCH_RGCTX_REG
169 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext*)mono_arch_find_static_call_vtable ((gpointer*)regs, code);
171 klass = mrgctx->class_vtable->klass;
172 method_inst = mrgctx->method_inst;
174 g_assert_not_reached ();
176 } else if (m->flags & METHOD_ATTRIBUTE_STATIC) {
177 #ifdef MONO_ARCH_RGCTX_REG
178 MonoVTable *vtable = mono_arch_find_static_call_vtable ((gpointer*)regs, code);
180 klass = vtable->klass;
182 g_assert_not_reached ();
185 #ifdef MONO_ARCH_HAVE_IMT
186 MonoObject *this_argument = mono_arch_find_this_argument ((gpointer*)regs, m,
187 mono_get_generic_context_from_code (code));
189 vt = this_argument->vtable;
190 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
192 g_assert (this_argument->vtable->klass->inited);
193 //mono_class_init (this_argument->vtable->klass);
196 klass = this_argument->vtable->klass->supertypes [m->klass->idepth - 1];
202 g_assert (vtable_slot || klass);
205 int displacement = vtable_slot - ((gpointer*)vt);
207 g_assert_not_reached ();
209 g_assert (displacement > 0);
211 actual_method = vt->klass->vtable [displacement];
215 MonoGenericContext context = { NULL, NULL };
218 declaring = mono_method_get_declaring_generic_method (m);
222 if (klass->generic_class)
223 context.class_inst = klass->generic_class->context.class_inst;
224 else if (klass->generic_container)
225 context.class_inst = klass->generic_container->context.class_inst;
226 context.method_inst = method_inst;
228 actual_method = mono_class_inflate_generic_method (declaring, &context);
230 actual_method = mono_class_get_method_generic (klass, m);
234 g_assert (actual_method->klass == klass);
236 if (actual_method->is_inflated)
237 declaring = mono_method_get_declaring_generic_method (actual_method);
244 addr = mono_compile_method (m);
247 mono_debugger_trampoline_compiled (m, addr);
249 /* the method was jumped to */
253 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
256 if (m->klass->valuetype)
257 addr = mono_arch_get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr);
259 g_assert (*vtable_slot);
261 if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
262 #ifdef MONO_ARCH_HAVE_IMT
263 vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, (gpointer*)regs, code, m, NULL);
265 *vtable_slot = mono_get_addr_from_ftnptr (addr);
268 else if (!generic_shared || mono_domain_lookup_shared_generic (mono_domain_get (), declaring)) {
269 guint8 *plt_entry = mono_aot_get_plt_entry (code);
272 g_assert (mono_method_is_generic_sharable_impl (m, FALSE));
274 /* Patch calling code */
276 mono_arch_patch_plt_entry (plt_entry, addr);
279 mono_jit_info_table_find (mono_domain_get (), (char*)code);
280 MonoJitInfo *target_ji =
281 mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr));
283 if (mono_method_same_domain (ji, target_ji))
284 mono_arch_patch_callsite (ji->code_start, code, addr);
292 * mono_aot_trampoline:
294 * This trampoline handles calls made from AOT code. We try to bypass the
295 * normal JIT compilation logic to avoid loading the metadata for the method.
297 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
299 mono_aot_trampoline (gssize *regs, guint8 *code, guint8 *token_info,
304 MonoMethod *method = NULL;
306 gpointer *vtable_slot;
307 gboolean is_got_entry;
309 image = *(gpointer*)(gpointer)token_info;
310 token_info += sizeof (gpointer);
311 token = *(guint32*)(gpointer)token_info;
313 addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
315 method = mono_get_method (image, token, NULL);
318 //printf ("F: %s\n", mono_method_full_name (method, TRUE));
320 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
321 method = mono_marshal_get_synchronized_wrapper (method);
323 addr = mono_compile_method (method);
327 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
330 is_got_entry = mono_aot_is_got_entry (code, (guint8*)vtable_slot);
334 method = mono_get_method (image, token, NULL);
335 if (method->klass->valuetype)
336 addr = mono_arch_get_unbox_trampoline (mono_get_generic_context_from_code (code), method, addr);
339 /* This is a normal call through a PLT entry */
340 guint8 *plt_entry = mono_aot_get_plt_entry (code);
342 g_assert (plt_entry);
344 mono_arch_patch_plt_entry (plt_entry, addr);
346 is_got_entry = FALSE;
350 * Since AOT code is only used in the root domain,
351 * mono_domain_get () != mono_get_root_domain () means the calling method
352 * is AppDomain:InvokeInDomain, so this is the same check as in
353 * mono_method_same_domain () but without loading the metadata for the method.
355 if ((is_got_entry && (mono_domain_get () == mono_get_root_domain ())) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
356 #ifdef MONO_ARCH_HAVE_IMT
358 method = mono_get_method (image, token, NULL);
359 vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, (gpointer*)regs, code, method, NULL);
368 * mono_aot_plt_trampoline:
370 * This trampoline handles calls made from AOT code through the PLT table.
373 mono_aot_plt_trampoline (gssize *regs, guint8 *code, guint8 *aot_module,
376 #ifdef MONO_ARCH_AOT_PLT_OFFSET_REG
377 guint32 plt_info_offset = regs [MONO_ARCH_AOT_PLT_OFFSET_REG];
379 guint32 plt_info_offset = -1;
382 return mono_aot_plt_resolve (aot_module, plt_info_offset, code);
387 * mono_class_init_trampoline:
389 * This method calls mono_runtime_class_init () to run the static constructor
390 * for the type, then patches the caller code so it is not called again.
393 mono_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
395 guint8 *plt_entry = mono_aot_get_plt_entry (code);
397 mono_runtime_class_init (vtable);
399 if (!mono_running_on_valgrind ()) {
401 mono_arch_nullify_plt_entry (plt_entry);
403 mono_arch_nullify_class_init_trampoline (code, regs);
409 * mono_generic_class_init_trampoline:
411 * This method calls mono_runtime_class_init () to run the static constructor
415 mono_generic_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
417 g_assert (!vtable->initialized);
419 mono_runtime_class_init (vtable);
423 mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, gpointer data, guint8 *tramp)
425 static gboolean inited = FALSE;
426 static int num_lookups = 0;
428 guint32 slot = mono_arch_get_rgctx_lazy_fetch_offset ((gpointer*)regs);
429 guint32 index = MONO_RGCTX_SLOT_INDEX (slot);
430 gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
433 mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_lookups);
440 return mono_method_fill_runtime_generic_context (data, index);
442 return mono_class_fill_runtime_generic_context (data, index);
445 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
448 * mono_delegate_trampoline:
450 * This trampoline handles calls made to Delegate:Invoke ().
451 * This is called once the first time a delegate is invoked, so it must be fast.
454 mono_delegate_trampoline (gssize *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
456 MonoDomain *domain = mono_domain_get ();
457 MonoDelegate *delegate;
460 MonoMethod *method = NULL;
461 gboolean multicast, callvirt;
462 MonoMethod *invoke = tramp_data [0];
463 guint8 *impl_this = tramp_data [1];
464 guint8 *impl_nothis = tramp_data [2];
466 /* Obtain the delegate object according to the calling convention */
469 * Avoid calling mono_get_generic_context_from_code () now since it is expensive,
470 * get_this_arg_from_call will call it if needed.
472 delegate = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (invoke), regs, code);
474 if (!delegate->method_ptr && delegate->method) {
475 /* The delegate was initialized by mini_delegate_ctor */
476 method = delegate->method;
478 if (delegate->target && delegate->target->vtable->klass == mono_defaults.transparent_proxy_class)
479 method = mono_marshal_get_remoting_invoke (method);
480 else if (mono_method_signature (method)->hasthis && method->klass->valuetype)
481 method = mono_marshal_get_unbox_wrapper (method);
482 } else if (delegate->method) {
483 method = delegate->method;
485 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr));
489 callvirt = !delegate->target && method && mono_method_signature (method)->hasthis;
492 * If the called address is a trampoline, replace it with the compiled method so
493 * further calls don't have to go through the trampoline.
495 if (method && !callvirt) {
496 delegate->method_ptr = mono_compile_method (method);
497 mono_debugger_trampoline_compiled (method, delegate->method_ptr);
500 multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL;
501 if (!multicast && !callvirt) {
502 code = delegate->target ? impl_this : impl_nothis;
505 delegate->invoke_impl = code;
510 /* The general, unoptimized case */
511 m = mono_marshal_get_delegate_invoke (invoke, delegate);
512 code = mono_compile_method (m);
513 delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
514 mono_debugger_trampoline_compiled (m, delegate->invoke_impl);
522 * mono_get_trampoline_func:
524 * Return the C function which needs to be called by the generic trampoline of type
528 mono_get_trampoline_func (MonoTrampolineType tramp_type)
530 switch (tramp_type) {
531 case MONO_TRAMPOLINE_JIT:
532 case MONO_TRAMPOLINE_JUMP:
533 return mono_magic_trampoline;
534 case MONO_TRAMPOLINE_CLASS_INIT:
535 return mono_class_init_trampoline;
536 case MONO_TRAMPOLINE_GENERIC_CLASS_INIT:
537 return mono_generic_class_init_trampoline;
538 case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH:
539 return mono_rgctx_lazy_fetch_trampoline;
540 #ifdef MONO_ARCH_AOT_SUPPORTED
541 case MONO_TRAMPOLINE_AOT:
542 return mono_aot_trampoline;
543 case MONO_TRAMPOLINE_AOT_PLT:
544 return mono_aot_plt_trampoline;
546 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
547 case MONO_TRAMPOLINE_DELEGATE:
548 return mono_delegate_trampoline;
551 g_assert_not_reached ();
557 mono_trampolines_init (void)
559 InitializeCriticalSection (&trampolines_mutex);
561 mono_trampoline_code [MONO_TRAMPOLINE_JIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JIT);
562 mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
563 mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
564 mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
565 mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
566 #ifdef MONO_ARCH_AOT_SUPPORTED
567 mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
568 mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
570 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
571 mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
576 mono_trampolines_cleanup (void)
578 if (class_init_hash_addr)
579 g_hash_table_destroy (class_init_hash_addr);
580 if (delegate_trampoline_hash_addr)
581 g_hash_table_destroy (delegate_trampoline_hash_addr);
583 DeleteCriticalSection (&trampolines_mutex);
587 mono_get_trampoline_code (MonoTrampolineType tramp_type)
589 return mono_trampoline_code [tramp_type];
593 mono_create_class_init_trampoline (MonoVTable *vtable)
597 g_assert (!vtable->klass->generic_container);
599 /* previously created trampoline code */
600 mono_domain_lock (vtable->domain);
602 g_hash_table_lookup (vtable->domain->class_init_trampoline_hash,
604 mono_domain_unlock (vtable->domain);
609 code = mono_aot_create_specific_trampoline (vtable->klass->image, vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
611 code = mono_arch_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL);
613 ptr = mono_create_ftnptr (vtable->domain, code);
615 /* store trampoline address */
616 mono_domain_lock (vtable->domain);
617 g_hash_table_insert (vtable->domain->class_init_trampoline_hash,
619 mono_domain_unlock (vtable->domain);
621 mono_trampolines_lock ();
622 if (!class_init_hash_addr)
623 class_init_hash_addr = g_hash_table_new (NULL, NULL);
624 g_hash_table_insert (class_init_hash_addr, ptr, vtable);
625 mono_trampolines_unlock ();
631 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
632 gboolean add_sync_wrapper)
636 guint32 code_size = 0;
638 if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
639 return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE);
641 code = mono_jit_find_compiled_method (domain, method);
645 mono_domain_lock (domain);
646 code = g_hash_table_lookup (domain->jump_trampoline_hash, method);
647 mono_domain_unlock (domain);
651 code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
652 g_assert (code_size);
654 mono_domain_lock (domain);
655 ji = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
656 mono_domain_unlock (domain);
657 ji->code_start = code;
658 ji->code_size = code_size;
662 * mono_delegate_ctor needs to find the method metadata from the
663 * trampoline address, so we save it here.
666 mono_jit_info_table_add (domain, ji);
668 mono_domain_lock (domain);
669 g_hash_table_insert (domain->jump_trampoline_hash, method, ji->code_start);
670 mono_domain_unlock (domain);
672 return ji->code_start;
676 mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
681 /* Load the method from AOT right away */
682 return mono_compile_method (method);
684 mono_domain_lock (domain);
685 tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method);
686 mono_domain_unlock (domain);
690 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) && add_sync_wrapper)
691 return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
693 tramp = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JIT, domain, NULL);
695 mono_domain_lock (domain);
696 g_hash_table_insert (domain->jit_trampoline_hash, method, tramp);
697 mono_domain_unlock (domain);
699 mono_jit_stats.method_trampolines++;
705 mono_create_jit_trampoline (MonoMethod *method)
707 return mono_create_jit_trampoline_in_domain (mono_domain_get (), method, TRUE);
710 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
712 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
716 MonoDomain *domain = mono_domain_get ();
719 mono_domain_lock (domain);
720 buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
721 mono_domain_unlock (domain);
723 *(gpointer*)(gpointer)buf = image;
724 buf += sizeof (gpointer);
725 *(guint32*)(gpointer)buf = token;
727 tramp = mono_arch_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
729 mono_jit_stats.method_trampolines++;
736 mono_create_delegate_trampoline (MonoClass *klass)
738 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
739 MonoDomain *domain = mono_domain_get ();
741 guint32 code_size = 0;
742 gpointer *tramp_data;
745 mono_domain_lock (domain);
746 ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass);
747 mono_domain_unlock (domain);
751 // Precompute the delegate invoke impl and pass it to the delegate trampoline
752 invoke = mono_get_delegate_invoke (klass);
755 mono_domain_lock (domain );
756 tramp_data = mono_mempool_alloc (domain->mp, sizeof (gpointer) * 3);
757 mono_domain_unlock (domain);
758 tramp_data [0] = invoke;
759 tramp_data [1] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
760 tramp_data [2] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
762 ptr = mono_arch_create_specific_trampoline (tramp_data, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
763 g_assert (code_size);
765 /* store trampoline address */
766 mono_domain_lock (domain);
767 g_hash_table_insert (domain->delegate_trampoline_hash,
769 mono_domain_unlock (domain);
771 mono_trampolines_lock ();
772 if (!delegate_trampoline_hash_addr)
773 delegate_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
774 g_hash_table_insert (delegate_trampoline_hash_addr, ptr, klass);
775 mono_trampolines_unlock ();
784 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
788 mono_trampolines_lock ();
789 if (class_init_hash_addr)
790 res = g_hash_table_lookup (class_init_hash_addr, addr);
793 mono_trampolines_unlock ();
798 mono_find_delegate_trampoline_by_addr (gconstpointer addr)
802 mono_trampolines_lock ();
803 if (delegate_trampoline_hash_addr)
804 res = g_hash_table_lookup (delegate_trampoline_hash_addr, addr);
807 mono_trampolines_unlock ();
812 * Return the generic trampoline of type TRAMP_TYPE which can be called from AOT code in
816 mono_get_aot_trampoline_code (MonoTrampolineType tramp_type)
818 #ifdef MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES
821 if (mono_aot_trampoline_code [tramp_type])
822 return mono_aot_trampoline_code [tramp_type];
824 mono_trampolines_lock ();
826 code = mono_arch_create_trampoline_code_full (tramp_type, TRUE);
828 mono_memory_barrier ();
830 mono_aot_trampoline_code [tramp_type] = code;
834 g_assert_not_reached ();