X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-trampolines.c;h=f215cc585bd05e04d03ecb9e8edf54a18a182142;hb=b291f31d3061adb6d75d3f477945775608daf751;hp=bb0846f01078512c20feab8ccfa343c2a4348ad9;hpb=ec793dabd1ff1f436b27120332a838346be2c561;p=mono.git diff --git a/mono/mini/mini-trampolines.c b/mono/mini/mini-trampolines.c index bb0846f0107..f215cc585bd 100644 --- a/mono/mini/mini-trampolines.c +++ b/mono/mini/mini-trampolines.c @@ -7,10 +7,7 @@ #include #include #include - -#ifdef HAVE_VALGRIND_MEMCHECK_H -#include -#endif +#include #include "mini.h" #include "debug-mini.h" @@ -24,6 +21,7 @@ guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM]; static GHashTable *class_init_hash_addr = NULL; static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL; static GHashTable *rgctx_lazy_fetch_trampoline_hash_addr = NULL; +static guint32 trampoline_calls; #define mono_trampolines_lock() EnterCriticalSection (&trampolines_mutex) #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex) @@ -47,6 +45,32 @@ get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer } #ifdef MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE + +typedef struct { + MonoMethod *m; + gpointer addr; +} RgctxTrampInfo; + +static gint +rgctx_tramp_info_equal (gconstpointer ka, gconstpointer kb) +{ + const RgctxTrampInfo *i1 = ka; + const RgctxTrampInfo *i2 = kb; + + if (i1->m == i2->m && i1->addr == i2->addr) + return 1; + else + return 0; +} + +static guint +rgctx_tramp_info_hash (gconstpointer data) +{ + const RgctxTrampInfo *info = data; + + return GPOINTER_TO_UINT (info->m) ^ GPOINTER_TO_UINT (info->addr); +} + /* * mono_create_static_rgctx_trampoline: * @@ -59,6 +83,7 @@ get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer * methods code. These trampolines are similar to the unbox trampolines, they * perform the same task as the static rgctx wrappers, but they are smaller/faster, * and can be made to work with full AOT. + * On PPC addr should be an ftnptr and the return value is an ftnptr too. */ gpointer mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr) @@ -66,29 +91,46 @@ mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr) gpointer ctx; gpointer res; MonoDomain *domain; + RgctxTrampInfo tmp_info; + RgctxTrampInfo *info; + +#ifdef PPC_USES_FUNCTION_DESCRIPTOR + g_assert (((gpointer*)addr) [2] == 0); +#endif if (mini_method_get_context (m)->method_inst) ctx = mono_method_lookup_rgctx (mono_class_vtable (mono_domain_get (), m->klass), mini_method_get_context (m)->method_inst); else ctx = mono_class_vtable (mono_domain_get (), m->klass); - if (mono_aot_only) - return mono_aot_get_static_rgctx_trampoline (ctx, addr); - domain = mono_domain_get (); + /* + * In the AOT case, addr might point to either the method, or to an unbox trampoline, + * so make the hash keyed on the m+addr pair. + */ mono_domain_lock (domain); + if (!domain_jit_info (domain)->static_rgctx_trampoline_hash) + domain_jit_info (domain)->static_rgctx_trampoline_hash = g_hash_table_new (rgctx_tramp_info_hash, rgctx_tramp_info_equal); + tmp_info.m = m; + tmp_info.addr = addr; res = g_hash_table_lookup (domain_jit_info (domain)->static_rgctx_trampoline_hash, - m); + &tmp_info); mono_domain_unlock (domain); if (res) return res; - res = mono_arch_get_static_rgctx_trampoline (m, ctx, addr); + if (mono_aot_only) + res = mono_aot_get_static_rgctx_trampoline (ctx, addr); + else + res = mono_arch_get_static_rgctx_trampoline (m, ctx, addr); mono_domain_lock (domain); /* Duplicates inserted while we didn't hold the lock are OK */ - g_hash_table_insert (domain_jit_info (domain)->static_rgctx_trampoline_hash, m, res); + info = mono_domain_alloc (domain, sizeof (RgctxTrampInfo)); + info->m = m; + info->addr = addr; + g_hash_table_insert (domain_jit_info (domain)->static_rgctx_trampoline_hash, info, res); mono_domain_unlock (domain); return res; @@ -119,10 +161,9 @@ mono_get_vcall_slot_addr (guint8* code, mgreg_t *regs) #ifdef MONO_ARCH_HAVE_IMT static gpointer* -mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method, gboolean *need_rgctx_tramp) +mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method, gboolean *need_rgctx_tramp, gboolean *variance_used) { - MonoGenericSharingContext *gsctx = mono_get_generic_context_from_code (code); - MonoObject *this_argument = mono_arch_find_this_argument (regs, method, gsctx); + MonoObject *this_argument = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (method), regs, code); MonoVTable *vt = this_argument->vtable; int displacement = slot - ((gpointer*)vt); @@ -137,11 +178,11 @@ mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *cod int interface_offset; int imt_slot = MONO_IMT_SIZE + displacement; - interface_offset = mono_class_interface_offset (vt->klass, imt_method->klass); + /*This has to be variance aware since imt_method can be from an interface that vt->klass doesn't directly implement*/ + interface_offset = mono_class_interface_offset_with_variance (vt->klass, imt_method->klass, variance_used); if (interface_offset < 0) { - 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)); - g_assert_not_reached (); + g_error ("%s doesn't implement interface %s\n", mono_type_get_name_full (&vt->klass->byval_arg, 0), mono_type_get_name_full (&imt_method->klass->byval_arg, 0)); } mono_vtable_build_imt_slot (vt, mono_method_get_imt_slot (imt_method)); @@ -163,7 +204,7 @@ mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *cod context.method_inst = ((MonoMethodInflated*)imt_method)->context.method_inst; impl = mono_class_inflate_generic_method (impl, &context); } else { - impl = mono_class_get_vtable_entry (vt->klass, interface_offset + imt_method->slot); + impl = mono_class_get_vtable_entry (vt->klass, interface_offset + mono_method_get_vtable_slot (imt_method)); } if (mono_method_needs_static_rgctx_invoke (impl, FALSE)) @@ -178,8 +219,13 @@ mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *cod } g_assert (imt_slot < MONO_IMT_SIZE); if (vt->imt_collisions_bitmap & (1 << imt_slot)) { - int vtable_offset = interface_offset + mono_method_get_vtable_index (imt_method); - gpointer *vtable_slot = & (vt->vtable [vtable_offset]); + int slot = mono_method_get_vtable_index (imt_method); + int vtable_offset; + gpointer *vtable_slot; + + g_assert (slot != -1); + vtable_offset = interface_offset + slot; + vtable_slot = & (vt->vtable [vtable_offset]); #if 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); #endif @@ -203,14 +249,15 @@ mono_convert_imt_slot_to_vtable_slot (gpointer* slot, mgreg_t *regs, guint8 *cod static gpointer common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp, MonoVTable *vt, gpointer *vtable_slot, gboolean need_rgctx_tramp) { - gpointer addr; + gpointer addr, compiled_method; gboolean generic_shared = FALSE; MonoMethod *m; MonoMethod *declaring = NULL; - MonoMethod *generic_virtual = NULL; + MonoMethod *generic_virtual = NULL, *variant_iface = NULL; int context_used; - gboolean proxy = FALSE; + gboolean proxy = FALSE, variance_used = FALSE; gpointer *orig_vtable_slot; + MonoJitInfo *ji = NULL; m = arg; @@ -265,7 +312,6 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp #ifdef MONO_ARCH_HAVE_IMT if (m == MONO_FAKE_IMT_METHOD) { MonoMethod *impl_method; - MonoGenericSharingContext *gsctx; MonoObject *this_arg; /* we get the interface method because mono_convert_imt_slot_to_vtable_slot () @@ -275,15 +321,14 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp vtable_slot = orig_vtable_slot; g_assert (vtable_slot); - gsctx = mono_get_generic_context_from_code (code); - this_arg = mono_arch_find_this_argument (regs, m, gsctx); + this_arg = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (m), regs, code); if (this_arg->vtable->klass == mono_defaults.transparent_proxy_class) { /* Use the slow path for now */ proxy = TRUE; m = mono_object_get_virtual_method (this_arg, m); } else { - vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, &impl_method, &need_rgctx_tramp); + vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, &impl_method, &need_rgctx_tramp, &variance_used); /* mono_convert_imt_slot_to_vtable_slot () also gives us the method that is supposed * to be called, so we compile it and go ahead as usual. */ @@ -291,11 +336,25 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp if (m->is_inflated && ((MonoMethodInflated*)m)->context.method_inst) { /* Generic virtual method */ generic_virtual = m; - m = impl_method; need_rgctx_tramp = TRUE; - } else { - m = impl_method; + } else if (variance_used && mono_class_has_variant_generic_params (m->klass)) { + variant_iface = m; } + m = impl_method; + } + } +#endif + +#ifdef MONO_ARCH_LLVM_SUPPORTED + if (!vtable_slot && code && !need_rgctx_tramp && mono_method_needs_static_rgctx_invoke (m, FALSE)) { + /* + * Call this only if the called method is shared, cause it is slow/loads a lot of + * data in AOT. + */ + ji = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL); + if (ji && ji->from_llvm) { + /* LLVM can't pass an rgctx arg */ + need_rgctx_tramp = TRUE; } } #endif @@ -355,8 +414,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp #endif } else { #ifdef MONO_ARCH_HAVE_IMT - MonoObject *this_argument = mono_arch_find_this_argument (regs, m, - mono_get_generic_context_from_code (code)); + MonoObject *this_argument = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (m), regs, code); vt = this_argument->vtable; vtable_slot = orig_vtable_slot; @@ -403,6 +461,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp } g_assert (klass); + g_assert (actual_method); g_assert (actual_method->klass == klass); if (actual_method->is_inflated) @@ -417,7 +476,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp MonoJitInfo *ji; if (code) - ji = mono_jit_info_table_find (mono_domain_get (), (char*)code); + ji = mini_jit_info_table_find (mono_domain_get (), (char*)code, NULL); else ji = NULL; @@ -430,7 +489,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp if (!code && mono_method_needs_static_rgctx_invoke (m, FALSE)) need_rgctx_tramp = TRUE; - addr = mono_compile_method (m); + addr = compiled_method = mono_compile_method (m); g_assert (addr); mono_debugger_trampoline_compiled (code, m, addr); @@ -438,16 +497,18 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp if (need_rgctx_tramp) addr = mono_create_static_rgctx_trampoline (m, addr); - if (generic_virtual) { + if (generic_virtual || variant_iface) { + MonoMethod *target = generic_virtual ? generic_virtual : variant_iface; + vtable_slot = orig_vtable_slot; g_assert (vtable_slot); - if (vt->klass->valuetype) + if (vt->klass->valuetype) /*FIXME is this required variant iface?*/ addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr, need_rgctx_tramp); mono_method_add_generic_virtual_invocation (mono_domain_get (), vt, vtable_slot, - generic_virtual, addr); + target, addr); return addr; } @@ -483,13 +544,14 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp vtable_slot = orig_vtable_slot; if (vtable_slot) { + gboolean variance_used = FALSE; if (m->klass->valuetype) addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr, need_rgctx_tramp); g_assert (*vtable_slot); if (!proxy && (mono_aot_is_got_entry (code, (guint8*)vtable_slot) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot))) { #ifdef MONO_ARCH_HAVE_IMT - vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, NULL, &need_rgctx_tramp); + vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, m, NULL, &need_rgctx_tramp, &variance_used); #endif *vtable_slot = mono_get_addr_from_ftnptr (addr); } @@ -498,9 +560,8 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp guint8 *plt_entry = mono_aot_get_plt_entry (code); if (plt_entry) { - mono_arch_patch_plt_entry (plt_entry, NULL, regs, addr); - } else if (!generic_shared || (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || - mono_domain_lookup_shared_generic (mono_domain_get (), declaring)) { + mono_aot_patch_plt_entry (plt_entry, NULL, regs, addr); + } else { if (generic_shared) { if (m->wrapper_type != MONO_WRAPPER_NONE) m = mono_marshal_method_from_wrapper (m); @@ -508,13 +569,12 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp } /* Patch calling code */ - if (plt_entry) { - - } else { - MonoJitInfo *ji = - mono_jit_info_table_find (mono_domain_get (), (char*)code); + { MonoJitInfo *target_ji = - mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (addr)); + mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method)); + + if (!ji) + ji = mono_jit_info_table_find (mono_domain_get (), (char*)code); if (mono_method_same_domain (ji, target_ji)) mono_arch_patch_callsite (ji->code_start, code, addr); @@ -537,7 +597,9 @@ mono_magic_trampoline (mgreg_t *regs, guint8 *code, gpointer arg, guint8* tramp) int displacement; MonoVTable *vt; - if (code) + trampoline_calls ++; + + if (code && !mono_use_llvm) vt = mono_arch_get_vcall_slot (code, regs, &displacement); else vt = NULL; @@ -561,6 +623,9 @@ mono_llvm_vcall_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 * MonoObject *this; MonoVTable *vt; gpointer *vtable_slot; + int slot; + + trampoline_calls ++; /* * We have the method which is called, we need to obtain the vtable slot without @@ -570,13 +635,17 @@ mono_llvm_vcall_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8 * this = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (m), regs, code); g_assert (this); - g_assert (this->vtable->klass->vtable [mono_method_get_vtable_slot (m)] == m); + slot = mono_method_get_vtable_slot (m); + + g_assert (slot != -1); + + g_assert (this->vtable->klass->vtable [slot] == m); vt = this->vtable; g_assert (!m->is_generic); - vtable_slot = &(vt->vtable [mono_method_get_vtable_slot (m)]); + vtable_slot = &(vt->vtable [slot]); return common_call_trampoline (regs, code, m, tramp, vt, vtable_slot, mono_method_needs_static_rgctx_invoke (m, 0)); } @@ -589,6 +658,8 @@ mono_generic_virtual_remoting_trampoline (mgreg_t *regs, guint8 *code, MonoMetho MonoMethod *imt_method, *declaring; gpointer addr; + trampoline_calls ++; + g_assert (m->is_generic); if (m->is_inflated) @@ -633,9 +704,9 @@ mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info, MonoMethod *method = NULL; gpointer addr; gpointer *vtable_slot; - gboolean is_got_entry; guint8 *plt_entry; - gboolean need_rgctx_tramp = FALSE; + + trampoline_calls ++; image = *(gpointer*)(gpointer)token_info; token_info += sizeof (gpointer); @@ -659,24 +730,7 @@ mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info, plt_entry = mono_aot_get_plt_entry (code); g_assert (plt_entry); - mono_arch_patch_plt_entry (plt_entry, NULL, regs, addr); - - is_got_entry = FALSE; - - /* - * Since AOT code is only used in the root domain, - * mono_domain_get () != mono_get_root_domain () means the calling method - * is AppDomain:InvokeInDomain, so this is the same check as in - * mono_method_same_domain () but without loading the metadata for the method. - */ - if ((is_got_entry && (mono_domain_get () == mono_get_root_domain ())) || mono_domain_owns_vtable_slot (mono_domain_get (), vtable_slot)) { -#ifdef MONO_ARCH_HAVE_IMT - if (!method) - method = mono_get_method (image, token, NULL); - vtable_slot = mono_convert_imt_slot_to_vtable_slot (vtable_slot, regs, code, method, NULL, &need_rgctx_tramp); -#endif - *vtable_slot = addr; - } + mono_aot_patch_plt_entry (plt_entry, NULL, regs, addr); return addr; } @@ -691,8 +745,19 @@ mono_aot_plt_trampoline (mgreg_t *regs, guint8 *code, guint8 *aot_module, guint8* tramp) { guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code); + gpointer res; - return mono_aot_plt_resolve (aot_module, plt_info_offset, code); + trampoline_calls ++; + + res = mono_aot_plt_resolve (aot_module, plt_info_offset, code); + if (!res) { + if (mono_loader_get_last_error ()) + mono_raise_exception (mono_loader_error_prepare_exception (mono_loader_get_last_error ())); + // FIXME: Error handling (how ?) + g_assert (res); + } + + return res; } #endif @@ -707,6 +772,8 @@ mono_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, gui { guint8 *plt_entry = mono_aot_get_plt_entry (code); + trampoline_calls ++; + mono_runtime_class_init (vtable); if (plt_entry) { @@ -725,6 +792,8 @@ mono_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, gui void mono_generic_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp) { + trampoline_calls ++; + mono_runtime_class_init (vtable); } @@ -740,6 +809,8 @@ mono_rgctx_lazy_fetch_trampoline (mgreg_t *regs, guint8 *code, gpointer data, gu guint32 index = MONO_RGCTX_SLOT_INDEX (slot); gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot); + trampoline_calls ++; + if (!inited) { mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_lookups); inited = TRUE; @@ -784,11 +855,15 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui MonoJitInfo *ji; MonoMethod *m; MonoMethod *method = NULL; - gboolean multicast, callvirt; + gboolean multicast, callvirt = FALSE; gboolean need_rgctx_tramp = FALSE; MonoMethod *invoke = tramp_data [0]; guint8 *impl_this = tramp_data [1]; guint8 *impl_nothis = tramp_data [2]; + MonoError err; + MonoMethodSignature *sig; + + trampoline_calls ++; /* Obtain the delegate object according to the calling convention */ @@ -815,14 +890,29 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui #endif method = mono_marshal_get_remoting_invoke (method); } - else if (mono_method_signature (method)->hasthis && method->klass->valuetype) - method = mono_marshal_get_unbox_wrapper (method); + else { + mono_error_init (&err); + sig = mono_method_signature_checked (method, &err); + if (!sig) + mono_error_raise_exception (&err); + + if (sig->hasthis && method->klass->valuetype) + method = mono_marshal_get_unbox_wrapper (method); + } } else { ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr)); if (ji) method = ji->method; } - callvirt = !delegate->target && method && mono_method_signature (method)->hasthis; + + if (method) { + mono_error_init (&err); + sig = mono_method_signature_checked (method, &err); + if (!sig) + mono_error_raise_exception (&err); + + callvirt = !delegate->target && sig->hasthis; + } if (method && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) method = mono_marshal_get_synchronized_wrapper (method); @@ -840,15 +930,17 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui delegate->method_ptr = *delegate->method_code; } else { delegate->method_ptr = mono_compile_method (method); + if (need_rgctx_tramp) + delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr); if (delegate->method_code) *delegate->method_code = delegate->method_ptr; mono_debugger_trampoline_compiled (NULL, method, delegate->method_ptr); } + } else { + if (need_rgctx_tramp) + delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr); } - if (need_rgctx_tramp) - delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr); - multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL; if (!multicast && !callvirt) { if (method && (method->flags & METHOD_ATTRIBUTE_STATIC) && mono_method_signature (method)->param_count == mono_method_signature (invoke)->param_count + 1) @@ -874,6 +966,60 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, gui #endif +#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD +static gpointer +mono_handler_block_guard_trampoline (mgreg_t *regs, guint8 *code, gpointer *tramp_data, guint8* tramp) +{ + MonoContext ctx; + MonoException *exc; + MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); + gpointer resume_ip = jit_tls->handler_block_return_address; + + memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext)); + MONO_CONTEXT_SET_IP (&ctx, jit_tls->handler_block_return_address); + + jit_tls->handler_block_return_address = NULL; + jit_tls->handler_block = NULL; + + if (!resume_ip) /*this should not happen, but we should avoid crashing */ + exc = mono_get_exception_execution_engine ("Invalid internal state, resuming abort after handler block but no resume ip found"); + else + exc = mono_thread_resume_interruption (); + + if (exc) { + static void (*restore_context) (MonoContext *); + + if (!restore_context) + restore_context = mono_get_restore_context (); + + mono_handle_exception (&ctx, exc, NULL, FALSE); + restore_context (&ctx); + } + + return resume_ip; +} + +gpointer +mono_create_handler_block_trampoline (void) +{ + static gpointer code; + + if (mono_aot_only) { + g_assert (0); + return code; + } + + mono_trampolines_lock (); + + if (!code) + code = mono_arch_create_handler_block_trampoline (); + + mono_trampolines_unlock (); + + return code; +} +#endif + /* * mono_get_trampoline_func: * @@ -914,6 +1060,10 @@ mono_get_trampoline_func (MonoTrampolineType tramp_type) #ifdef MONO_ARCH_LLVM_SUPPORTED case MONO_TRAMPOLINE_LLVM_VCALL: return mono_llvm_vcall_trampoline; +#endif +#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD + case MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD: + return mono_handler_block_guard_trampoline; #endif default: g_assert_not_reached (); @@ -921,6 +1071,21 @@ mono_get_trampoline_func (MonoTrampolineType tramp_type) } } +static guchar* +create_trampoline_code (MonoTrampolineType tramp_type) +{ + MonoTrampInfo *info; + guchar *code; + + code = mono_arch_create_generic_trampoline (tramp_type, &info, FALSE); + if (info) { + mono_save_trampoline_xdebug_info (info->name, info->code, info->code_size, info->unwind_ops); + mono_tramp_info_free (info); + } + + return code; +} + void mono_trampolines_init (void) { @@ -929,25 +1094,31 @@ mono_trampolines_init (void) if (mono_aot_only) return; - mono_trampoline_code [MONO_TRAMPOLINE_JIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JIT); - mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_JUMP); - mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT); - mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT); - mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH); + mono_trampoline_code [MONO_TRAMPOLINE_JIT] = create_trampoline_code (MONO_TRAMPOLINE_JIT); + mono_trampoline_code [MONO_TRAMPOLINE_JUMP] = create_trampoline_code (MONO_TRAMPOLINE_JUMP); + mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT); + mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_CLASS_INIT] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT); + mono_trampoline_code [MONO_TRAMPOLINE_RGCTX_LAZY_FETCH] = create_trampoline_code (MONO_TRAMPOLINE_RGCTX_LAZY_FETCH); #ifdef MONO_ARCH_AOT_SUPPORTED - mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT); - mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT); + mono_trampoline_code [MONO_TRAMPOLINE_AOT] = create_trampoline_code (MONO_TRAMPOLINE_AOT); + mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT); #endif #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE - mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE); + mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = create_trampoline_code (MONO_TRAMPOLINE_DELEGATE); #endif - mono_trampoline_code [MONO_TRAMPOLINE_RESTORE_STACK_PROT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT); - mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING); - mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER); - mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT); + mono_trampoline_code [MONO_TRAMPOLINE_RESTORE_STACK_PROT] = create_trampoline_code (MONO_TRAMPOLINE_RESTORE_STACK_PROT); + mono_trampoline_code [MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING] = create_trampoline_code (MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING); + mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_ENTER] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_ENTER); + mono_trampoline_code [MONO_TRAMPOLINE_MONITOR_EXIT] = create_trampoline_code (MONO_TRAMPOLINE_MONITOR_EXIT); #ifdef MONO_ARCH_LLVM_SUPPORTED - mono_trampoline_code [MONO_TRAMPOLINE_LLVM_VCALL] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_LLVM_VCALL); + mono_trampoline_code [MONO_TRAMPOLINE_LLVM_VCALL] = create_trampoline_code (MONO_TRAMPOLINE_LLVM_VCALL); +#endif +#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD + mono_trampoline_code [MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD] = create_trampoline_code (MONO_TRAMPOLINE_HANDLER_BLOCK_GUARD); + mono_create_handler_block_trampoline (); #endif + + mono_counters_register ("Calls to trampolines", MONO_COUNTER_JIT | MONO_COUNTER_INT, &trampoline_calls); } void @@ -1022,9 +1193,10 @@ mono_create_generic_class_init_trampoline (void) if (!code) { if (mono_aot_only) - code = mono_aot_get_named_code ("generic_class_init_trampoline"); + /* get_named_code () might return an ftnptr, but our caller expects a direct pointer */ + code = mono_get_addr_from_ftnptr (mono_aot_get_trampoline ("generic_class_init_trampoline")); else - code = mono_arch_create_generic_class_init_trampoline (); + code = mono_arch_create_generic_class_init_trampoline (NULL, FALSE); } mono_trampolines_unlock (); @@ -1196,7 +1368,7 @@ mono_create_rgctx_lazy_fetch_trampoline (guint32 offset) if (tramp) return tramp; - tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset); + tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset, NULL, FALSE); ptr = mono_create_ftnptr (mono_get_root_domain (), tramp); mono_trampolines_lock (); @@ -1226,7 +1398,7 @@ mono_create_monitor_enter_trampoline (void) if (mono_aot_only) { if (!code) - code = mono_aot_get_named_code ("monitor_enter_trampoline"); + code = mono_aot_get_trampoline ("monitor_enter_trampoline"); return code; } @@ -1234,7 +1406,7 @@ mono_create_monitor_enter_trampoline (void) mono_trampolines_lock (); if (!code) - code = mono_arch_create_monitor_enter_trampoline (); + code = mono_arch_create_monitor_enter_trampoline (NULL, FALSE); mono_trampolines_unlock (); #else @@ -1252,7 +1424,7 @@ mono_create_monitor_exit_trampoline (void) if (mono_aot_only) { if (!code) - code = mono_aot_get_named_code ("monitor_exit_trampoline"); + code = mono_aot_get_trampoline ("monitor_exit_trampoline"); return code; } @@ -1260,7 +1432,7 @@ mono_create_monitor_exit_trampoline (void) mono_trampolines_lock (); if (!code) - code = mono_arch_create_monitor_exit_trampoline (); + code = mono_arch_create_monitor_exit_trampoline (NULL, FALSE); mono_trampolines_unlock (); #else