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 static GHashTable *class_init_hash_addr = NULL;
25 static GHashTable *delegate_trampoline_hash_addr = NULL;
26 static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL;
27 static GHashTable *rgctx_lazy_fetch_trampoline_hash_addr = NULL;
29 #define mono_trampolines_lock() EnterCriticalSection (&trampolines_mutex)
30 #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex)
31 static CRITICAL_SECTION trampolines_mutex;
34 get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr)
37 return mono_aot_get_unbox_trampoline (m);
39 return mono_arch_get_unbox_trampoline (gsctx, m, addr);
42 #ifdef MONO_ARCH_HAVE_IMT
45 mono_convert_imt_slot_to_vtable_slot (gpointer* slot, gpointer *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method)
47 MonoGenericSharingContext *gsctx = mono_get_generic_context_from_code (code);
48 MonoObject *this_argument = mono_arch_find_this_argument (regs, method, gsctx);
49 MonoVTable *vt = this_argument->vtable;
50 int displacement = slot - ((gpointer*)vt);
52 if (displacement > 0) {
53 /* slot is in the vtable, not in the IMT */
55 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p is in the vtable, not in the IMT\n", slot);
59 MonoMethod *imt_method = mono_arch_find_imt_method (regs, code);
61 int imt_slot = MONO_IMT_SIZE + displacement;
63 interface_offset = mono_class_interface_offset (vt->klass, imt_method->klass);
65 if (interface_offset < 0) {
66 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));
67 g_assert_not_reached ();
69 mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method));
72 *impl_method = mono_class_get_vtable_entry (vt->klass, interface_offset + imt_method->slot);
74 printf ("mono_convert_imt_slot_to_vtable_slot: method = %s.%s.%s, imt_method = %s.%s.%s\n",
75 method->klass->name_space, method->klass->name, method->name,
76 imt_method->klass->name_space, imt_method->klass->name, imt_method->name);
78 g_assert (imt_slot < MONO_IMT_SIZE);
79 if (vt->imt_collisions_bitmap & (1 << imt_slot)) {
80 int vtable_offset = interface_offset + mono_method_get_vtable_index (imt_method);
81 gpointer *vtable_slot = & (vt->vtable [vtable_offset]);
83 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);
88 printf ("mono_convert_imt_slot_to_vtable_slot: slot %p[%d] is in the IMT, but not colliding\n", slot, imt_slot);
97 * mono_magic_trampoline:
99 * This trampoline handles calls from JITted code.
102 mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp)
105 gpointer *vtable_slot;
106 gboolean generic_shared = FALSE;
107 MonoMethod *declaring = NULL;
108 MonoGenericInst *generic_virtual_method_inst = NULL;
111 #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
112 if (m == MONO_FAKE_VTABLE_METHOD) {
114 MonoVTable *vt = mono_arch_get_vcall_slot (code, (gpointer*)regs, &displacement);
116 if (displacement > 0) {
117 displacement -= G_STRUCT_OFFSET (MonoVTable, vtable);
118 g_assert (displacement >= 0);
119 displacement /= sizeof (gpointer);
121 /* Avoid loading metadata or creating a generic vtable if possible */
122 addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, displacement);
123 if (addr && !vt->klass->valuetype) {
124 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
125 if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
126 *vtable_slot = mono_get_addr_from_ftnptr (addr);
132 mono_class_setup_vtable (vt->klass);
133 m = vt->klass->vtable [displacement];
134 /*g_print ("%s with disp %d: %s at %p\n", vt->klass->name, displacement, m->name, code);*/
136 /* We got here from an interface method: redirect to IMT handling */
137 m = MONO_FAKE_IMT_METHOD;
138 /*g_print ("vtable with disp %d at %p\n", displacement, code);*/
142 /* this is the IMT trampoline */
143 #ifdef MONO_ARCH_HAVE_IMT
144 if (m == MONO_FAKE_IMT_METHOD) {
145 MonoMethod *impl_method;
146 /* we get the interface method because mono_convert_imt_slot_to_vtable_slot ()
147 * needs the signature to be able to find the this argument
149 m = mono_arch_find_imt_method ((gpointer*)regs, code);
150 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
151 g_assert (vtable_slot);
152 vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, (gpointer*)regs, code, m, &impl_method);
153 /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed
154 * to be called, so we compile it and go ahead as usual.
156 /*g_print ("imt found method %p (%s) at %p\n", impl_method, impl_method->name, code);*/
162 MonoGenericContext context = { NULL, NULL };
163 MonoMethod *declaring;
166 declaring = mono_method_get_declaring_generic_method (m);
170 if (m->klass->generic_class)
171 context.class_inst = m->klass->generic_class->context.class_inst;
173 g_assert (!m->klass->generic_container);
175 #ifdef MONO_ARCH_HAVE_IMT
176 generic_virtual_method_inst = (MonoGenericInst*)mono_arch_find_imt_method ((gpointer*)regs, code);
178 context.method_inst = generic_virtual_method_inst;
180 m = mono_class_inflate_generic_method (declaring, &context);
181 /* FIXME: only do this if the method is sharable */
182 m = mono_marshal_get_static_rgctx_invoke (m);
183 } else if ((context_used = mono_method_check_context_used (m))) {
184 MonoClass *klass = NULL;
185 MonoMethod *actual_method = NULL;
186 MonoVTable *vt = NULL;
187 MonoGenericInst *method_inst = NULL;
190 generic_shared = TRUE;
194 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
195 #ifdef MONO_ARCH_RGCTX_REG
196 MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext*)mono_arch_find_static_call_vtable ((gpointer*)regs, code);
198 klass = mrgctx->class_vtable->klass;
199 method_inst = mrgctx->method_inst;
201 g_assert_not_reached ();
203 } else if ((m->flags & METHOD_ATTRIBUTE_STATIC) || m->klass->valuetype) {
204 #ifdef MONO_ARCH_RGCTX_REG
205 MonoVTable *vtable = mono_arch_find_static_call_vtable ((gpointer*)regs, code);
207 klass = vtable->klass;
209 g_assert_not_reached ();
212 #ifdef MONO_ARCH_HAVE_IMT
213 MonoObject *this_argument = mono_arch_find_this_argument ((gpointer*)regs, m,
214 mono_get_generic_context_from_code (code));
216 vt = this_argument->vtable;
217 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
219 g_assert (this_argument->vtable->klass->inited);
220 //mono_class_init (this_argument->vtable->klass);
223 klass = this_argument->vtable->klass->supertypes [m->klass->idepth - 1];
229 g_assert (vtable_slot || klass);
232 int displacement = vtable_slot - ((gpointer*)vt);
234 g_assert_not_reached ();
236 g_assert (displacement > 0);
238 actual_method = vt->klass->vtable [displacement];
242 MonoGenericContext context = { NULL, NULL };
245 declaring = mono_method_get_declaring_generic_method (m);
249 if (klass->generic_class)
250 context.class_inst = klass->generic_class->context.class_inst;
251 else if (klass->generic_container)
252 context.class_inst = klass->generic_container->context.class_inst;
253 context.method_inst = method_inst;
255 actual_method = mono_class_inflate_generic_method (declaring, &context);
257 actual_method = mono_class_get_method_generic (klass, m);
261 g_assert (actual_method->klass == klass);
263 if (actual_method->is_inflated)
264 declaring = mono_method_get_declaring_generic_method (actual_method);
271 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
275 ji = mono_jit_info_table_find (mono_domain_get (), (char*)code);
279 /* Avoid recursion */
280 if (!(ji && ji->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED))
281 m = mono_marshal_get_synchronized_wrapper (m);
284 addr = mono_compile_method (m);
287 mono_debugger_trampoline_compiled (m, addr);
289 if (generic_virtual_method_inst) {
290 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
291 g_assert (vtable_slot);
293 mono_method_add_generic_virtual_invocation (mono_domain_get (), vtable_slot,
294 generic_virtual_method_inst, addr);
299 /* the method was jumped to */
301 MonoDomain *domain = mono_domain_get ();
303 /* Patch the got entries pointing to this method */
305 * We do this here instead of in mono_codegen () to cover the case when m
306 * was loaded from an aot image.
308 if (domain_jit_info (domain)->jump_target_got_slot_hash) {
311 mono_domain_lock (domain);
312 list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_got_slot_hash, m);
314 for (tmp = list; tmp; tmp = tmp->next) {
315 gpointer *got_slot = tmp->data;
318 g_hash_table_remove (domain_jit_info (domain)->jump_target_got_slot_hash, m);
321 mono_domain_unlock (domain);
327 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
330 if (m->klass->valuetype)
331 addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr);
333 g_assert (*vtable_slot);
335 if (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
336 #ifdef MONO_ARCH_HAVE_IMT
337 vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, (gpointer*)regs, code, m, NULL);
339 *vtable_slot = mono_get_addr_from_ftnptr (addr);
343 guint8 *plt_entry = mono_aot_get_plt_entry (code);
346 mono_arch_patch_plt_entry (plt_entry, addr);
347 } else if (!generic_shared || (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
348 mono_domain_lookup_shared_generic (mono_domain_get (), declaring)) {
349 if (generic_shared) {
350 if (m->wrapper_type != MONO_WRAPPER_NONE)
351 m = mono_marshal_method_from_wrapper (m);
352 g_assert (mono_method_is_generic_sharable_impl (m, FALSE));
355 /* Patch calling code */
360 mono_jit_info_table_find (mono_domain_get (), (char*)code);
361 MonoJitInfo *target_ji =
362 mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr));
364 if (mono_method_same_domain (ji, target_ji))
365 mono_arch_patch_callsite (ji->code_start, code, addr);
374 mono_generic_virtual_remoting_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8 *tramp)
376 MonoGenericContext context = { NULL, NULL };
377 MonoMethod *declaring;
380 g_assert (m->is_generic);
383 declaring = mono_method_get_declaring_generic_method (m);
387 if (m->klass->generic_class)
388 context.class_inst = m->klass->generic_class->context.class_inst;
390 g_assert (!m->klass->generic_container);
392 #ifdef MONO_ARCH_HAVE_IMT
393 context.method_inst = (MonoGenericInst*)mono_arch_find_imt_method ((gpointer*)regs, code);
395 m = mono_class_inflate_generic_method (declaring, &context);
396 m = mono_marshal_get_remoting_invoke_with_check (m);
398 addr = mono_compile_method (m);
401 mono_debugger_trampoline_compiled (m, addr);
407 * mono_aot_trampoline:
409 * This trampoline handles calls made from AOT code. We try to bypass the
410 * normal JIT compilation logic to avoid loading the metadata for the method.
412 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
414 mono_aot_trampoline (gssize *regs, guint8 *code, guint8 *token_info,
419 MonoMethod *method = NULL;
421 gpointer *vtable_slot;
422 gboolean is_got_entry;
425 image = *(gpointer*)(gpointer)token_info;
426 token_info += sizeof (gpointer);
427 token = *(guint32*)(gpointer)token_info;
429 addr = mono_aot_get_method_from_token (mono_domain_get (), image, token);
431 method = mono_get_method (image, token, NULL);
434 /* Use the generic code */
435 return mono_magic_trampoline (regs, code, method, tramp);
438 vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs);
439 g_assert (!vtable_slot);
441 /* This is a normal call through a PLT entry */
442 plt_entry = mono_aot_get_plt_entry (code);
443 g_assert (plt_entry);
445 mono_arch_patch_plt_entry (plt_entry, addr);
447 is_got_entry = FALSE;
450 * Since AOT code is only used in the root domain,
451 * mono_domain_get () != mono_get_root_domain () means the calling method
452 * is AppDomain:InvokeInDomain, so this is the same check as in
453 * mono_method_same_domain () but without loading the metadata for the method.
455 if ((is_got_entry && (mono_domain_get () == mono_get_root_domain ())) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) {
456 #ifdef MONO_ARCH_HAVE_IMT
458 method = mono_get_method (image, token, NULL);
459 vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, (gpointer*)regs, code, method, NULL);
468 * mono_aot_plt_trampoline:
470 * This trampoline handles calls made from AOT code through the PLT table.
473 mono_aot_plt_trampoline (gssize *regs, guint8 *code, guint8 *aot_module,
476 guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code);
478 return mono_aot_plt_resolve (aot_module, plt_info_offset, code);
483 * mono_class_init_trampoline:
485 * This method calls mono_runtime_class_init () to run the static constructor
486 * for the type, then patches the caller code so it is not called again.
489 mono_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
491 guint8 *plt_entry = mono_aot_get_plt_entry (code);
493 mono_runtime_class_init (vtable);
496 mono_arch_nullify_plt_entry (plt_entry);
498 mono_arch_nullify_class_init_trampoline (code, regs);
503 * mono_generic_class_init_trampoline:
505 * This method calls mono_runtime_class_init () to run the static constructor
509 mono_generic_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp)
511 g_assert (!vtable->initialized);
513 mono_runtime_class_init (vtable);
517 mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, gpointer data, guint8 *tramp)
519 #ifdef MONO_ARCH_VTABLE_REG
520 static gboolean inited = FALSE;
521 static int num_lookups = 0;
522 guint32 slot = GPOINTER_TO_UINT (data);
523 gpointer arg = (gpointer)(gssize)regs [MONO_ARCH_VTABLE_REG];
524 guint32 index = MONO_RGCTX_SLOT_INDEX (slot);
525 gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
528 mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_lookups);
535 return mono_method_fill_runtime_generic_context (arg, index);
537 return mono_class_fill_runtime_generic_context (arg, index);
539 g_assert_not_reached ();
544 mono_monitor_enter_trampoline (gssize *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
546 mono_monitor_enter (obj);
550 mono_monitor_exit_trampoline (gssize *regs, guint8 *code, MonoObject *obj, guint8 *tramp)
552 mono_monitor_exit (obj);
555 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
558 * mono_delegate_trampoline:
560 * This trampoline handles calls made to Delegate:Invoke ().
561 * This is called once the first time a delegate is invoked, so it must be fast.
564 mono_delegate_trampoline (gssize *regs, guint8 *code, gpointer *tramp_data, guint8* tramp)
566 MonoDomain *domain = mono_domain_get ();
567 MonoDelegate *delegate;
570 MonoMethod *method = NULL;
571 gboolean multicast, callvirt;
572 MonoMethod *invoke = tramp_data [0];
573 guint8 *impl_this = tramp_data [1];
574 guint8 *impl_nothis = tramp_data [2];
576 /* Obtain the delegate object according to the calling convention */
579 * Avoid calling mono_get_generic_context_from_code () now since it is expensive,
580 * get_this_arg_from_call will call it if needed.
582 delegate = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (invoke), regs, code);
584 if (delegate->method) {
585 method = delegate->method;
588 * delegate->method_ptr == NULL means the delegate was initialized by
589 * mini_delegate_ctor, while != NULL means it is initialized by
590 * mono_delegate_ctor_with_method (). In both cases, we need to add wrappers
591 * (ctor_with_method () does this, but it doesn't store the wrapper back into
594 if (delegate->target && delegate->target->vtable->klass == mono_defaults.transparent_proxy_class)
595 method = mono_marshal_get_remoting_invoke (method);
596 else if (mono_method_signature (method)->hasthis && method->klass->valuetype)
597 method = mono_marshal_get_unbox_wrapper (method);
599 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr));
603 callvirt = !delegate->target && method && mono_method_signature (method)->hasthis;
605 if (method && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
606 method = mono_marshal_get_synchronized_wrapper (method);
609 * If the called address is a trampoline, replace it with the compiled method so
610 * further calls don't have to go through the trampoline.
612 if (method && !callvirt) {
613 /* Avoid the overhead of looking up an already compiled method if possible */
614 if (delegate->method_code && *delegate->method_code) {
615 delegate->method_ptr = *delegate->method_code;
617 delegate->method_ptr = mono_compile_method (method);
618 if (delegate->method_code)
619 *delegate->method_code = delegate->method_ptr;
620 mono_debugger_trampoline_compiled (method, delegate->method_ptr);
624 multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL;
625 if (!multicast && !callvirt) {
626 code = delegate->target ? impl_this : impl_nothis;
629 delegate->invoke_impl = code;
634 /* The general, unoptimized case */
635 m = mono_marshal_get_delegate_invoke (invoke, delegate);
636 code = mono_compile_method (m);
637 delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
638 mono_debugger_trampoline_compiled (m, delegate->invoke_impl);
640 return mono_get_addr_from_ftnptr (code);
646 * mono_get_trampoline_func:
648 * Return the C function which needs to be called by the generic trampoline of type
652 mono_get_trampoline_func (MonoTrampolineType tramp_type)
654 switch (tramp_type) {
655 case MONO_TRAMPOLINE_JIT:
656 case MONO_TRAMPOLINE_JUMP:
657 return mono_magic_trampoline;
658 case MONO_TRAMPOLINE_CLASS_INIT:
659 return mono_class_init_trampoline;
660 case MONO_TRAMPOLINE_GENERIC_CLASS_INIT:
661 return mono_generic_class_init_trampoline;
662 case MONO_TRAMPOLINE_RGCTX_LAZY_FETCH:
663 return mono_rgctx_lazy_fetch_trampoline;
664 #ifdef MONO_ARCH_AOT_SUPPORTED
665 case MONO_TRAMPOLINE_AOT:
666 return mono_aot_trampoline;
667 case MONO_TRAMPOLINE_AOT_PLT:
668 return mono_aot_plt_trampoline;
670 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
671 case MONO_TRAMPOLINE_DELEGATE:
672 return mono_delegate_trampoline;
674 case MONO_TRAMPOLINE_RESTORE_STACK_PROT:
675 return mono_altstack_restore_prot;
676 case MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING:
677 return mono_generic_virtual_remoting_trampoline;
678 case MONO_TRAMPOLINE_MONITOR_ENTER:
679 return mono_monitor_enter_trampoline;
680 case MONO_TRAMPOLINE_MONITOR_EXIT:
681 return mono_monitor_exit_trampoline;
683 g_assert_not_reached ();
689 mono_trampolines_init (void)
691 InitializeCriticalSection (&trampolines_mutex);
696 mono_trampoline_code [MONO_TRAMPOLINE_JIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JIT);
697 mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP);
698 mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
699 mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT);
700 mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH);
701 #ifdef MONO_ARCH_AOT_SUPPORTED
702 mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
703 mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
705 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
706 mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
708 mono_trampoline_code [MONO_TRAMPOLINE_RESTORE_STACK_PROT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT);
709 mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING);
710 mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER);
711 mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT);
715 mono_trampolines_cleanup (void)
717 if (class_init_hash_addr)
718 g_hash_table_destroy (class_init_hash_addr);
719 if (delegate_trampoline_hash_addr)
720 g_hash_table_destroy (delegate_trampoline_hash_addr);
722 DeleteCriticalSection (&trampolines_mutex);
726 mono_get_trampoline_code (MonoTrampolineType tramp_type)
728 g_assert (mono_trampoline_code [tramp_type]);
730 return mono_trampoline_code [tramp_type];
734 mono_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
737 return mono_aot_create_specific_trampoline (mono_defaults.corlib, arg1, tramp_type, domain, code_len);
739 return mono_arch_create_specific_trampoline (arg1, tramp_type, domain, code_len);
743 mono_create_class_init_trampoline (MonoVTable *vtable)
746 MonoDomain *domain = vtable->domain;
748 g_assert (!vtable->klass->generic_container);
750 /* previously created trampoline code */
751 mono_domain_lock (domain);
753 g_hash_table_lookup (domain_jit_info (domain)->class_init_trampoline_hash,
755 mono_domain_unlock (domain);
759 code = mono_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, domain, NULL);
761 ptr = mono_create_ftnptr (domain, code);
763 /* store trampoline address */
764 mono_domain_lock (domain);
765 g_hash_table_insert (domain_jit_info (domain)->class_init_trampoline_hash,
767 mono_domain_unlock (domain);
769 mono_trampolines_lock ();
770 if (!class_init_hash_addr)
771 class_init_hash_addr = g_hash_table_new (NULL, NULL);
772 g_hash_table_insert (class_init_hash_addr, ptr, vtable);
773 mono_trampolines_unlock ();
779 mono_create_generic_class_init_trampoline (void)
781 #ifdef MONO_ARCH_VTABLE_REG
782 static gpointer code;
784 mono_trampolines_lock ();
787 code = mono_arch_create_generic_class_init_trampoline ();
789 mono_trampolines_unlock ();
793 g_assert_not_reached ();
798 mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
802 guint32 code_size = 0;
804 code = mono_jit_find_compiled_method (domain, method);
808 mono_domain_lock (domain);
809 code = g_hash_table_lookup (domain_jit_info (domain)->jump_trampoline_hash, method);
810 mono_domain_unlock (domain);
814 code = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
815 g_assert (code_size);
817 mono_domain_lock (domain);
818 ji = mono_domain_alloc0 (domain, sizeof (MonoJitInfo));
819 mono_domain_unlock (domain);
820 ji->code_start = code;
821 ji->code_size = code_size;
825 * mono_delegate_ctor needs to find the method metadata from the
826 * trampoline address, so we save it here.
829 mono_jit_info_table_add (domain, ji);
831 mono_domain_lock (domain);
832 g_hash_table_insert (domain_jit_info (domain)->jump_trampoline_hash, method, ji->code_start);
833 mono_domain_unlock (domain);
835 return ji->code_start;
839 mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
844 /* Avoid creating trampolines if possible */
845 gpointer code = mono_jit_find_compiled_method (domain, method);
851 mono_domain_lock (domain);
852 tramp = g_hash_table_lookup (domain_jit_info (domain)->jit_trampoline_hash, method);
853 mono_domain_unlock (domain);
857 tramp = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JIT, domain, NULL);
859 mono_domain_lock (domain);
860 g_hash_table_insert (domain_jit_info (domain)->jit_trampoline_hash, method, tramp);
861 mono_domain_unlock (domain);
863 mono_jit_stats.method_trampolines++;
869 mono_create_jit_trampoline (MonoMethod *method)
871 return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
874 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
876 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
880 MonoDomain *domain = mono_domain_get ();
883 mono_domain_lock (domain);
884 buf = start = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
885 mono_domain_unlock (domain);
887 *(gpointer*)(gpointer)buf = image;
888 buf += sizeof (gpointer);
889 *(guint32*)(gpointer)buf = token;
891 tramp = mono_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL);
893 mono_jit_stats.method_trampolines++;
900 mono_create_delegate_trampoline (MonoClass *klass)
902 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
903 MonoDomain *domain = mono_domain_get ();
905 guint32 code_size = 0;
906 gpointer *tramp_data;
909 mono_domain_lock (domain);
910 ptr = g_hash_table_lookup (domain_jit_info (domain)->delegate_trampoline_hash, klass);
911 mono_domain_unlock (domain);
915 // Precompute the delegate invoke impl and pass it to the delegate trampoline
916 invoke = mono_get_delegate_invoke (klass);
919 mono_domain_lock (domain );
920 tramp_data = mono_domain_alloc (domain, sizeof (gpointer) * 3);
921 mono_domain_unlock (domain);
922 tramp_data [0] = invoke;
924 tramp_data [1] = NULL;
925 tramp_data [2] = NULL;
927 tramp_data [1] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
928 tramp_data [2] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
931 ptr = mono_create_specific_trampoline (tramp_data, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
932 g_assert (code_size);
934 /* store trampoline address */
935 mono_domain_lock (domain);
936 g_hash_table_insert (domain_jit_info (domain)->delegate_trampoline_hash,
938 mono_domain_unlock (domain);
940 mono_trampolines_lock ();
941 if (!delegate_trampoline_hash_addr)
942 delegate_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
943 g_hash_table_insert (delegate_trampoline_hash_addr, ptr, klass);
944 mono_trampolines_unlock ();
953 mono_create_rgctx_lazy_fetch_trampoline (guint32 offset)
955 static gboolean inited = FALSE;
956 static int num_trampolines = 0;
961 return mono_aot_get_lazy_fetch_trampoline (offset);
963 mono_trampolines_lock ();
964 if (rgctx_lazy_fetch_trampoline_hash)
965 tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset));
968 mono_trampolines_unlock ();
972 tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset);
973 ptr = mono_create_ftnptr (mono_get_root_domain (), tramp);
975 mono_trampolines_lock ();
976 if (!rgctx_lazy_fetch_trampoline_hash) {
977 rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL);
978 rgctx_lazy_fetch_trampoline_hash_addr = g_hash_table_new (NULL, NULL);
980 g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr);
981 g_assert (offset != -1);
982 g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr, ptr, GUINT_TO_POINTER (offset + 1));
983 mono_trampolines_unlock ();
986 mono_counters_register ("RGCTX num lazy fetch trampolines",
987 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines);
996 mono_create_monitor_enter_trampoline (void)
998 static gpointer code;
1000 if (mono_aot_only) {
1002 code = mono_aot_get_named_code ("monitor_enter_trampoline");
1006 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1007 mono_trampolines_lock ();
1010 code = mono_arch_create_monitor_enter_trampoline ();
1012 mono_trampolines_unlock ();
1015 g_assert_not_reached ();
1022 mono_create_monitor_exit_trampoline (void)
1024 static gpointer code;
1026 if (mono_aot_only) {
1028 code = mono_aot_get_named_code ("monitor_exit_trampoline");
1032 #ifdef MONO_ARCH_MONITOR_OBJECT_REG
1033 mono_trampolines_lock ();
1036 code = mono_arch_create_monitor_exit_trampoline ();
1038 mono_trampolines_unlock ();
1041 g_assert_not_reached ();
1047 mono_find_class_init_trampoline_by_addr (gconstpointer addr)
1051 mono_trampolines_lock ();
1052 if (class_init_hash_addr)
1053 res = g_hash_table_lookup (class_init_hash_addr, addr);
1056 mono_trampolines_unlock ();
1061 mono_find_delegate_trampoline_by_addr (gconstpointer addr)
1065 mono_trampolines_lock ();
1066 if (delegate_trampoline_hash_addr)
1067 res = g_hash_table_lookup (delegate_trampoline_hash_addr, addr);
1070 mono_trampolines_unlock ();
1075 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr)
1079 mono_trampolines_lock ();
1080 if (rgctx_lazy_fetch_trampoline_hash_addr) {
1081 /* We store the real offset + 1 so we can detect when the lookup fails */
1082 offset = GPOINTER_TO_INT (g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash_addr, addr));
1090 mono_trampolines_unlock ();