X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-trampolines.c;h=78b7daf91e0a42adf65007f2a724501f426fe502;hb=8f7da560f35e88570717df31e8c96668af61eb2c;hp=741d9e8c82817917fe109a2993c246d971dfdf89;hpb=2a73552b4cce3a83045c8334d927d7d3a95a9099;p=mono.git diff --git a/mono/mini/mini-trampolines.c b/mono/mini/mini-trampolines.c index 741d9e8c828..78b7daf91e0 100644 --- a/mono/mini/mini-trampolines.c +++ b/mono/mini/mini-trampolines.c @@ -23,19 +23,20 @@ guint8* mono_trampoline_code [MONO_TRAMPOLINE_NUM]; static GHashTable *class_init_hash_addr = NULL; static GHashTable *delegate_trampoline_hash_addr = NULL; +static GHashTable *rgctx_lazy_fetch_trampoline_hash = NULL; +static GHashTable *rgctx_lazy_fetch_trampoline_hash_addr = NULL; #define mono_trampolines_lock() EnterCriticalSection (&trampolines_mutex) #define mono_trampolines_unlock() LeaveCriticalSection (&trampolines_mutex) static CRITICAL_SECTION trampolines_mutex; -static MonoGenericSharingContext* -get_generic_context (guint8 *code) +static gpointer +get_unbox_trampoline (MonoGenericSharingContext *gsctx, MonoMethod *m, gpointer addr) { - MonoJitInfo *jit_info = mono_jit_info_table_find (mono_domain_get (), (char*)code); - - g_assert (jit_info); - - return mono_jit_info_get_generic_sharing_context (jit_info); + if (mono_aot_only) + return mono_aot_get_unbox_trampoline (m); + else + return mono_arch_get_unbox_trampoline (gsctx, m, addr); } #ifdef MONO_ARCH_HAVE_IMT @@ -43,7 +44,7 @@ get_generic_context (guint8 *code) static gpointer* mono_convert_imt_slot_to_vtable_slot (gpointer* slot, gpointer *regs, guint8 *code, MonoMethod *method, MonoMethod **impl_method) { - MonoGenericSharingContext *gsctx = get_generic_context (code); + MonoGenericSharingContext *gsctx = mono_get_generic_context_from_code (code); MonoObject *this_argument = mono_arch_find_this_argument (regs, method, gsctx); MonoVTable *vt = this_argument->vtable; int displacement = slot - ((gpointer*)vt); @@ -105,6 +106,7 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp) gpointer *vtable_slot; gboolean generic_shared = FALSE; MonoMethod *declaring = NULL; + int context_used; #if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE if (m == MONO_FAKE_VTABLE_METHOD) { @@ -129,8 +131,6 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp) mono_class_setup_vtable (vt->klass); m = vt->klass->vtable [displacement]; - if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) - m = mono_marshal_get_synchronized_wrapper (m); /*g_print ("%s with disp %d: %s at %p\n", vt->klass->name, displacement, m->name, code);*/ } else { /* We got here from an interface method: redirect to IMT handling */ @@ -158,18 +158,27 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp) } #endif - if (mono_method_check_context_used (m)) { + if ((context_used = mono_method_check_context_used (m))) { MonoClass *klass = NULL; MonoMethod *actual_method = NULL; MonoVTable *vt = NULL; + MonoGenericInst *method_inst = NULL; vtable_slot = NULL; generic_shared = TRUE; g_assert (code); + if (m->is_inflated && mono_method_get_context (m)->method_inst) { +#ifdef MONO_ARCH_RGCTX_REG + MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext*)mono_arch_find_static_call_vtable ((gpointer*)regs, code); - if (m->flags & METHOD_ATTRIBUTE_STATIC) { + klass = mrgctx->class_vtable->klass; + method_inst = mrgctx->method_inst; +#else + g_assert_not_reached (); +#endif + } else if (m->flags & METHOD_ATTRIBUTE_STATIC) { #ifdef MONO_ARCH_RGCTX_REG MonoVTable *vtable = mono_arch_find_static_call_vtable ((gpointer*)regs, code); @@ -180,7 +189,7 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp) } else { #ifdef MONO_ARCH_HAVE_IMT MonoObject *this_argument = mono_arch_find_this_argument ((gpointer*)regs, m, - get_generic_context (code)); + mono_get_generic_context_from_code (code)); vt = this_argument->vtable; vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs); @@ -205,49 +214,89 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp) g_assert (displacement > 0); actual_method = vt->klass->vtable [displacement]; - } else { - int i; + } + + if (method_inst) { + MonoGenericContext context = { NULL, NULL }; if (m->is_inflated) declaring = mono_method_get_declaring_generic_method (m); else declaring = m; - if (klass->generic_class && !klass->methods) { - /* Avoid calling setup_methods () if possible */ - actual_method = mono_class_inflate_generic_method_full (declaring, klass, mono_class_get_context (klass)); - } else { - mono_class_setup_methods (klass); - for (i = 0; i < klass->method.count; ++i) { - actual_method = klass->methods [i]; - if (actual_method->is_inflated) { - if (mono_method_get_declaring_generic_method (actual_method) == declaring) - break; - } - } - } + if (klass->generic_class) + context.class_inst = klass->generic_class->context.class_inst; + else if (klass->generic_container) + context.class_inst = klass->generic_container->context.class_inst; + context.method_inst = method_inst; - g_assert (mono_method_get_declaring_generic_method (actual_method) == declaring); + actual_method = mono_class_inflate_generic_method (declaring, &context); + } else { + actual_method = mono_class_get_method_generic (klass, m); } - g_assert (actual_method); + g_assert (klass); + g_assert (actual_method->klass == klass); + + if (actual_method->is_inflated) + declaring = mono_method_get_declaring_generic_method (actual_method); + else + declaring = NULL; + m = actual_method; } + if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) { + MonoJitInfo *ji; + + if (code) + ji = mono_jit_info_table_find (mono_domain_get (), (char*)code); + else + ji = NULL; + + /* Avoid recursion */ + if (!(ji && ji->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)) + m = mono_marshal_get_synchronized_wrapper (m); + } + addr = mono_compile_method (m); g_assert (addr); mono_debugger_trampoline_compiled (m, addr); /* the method was jumped to */ - if (!code) + if (!code) { + MonoDomain *domain = mono_domain_get (); + + /* Patch the got entries pointing to this method */ + /* + * We do this here instead of in mono_codegen () to cover the case when m + * was loaded from an aot image. + */ + if (jit_domain_info (domain)->jump_target_got_slot_hash) { + GSList *list, *tmp; + + mono_domain_lock (domain); + list = g_hash_table_lookup (jit_domain_info (domain)->jump_target_got_slot_hash, m); + if (list) { + for (tmp = list; tmp; tmp = tmp->next) { + gpointer *got_slot = tmp->data; + *got_slot = addr; + } + g_hash_table_remove (jit_domain_info (domain)->jump_target_got_slot_hash, m); + g_slist_free (list); + } + mono_domain_unlock (domain); + } + return addr; + } vtable_slot = mono_arch_get_vcall_slot_addr (code, (gpointer*)regs); if (vtable_slot) { if (m->klass->valuetype) - addr = mono_arch_get_unbox_trampoline (m, addr); + addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), m, addr); g_assert (*vtable_slot); @@ -258,9 +307,13 @@ mono_magic_trampoline (gssize *regs, guint8 *code, MonoMethod *m, guint8* tramp) *vtable_slot = mono_get_addr_from_ftnptr (addr); } } - else if (!generic_shared || mono_domain_lookup_shared_generic (mono_domain_get (), declaring)) { + else if (!generic_shared || (m->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || + mono_domain_lookup_shared_generic (mono_domain_get (), declaring)) { guint8 *plt_entry = mono_aot_get_plt_entry (code); + if (generic_shared) + g_assert (mono_method_is_generic_sharable_impl (m, FALSE)); + /* Patch calling code */ if (plt_entry) { mono_arch_patch_plt_entry (plt_entry, addr); @@ -323,7 +376,7 @@ mono_aot_trampoline (gssize *regs, guint8 *code, guint8 *token_info, if (!method) method = mono_get_method (image, token, NULL); if (method->klass->valuetype) - addr = mono_arch_get_unbox_trampoline (method, addr); + addr = get_unbox_trampoline (mono_get_generic_context_from_code (code), method, addr); } } else { /* This is a normal call through a PLT entry */ @@ -363,11 +416,7 @@ gpointer mono_aot_plt_trampoline (gssize *regs, guint8 *code, guint8 *aot_module, guint8* tramp) { -#ifdef MONO_ARCH_AOT_PLT_OFFSET_REG - guint32 plt_info_offset = regs [MONO_ARCH_AOT_PLT_OFFSET_REG]; -#else - guint32 plt_info_offset = -1; -#endif + guint32 plt_info_offset = mono_aot_get_plt_info_offset (regs, code); return mono_aot_plt_resolve (aot_module, plt_info_offset, code); } @@ -404,20 +453,21 @@ mono_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guin void mono_generic_class_init_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp) { - //g_print ("generic class init for class %s.%s\n", vtable->klass->name_space, vtable->klass->name); + g_assert (!vtable->initialized); mono_runtime_class_init (vtable); - - //g_print ("done initing generic\n"); } static gpointer -mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable, guint8 *tramp) +mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, gpointer data, guint8 *tramp) { +#ifdef MONO_ARCH_VTABLE_REG static gboolean inited = FALSE; static int num_lookups = 0; - - guint32 slot = mono_arch_get_rgctx_lazy_fetch_offset ((gpointer*)regs); + guint32 slot = GPOINTER_TO_UINT (data); + gpointer arg = (gpointer)(gssize)regs [MONO_ARCH_VTABLE_REG]; + guint32 index = MONO_RGCTX_SLOT_INDEX (slot); + gboolean mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot); if (!inited) { mono_counters_register ("RGCTX unmanaged lookups", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_lookups); @@ -426,7 +476,13 @@ mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable num_lookups++; - return mono_class_fill_runtime_generic_context (vtable, slot); + if (mrgctx) + return mono_method_fill_runtime_generic_context (arg, index); + else + return mono_class_fill_runtime_generic_context (arg, index); +#else + g_assert_not_reached (); +#endif } #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE @@ -435,23 +491,28 @@ mono_rgctx_lazy_fetch_trampoline (gssize *regs, guint8 *code, MonoVTable *vtable * mono_delegate_trampoline: * * This trampoline handles calls made to Delegate:Invoke (). + * This is called once the first time a delegate is invoked, so it must be fast. */ gpointer -mono_delegate_trampoline (gssize *regs, guint8 *code, MonoClass *klass, guint8* tramp) +mono_delegate_trampoline (gssize *regs, guint8 *code, gpointer *tramp_data, guint8* tramp) { MonoDomain *domain = mono_domain_get (); MonoDelegate *delegate; MonoJitInfo *ji; - MonoMethod *invoke, *m; + MonoMethod *m; MonoMethod *method = NULL; gboolean multicast, callvirt; - - invoke = mono_get_delegate_invoke (klass); - g_assert (invoke); + MonoMethod *invoke = tramp_data [0]; + guint8 *impl_this = tramp_data [1]; + guint8 *impl_nothis = tramp_data [2]; /* Obtain the delegate object according to the calling convention */ - delegate = mono_arch_get_this_arg_from_call (mono_method_signature (invoke), regs, code); + /* + * Avoid calling mono_get_generic_context_from_code () now since it is expensive, + * get_this_arg_from_call will call it if needed. + */ + delegate = mono_arch_get_this_arg_from_call (NULL, mono_method_signature (invoke), regs, code); if (!delegate->method_ptr && delegate->method) { /* The delegate was initialized by mini_delegate_ctor */ @@ -461,6 +522,8 @@ mono_delegate_trampoline (gssize *regs, guint8 *code, MonoClass *klass, guint8* 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 if (delegate->method) { + method = delegate->method; } else { ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (delegate->method_ptr)); if (ji) @@ -468,18 +531,28 @@ mono_delegate_trampoline (gssize *regs, guint8 *code, MonoClass *klass, guint8* } callvirt = !delegate->target && method && mono_method_signature (method)->hasthis; + if (method && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) + method = mono_marshal_get_synchronized_wrapper (method); + /* * If the called address is a trampoline, replace it with the compiled method so * further calls don't have to go through the trampoline. */ if (method && !callvirt) { - delegate->method_ptr = mono_compile_method (method); - mono_debugger_trampoline_compiled (method, delegate->method_ptr); + /* Avoid the overhead of looking up an already compiled method if possible */ + if (delegate->method_code && *delegate->method_code) { + delegate->method_ptr = *delegate->method_code; + } else { + delegate->method_ptr = mono_compile_method (method); + if (delegate->method_code) + *delegate->method_code = delegate->method_ptr; + mono_debugger_trampoline_compiled (method, delegate->method_ptr); + } } multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL; if (!multicast && !callvirt) { - code = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), delegate->target != NULL); + code = delegate->target ? impl_this : impl_nothis; if (code) { delegate->invoke_impl = code; @@ -508,7 +581,7 @@ gconstpointer mono_get_trampoline_func (MonoTrampolineType tramp_type) { switch (tramp_type) { - case MONO_TRAMPOLINE_GENERIC: + case MONO_TRAMPOLINE_JIT: case MONO_TRAMPOLINE_JUMP: return mono_magic_trampoline; case MONO_TRAMPOLINE_CLASS_INIT: @@ -538,7 +611,10 @@ mono_trampolines_init (void) { InitializeCriticalSection (&trampolines_mutex); - mono_trampoline_code [MONO_TRAMPOLINE_GENERIC] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_GENERIC); + 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); @@ -566,9 +642,20 @@ mono_trampolines_cleanup (void) guint8 * mono_get_trampoline_code (MonoTrampolineType tramp_type) { + g_assert (mono_trampoline_code [tramp_type]); + return mono_trampoline_code [tramp_type]; } +gpointer +mono_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) +{ + if (mono_aot_only) + return mono_aot_create_specific_trampoline (mono_defaults.corlib, arg1, tramp_type, domain, code_len); + else + return mono_arch_create_specific_trampoline (arg1, tramp_type, domain, code_len); +} + gpointer mono_create_class_init_trampoline (MonoVTable *vtable) { @@ -585,7 +672,7 @@ mono_create_class_init_trampoline (MonoVTable *vtable) if (ptr) return ptr; - code = mono_arch_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL); + code = mono_create_specific_trampoline (vtable, MONO_TRAMPOLINE_CLASS_INIT, vtable->domain, NULL); ptr = mono_create_ftnptr (vtable->domain, code); @@ -605,16 +692,31 @@ mono_create_class_init_trampoline (MonoVTable *vtable) } gpointer -mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, - gboolean add_sync_wrapper) +mono_create_generic_class_init_trampoline (void) +{ +#ifdef MONO_ARCH_VTABLE_REG + static gpointer code; + + mono_trampolines_lock (); + + if (!code) + code = mono_arch_create_generic_class_init_trampoline (); + + mono_trampolines_unlock (); + + return code; +#else + g_assert_not_reached (); +#endif +} + +gpointer +mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper) { MonoJitInfo *ji; gpointer code; guint32 code_size = 0; - if (add_sync_wrapper && method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) - return mono_create_jump_trampoline (domain, mono_marshal_get_synchronized_wrapper (method), FALSE); - code = mono_jit_find_compiled_method (domain, method); if (code) return code; @@ -625,7 +727,7 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, if (code) return code; - code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size); + code = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size); g_assert (code_size); mono_domain_lock (domain); @@ -654,16 +756,21 @@ mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method) { gpointer tramp; + if (mono_aot_only) { + /* Avoid creating trampolines if possible */ + gpointer code = mono_jit_find_compiled_method (domain, method); + + if (code) + return code; + } + mono_domain_lock (domain); tramp = g_hash_table_lookup (domain->jit_trampoline_hash, method); mono_domain_unlock (domain); if (tramp) return tramp; - if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) - return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method)); - - tramp = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, domain, NULL); + tramp = mono_create_specific_trampoline (method, MONO_TRAMPOLINE_JIT, domain, NULL); mono_domain_lock (domain); g_hash_table_insert (domain->jit_trampoline_hash, method, tramp); @@ -697,7 +804,7 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token) buf += sizeof (gpointer); *(guint32*)(gpointer)buf = token; - tramp = mono_arch_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL); + tramp = mono_create_specific_trampoline (start, MONO_TRAMPOLINE_AOT, domain, NULL); mono_jit_stats.method_trampolines++; @@ -712,6 +819,8 @@ mono_create_delegate_trampoline (MonoClass *klass) MonoDomain *domain = mono_domain_get (); gpointer ptr; guint32 code_size = 0; + gpointer *tramp_data; + MonoMethod *invoke; mono_domain_lock (domain); ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass); @@ -719,7 +828,23 @@ mono_create_delegate_trampoline (MonoClass *klass) if (ptr) return ptr; - ptr = mono_arch_create_specific_trampoline (klass, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size); + // Precompute the delegate invoke impl and pass it to the delegate trampoline + invoke = mono_get_delegate_invoke (klass); + g_assert (invoke); + + mono_domain_lock (domain ); + tramp_data = mono_mempool_alloc (domain->mp, sizeof (gpointer) * 3); + mono_domain_unlock (domain); + tramp_data [0] = invoke; + if (mono_aot_only) { + tramp_data [1] = NULL; + tramp_data [2] = NULL; + } else { + tramp_data [1] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE); + tramp_data [2] = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE); + } + + ptr = mono_create_specific_trampoline (tramp_data, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size); g_assert (code_size); /* store trampoline address */ @@ -740,6 +865,49 @@ mono_create_delegate_trampoline (MonoClass *klass) #endif } +gpointer +mono_create_rgctx_lazy_fetch_trampoline (guint32 offset) +{ + static gboolean inited = FALSE; + static int num_trampolines = 0; + + gpointer tramp, ptr; + + if (mono_aot_only) + return mono_aot_get_lazy_fetch_trampoline (offset); + + mono_trampolines_lock (); + if (rgctx_lazy_fetch_trampoline_hash) + tramp = g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset)); + else + tramp = NULL; + mono_trampolines_unlock (); + if (tramp) + return tramp; + + tramp = mono_arch_create_rgctx_lazy_fetch_trampoline (offset); + ptr = mono_create_ftnptr (mono_get_root_domain (), tramp); + + mono_trampolines_lock (); + if (!rgctx_lazy_fetch_trampoline_hash) { + rgctx_lazy_fetch_trampoline_hash = g_hash_table_new (NULL, NULL); + rgctx_lazy_fetch_trampoline_hash_addr = g_hash_table_new (NULL, NULL); + } + g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash, GUINT_TO_POINTER (offset), ptr); + g_assert (offset != -1); + g_hash_table_insert (rgctx_lazy_fetch_trampoline_hash_addr, ptr, GUINT_TO_POINTER (offset + 1)); + mono_trampolines_unlock (); + + if (!inited) { + mono_counters_register ("RGCTX num lazy fetch trampolines", + MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_trampolines); + inited = TRUE; + } + num_trampolines++; + + return ptr; +} + MonoVTable* mono_find_class_init_trampoline_by_addr (gconstpointer addr) { @@ -767,3 +935,23 @@ mono_find_delegate_trampoline_by_addr (gconstpointer addr) mono_trampolines_unlock (); return res; } + +guint32 +mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr) +{ + int offset; + + mono_trampolines_lock (); + if (rgctx_lazy_fetch_trampoline_hash_addr) { + /* We store the real offset + 1 so we can detect when the lookup fails */ + offset = GPOINTER_TO_INT (g_hash_table_lookup (rgctx_lazy_fetch_trampoline_hash_addr, addr)); + if (offset) + offset -= 1; + else + offset = -1; + } else { + offset = -1; + } + mono_trampolines_unlock (); + return offset; +}