Please see the attached patch that is a separated and improved version of the prevously submitted patch.
ChangeLog draft: mono_image_fixup_vtable is now called only when the image is loaded and creates trampolines rather than pointers to wrapper functions. A new trampoline type MONO_TRAMPOLINE_VTFIXUP is added that is created by mono_image_fixup_vtable, and is replacing the pointer to the trampoline with the result mono_marshal_get_vtfixup_ftnptr. Please review and if you like it, approve the patch. Thanks. Kornél
Index: mono/mono/metadata/assembly.c =================================================================== --- mono/mono/metadata/assembly.c (revision 145149) +++ mono/mono/metadata/assembly.c (working copy) @@ -1522,11 +1522,6 @@ loaded_assemblies = g_list_prepend (loaded_assemblies, ass); mono_assemblies_unlock (); -#ifdef PLATFORM_WIN32 - if (image->is_module_handle) - mono_image_fixup_vtable (image); -#endif - mono_assembly_invoke_load_hook (ass); mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK); Index: mono/mono/metadata/coree.c =================================================================== --- mono/mono/metadata/coree.c (revision 145149) +++ mono/mono/metadata/coree.c (working copy) @@ -106,20 +106,12 @@ } } - if (!image) { - g_free (file_name); + g_free (file_name); + + if (!image) return FALSE; - } - /* - * FIXME: Find a better way to call mono_image_fixup_vtable. Only - * loader trampolines should be used and assembly loading should - * probably be delayed until the first call to an exported function. - */ - if (image->tables [MONO_TABLE_ASSEMBLY].rows && ((MonoCLIImageInfo*) image->image_info)->cli_cli_header.ch_vtable_fixups.rva) - assembly = mono_assembly_open (file_name, NULL); - - g_free (file_name); + mono_image_fixup_vtable (image); break; case DLL_PROCESS_DETACH: if (lpReserved != NULL) @@ -198,6 +190,8 @@ argv [i] = g_utf16_to_utf8 (argvw [i], -1, NULL, NULL, NULL); LocalFree (argvw); + mono_image_fixup_vtable (image); + mono_runtime_run_main (method, argc, argv, NULL); mono_thread_manage (); @@ -919,8 +913,10 @@ void mono_fixup_exe_image (MonoImage* image) { - if (!init_from_coree && image && image->is_module_handle) + if (!init_from_coree && image && image->is_module_handle) { MonoFixupExe ((HMODULE) image->raw_data); + mono_image_fixup_vtable (image); + } } #endif /* PLATFORM_WIN32 */ Index: mono/mono/metadata/object.c =================================================================== --- mono/mono/metadata/object.c (revision 145149) +++ mono/mono/metadata/object.c (working copy) @@ -470,10 +470,18 @@ return NULL; } +static gpointer +default_vtfixup_trampoline (gpointer slot, MonoImage *image, guint32 token, guint16 type) +{ + g_assert_not_reached (); + return NULL; +} + static MonoTrampoline arch_create_jit_trampoline = default_trampoline; static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline; static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline; static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline; +static MonoVTFixupTrampoline arch_create_vtfixup_trampoline = default_vtfixup_trampoline; static MonoImtThunkBuilder imt_thunk_builder = NULL; #define ARCH_USE_IMT (imt_thunk_builder != NULL) #if (MONO_IMT_SIZE > 32) @@ -517,6 +525,12 @@ } void +mono_install_vtfixup_trampoline (MonoVTFixupTrampoline func) +{ + arch_create_vtfixup_trampoline = func? func: default_vtfixup_trampoline; +} + +void mono_install_imt_thunk_builder (MonoImtThunkBuilder func) { imt_thunk_builder = func; } @@ -564,6 +578,12 @@ return arch_create_delegate_trampoline (klass); } +gpointer +mono_runtime_create_vtfixup_trampoline (gpointer slot, MonoImage *image, guint32 token, guint16 type) +{ + return arch_create_vtfixup_trampoline (slot, image, token, type); +} + static MonoFreeMethodFunc default_mono_free_method = NULL; /** Index: mono/mono/metadata/class-internals.h =================================================================== --- mono/mono/metadata/class-internals.h (revision 145149) +++ mono/mono/metadata/class-internals.h (working copy) @@ -803,6 +803,7 @@ typedef gpointer (*MonoJumpTrampoline) (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper); typedef gpointer (*MonoRemotingTrampoline) (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target); typedef gpointer (*MonoDelegateTrampoline) (MonoClass *klass); +typedef gpointer (*MonoVTFixupTrampoline) (gpointer slot, MonoImage *image, guint32 token, guint16 type); typedef gpointer (*MonoLookupDynamicToken) (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context); @@ -892,6 +893,9 @@ void mono_install_delegate_trampoline (MonoDelegateTrampoline func) MONO_INTERNAL; +void +mono_install_vtfixup_trampoline (MonoVTFixupTrampoline func) MONO_INTERNAL; + gpointer mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context) MONO_INTERNAL; @@ -907,6 +911,9 @@ gpointer mono_runtime_create_delegate_trampoline (MonoClass *klass) MONO_INTERNAL; +gpointer +mono_runtime_create_vtfixup_trampoline (gpointer slot, MonoImage *image, guint32 token, guint16 type) MONO_INTERNAL; + void mono_install_get_cached_class_info (MonoGetCachedClassInfo func) MONO_INTERNAL; Index: mono/mono/metadata/image.c =================================================================== --- mono/mono/metadata/image.c (revision 145149) +++ mono/mono/metadata/image.c (working copy) @@ -572,10 +572,6 @@ if (image->modules [idx - 1]) { mono_image_addref (image->modules [idx - 1]); image->modules [idx - 1]->assembly = image->assembly; -#ifdef PLATFORM_WIN32 - if (image->modules [idx - 1]->is_module_handle) - mono_image_fixup_vtable (image->modules [idx - 1]); -#endif /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */ } g_free (module_ref); @@ -1292,7 +1288,6 @@ void mono_image_fixup_vtable (MonoImage *image) { -#ifdef PLATFORM_WIN32 MonoCLIImageInfo *iinfo; MonoPEDirEntry *de; MonoVTableFixup *vtfixup; @@ -1301,7 +1296,10 @@ guint16 slot_type; int slot_count; - g_assert (image->is_module_handle); +#ifdef PLATFORM_WIN32 + if (!image->is_module_handle) +#endif + g_assert_not_reached(); iinfo = image->image_info; de = &iinfo->cli_cli_header.ch_vtable_fixups; @@ -1310,7 +1308,7 @@ vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva); if (!vtfixup) return; - + count = de->size / sizeof (MonoVTableFixup); while (count--) { if (!vtfixup->rva || !vtfixup->count) @@ -1320,24 +1318,26 @@ g_assert (slot); slot_type = vtfixup->type; slot_count = vtfixup->count; - if (slot_type & VTFIXUP_TYPE_32BIT) + + switch (slot_type & (VTFIXUP_TYPE_32BIT | VTFIXUP_TYPE_64BIT)) { + case VTFIXUP_TYPE_32BIT: while (slot_count--) { - *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type); + *((guint32*) slot) = (guint32) mono_runtime_create_vtfixup_trampoline (slot, image, *((guint32*) slot), slot_type); slot = ((guint32*) slot) + 1; } - else if (slot_type & VTFIXUP_TYPE_64BIT) + break; + case VTFIXUP_TYPE_64BIT: while (slot_count--) { - *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type); - slot = ((guint32*) slot) + 1; + *((guint64*) slot) = (guint64) mono_runtime_create_vtfixup_trampoline (slot, image, *((guint64*) slot), slot_type); + slot = ((guint64*) slot) + 1; } - else + break; + default: g_assert_not_reached(); + } vtfixup++; } -#else - g_assert_not_reached(); -#endif } static void @@ -1926,10 +1926,6 @@ } image->files [fileidx - 1] = res; -#ifdef PLATFORM_WIN32 - if (res->is_module_handle) - mono_image_fixup_vtable (res); -#endif } mono_loader_unlock (); g_free (name); Index: mono/mono/metadata/marshal.c =================================================================== --- mono/mono/metadata/marshal.c (revision 145149) +++ mono/mono/metadata/marshal.c (working copy) @@ -8591,7 +8591,7 @@ } gpointer -mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) +mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type, MonoMethod **wrapper_method) { MonoMethod *method; MonoMethodSignature *sig; @@ -8641,9 +8641,15 @@ mono_metadata_free_marshal_spec (mspecs [i]); g_free (mspecs); + *wrapper_method = method; return mono_compile_method (method); } + if (!(type & VTFIXUP_TYPE_CALL_MOST_DERIVED)) { + wrapper_method = NULL; + return mono_compile_method (method); + } + sig = mono_method_signature (method); mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED); @@ -8651,16 +8657,14 @@ for (i = 0; i < param_count; i++) mono_mb_emit_ldarg (mb, i); - if (type & VTFIXUP_TYPE_CALL_MOST_DERIVED) - mono_mb_emit_op (mb, CEE_CALLVIRT, method); - else - mono_mb_emit_op (mb, CEE_CALL, method); + mono_mb_emit_op (mb, CEE_CALLVIRT, method); mono_mb_emit_byte (mb, CEE_RET); mb->dynamic = 1; method = mono_mb_create_method (mb, sig, param_count); mono_mb_free (mb); + *wrapper_method = method; return mono_compile_method (method); } Index: mono/mono/metadata/marshal.h =================================================================== --- mono/mono/metadata/marshal.h (revision 145149) +++ mono/mono/metadata/marshal.h (working copy) @@ -199,7 +199,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject **this_loc) MONO_INTERNAL; gpointer -mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) MONO_INTERNAL; +mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type, MonoMethod **wrapper_method) MONO_INTERNAL; MonoMethod * mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions) MONO_INTERNAL; Index: mono/mono/mini/mini.c =================================================================== --- mono/mono/mini/mini.c (revision 145149) +++ mono/mono/mini/mini.c (working copy) @@ -5058,6 +5058,7 @@ mono_install_jump_trampoline (mono_create_jump_trampoline); mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline); mono_install_delegate_trampoline (mono_create_delegate_trampoline); + mono_install_vtfixup_trampoline (mono_create_vtfixup_trampoline); mono_install_create_domain_hook (mini_create_jit_domain_info); mono_install_free_domain_hook (mini_free_jit_domain_info); #endif Index: mono/mono/mini/mini.h =================================================================== --- mono/mono/mini/mini.h (revision 145149) +++ mono/mono/mini/mini.h (working copy) @@ -827,6 +827,7 @@ MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING, MONO_TRAMPOLINE_MONITOR_ENTER, MONO_TRAMPOLINE_MONITOR_EXIT, + MONO_TRAMPOLINE_VTFIXUP, #ifdef ENABLE_LLVM MONO_TRAMPOLINE_LLVM_VCALL, #endif @@ -1482,6 +1483,7 @@ gpointer mono_create_monitor_enter_trampoline (void) MONO_INTERNAL; gpointer mono_create_monitor_exit_trampoline (void) MONO_INTERNAL; gpointer mono_create_static_rgctx_trampoline (MonoMethod *m, gpointer addr) MONO_INTERNAL; +gpointer mono_create_vtfixup_trampoline (gpointer slot, MonoImage *image, guint32 token, guint16 type) MONO_INTERNAL; gpointer mono_create_llvm_vcall_trampoline (MonoMethod *method) MONO_INTERNAL; MonoVTable* mono_find_class_init_trampoline_by_addr (gconstpointer addr) MONO_INTERNAL; guint32 mono_find_rgctx_lazy_fetch_trampoline_by_addr (gconstpointer addr) MONO_INTERNAL; Index: mono/mono/mini/mini-trampolines.c =================================================================== --- mono/mono/mini/mini-trampolines.c (revision 145149) +++ mono/mono/mini/mini-trampolines.c (working copy) @@ -6,6 +6,8 @@ #include <mono/metadata/metadata-internals.h> #include <mono/metadata/marshal.h> #include <mono/metadata/tabledefs.h> +#include <mono/metadata/assembly.h> +#include <mono/metadata/cil-coff.h> #include <mono/utils/mono-counters.h> #ifdef HAVE_VALGRIND_MEMCHECK_H @@ -779,6 +781,61 @@ mono_monitor_exit (obj); } +static gpointer +mono_vtfixup_trampoline (gssize *regs, guint8 *code, guint8 *slot_info, guint8* tramp) +{ + gpointer tramp_addr; + gpointer slot, slot_addr; + MonoImage *image; + guint32 token; + guint16 type; + gpointer addr; + MonoMethod *wrapper_method; + MonoImageOpenStatus status; + + tramp_addr = *((gpointer*) (gpointer) slot_info); + slot_info += sizeof (gpointer); + slot = *((gpointer*) (gpointer) slot_info); + slot_info += sizeof (gpointer); + image = *((gpointer*) (gpointer) slot_info); + slot_info += sizeof (gpointer); + token = *((guint32*) (gpointer) slot_info); + slot_info += sizeof (guint32); + type = *((guint16*) (gpointer) slot_info); + + if (type & VTFIXUP_TYPE_64BIT) + slot_addr = (gpointer) *((volatile gint64*) (slot)); + else + slot_addr = (gpointer) *((volatile gint32*) (slot)); + + if (slot_addr != tramp_addr) + return slot_addr; + + if (!image->assembly) { + // FIXME: Throw exceptions when assembly cannot be loaded + // FIXME: Fix mono_assembly_load_from_full to allow loading mscorlib.dll + g_assert (mono_assembly_load_from_full (image, image->name, &status, FALSE)); + } + + addr = mono_marshal_get_vtfixup_ftnptr (image, token, type, &wrapper_method); + if (type & VTFIXUP_TYPE_64BIT) +#if SIZEOF_VOID_P == 8 + slot_addr = InterlockedCompareExchangePointer (slot, addr, tramp_addr); +#else + slot_addr = (gpointer) ves_icall_System_Threading_Interlocked_CompareExchange_Long ((gint64*) slot, (gint64) addr, (gint64) tramp_addr); +#endif + else + slot_addr = (gpointer) InterlockedCompareExchange ((gint32*) slot, (gint32) addr, (gint32) tramp_addr); + + if (slot_addr == tramp_addr) + return addr; + + if (wrapper_method) + mono_free_method (wrapper_method); + + return slot_addr; +} + #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE /** @@ -922,6 +979,8 @@ return mono_monitor_enter_trampoline; case MONO_TRAMPOLINE_MONITOR_EXIT: return mono_monitor_exit_trampoline; + case MONO_TRAMPOLINE_VTFIXUP: + return mono_vtfixup_trampoline; #ifdef ENABLE_LLVM case MONO_TRAMPOLINE_LLVM_VCALL: return mono_llvm_vcall_trampoline; @@ -956,6 +1015,7 @@ 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_VTFIXUP] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_VTFIXUP); #ifdef ENABLE_LLVM mono_trampoline_code [MONO_TRAMPOLINE_LLVM_VCALL] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_LLVM_VCALL); #endif @@ -1280,7 +1340,31 @@ #endif return code; } - + +gpointer +mono_create_vtfixup_trampoline (gpointer slot, MonoImage *image, guint32 token, guint16 type) +{ + gpointer tramp; + + MonoDomain *domain = mono_get_root_domain (); + guint8 *buf, *start; + + buf = start = mono_domain_code_reserve (domain, 3 * sizeof (gpointer) + sizeof (guint32) + sizeof (guint16)); + + buf += sizeof (gpointer); + *(gpointer*) (gpointer) buf = slot; + buf += sizeof (gpointer); + *(gpointer*) (gpointer) buf = image; + buf += sizeof (gpointer); + *(guint32*) (gpointer) buf = token; + buf += sizeof (guint32); + *(guint16*) (gpointer) buf = type; + + tramp = mono_create_specific_trampoline (start, MONO_TRAMPOLINE_VTFIXUP, domain, NULL); + *(gpointer*) (gpointer) start = tramp; + return tramp; +} + #ifdef ENABLE_LLVM /* * mono_create_llvm_vcall_trampoline:
_______________________________________________ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list