X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fimage.c;h=f054be8acca0621cc168f399aeefa6e1468d354a;hb=d6cdd9715eff6eeac53c9d0970a90e49b7c80edd;hp=dbd6595f922cf3e3eef6763c02451346a0ffdacf;hpb=fa90295c1a6c2ea05c3d15002614b0c5e3d7ee33;p=mono.git diff --git a/mono/metadata/image.c b/mono/metadata/image.c index dbd6595f922..f054be8acca 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -6,7 +6,8 @@ * Miguel de Icaza (miguel@ximian.com) * Paolo Molaro (lupus@ximian.com) * - * (C) 2001-2003 Ximian, Inc. http://www.ximian.com + * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) * */ #include @@ -17,18 +18,25 @@ #include #include "image.h" #include "cil-coff.h" -#include "rawbuffer.h" #include "mono-endian.h" #include "tabledefs.h" #include "tokentype.h" #include "metadata-internals.h" +#include "profiler-private.h" #include "loader.h" +#include "marshal.h" +#include "coree.h" #include -#include +#include #include +#include #include #include #include +#include +#include +#include +#include #include #include #ifdef HAVE_UNISTD_H @@ -45,13 +53,49 @@ static GHashTable *loaded_images_refonly_hash; static gboolean debug_assembly_unload = FALSE; -#define mono_images_lock() EnterCriticalSection (&images_mutex) -#define mono_images_unlock() LeaveCriticalSection (&images_mutex) +#define mono_images_lock() if (mutex_inited) EnterCriticalSection (&images_mutex) +#define mono_images_unlock() if (mutex_inited) LeaveCriticalSection (&images_mutex) +static gboolean mutex_inited; static CRITICAL_SECTION images_mutex; +typedef struct ImageUnloadHook ImageUnloadHook; +struct ImageUnloadHook { + ImageUnloadHook *next; + MonoImageUnloadFunc func; + gpointer user_data; +}; + +ImageUnloadHook *image_unload_hook = NULL; + +void +mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data) +{ + ImageUnloadHook *hook; + + g_return_if_fail (func != NULL); + + hook = g_new0 (ImageUnloadHook, 1); + hook->func = func; + hook->user_data = user_data; + hook->next = image_unload_hook; + image_unload_hook = hook; +} + +static void +mono_image_invoke_unload_hook (MonoImage *image) +{ + ImageUnloadHook *hook; + + for (hook = image_unload_hook; hook; hook = hook->next) { + hook->func (image, hook->user_data); + } +} + +/* returns offset relative to image->raw_data */ guint32 -mono_cli_rva_image_map (MonoCLIImageInfo *iinfo, guint32 addr) +mono_cli_rva_image_map (MonoImage *image, guint32 addr) { + MonoCLIImageInfo *iinfo = image->image_info; const int top = iinfo->cli_section_count; MonoSectionTable *tables = iinfo->cli_section_tables; int i; @@ -59,6 +103,10 @@ mono_cli_rva_image_map (MonoCLIImageInfo *iinfo, guint32 addr) for (i = 0; i < top; i++){ if ((addr >= tables->st_virtual_address) && (addr < tables->st_virtual_address + tables->st_raw_data_size)){ +#ifdef HOST_WIN32 + if (image->is_module_handle) + return addr; +#endif return addr - tables->st_virtual_address + tables->st_raw_data_ptr; } tables++; @@ -92,6 +140,10 @@ mono_image_rva_map (MonoImage *image, guint32 addr) if (!mono_image_ensure_section_idx (image, i)) return NULL; } +#ifdef HOST_WIN32 + if (image->is_module_handle) + return image->raw_data + addr; +#endif return (char*)iinfo->cli_sections [i] + (addr - tables->st_virtual_address); } @@ -113,7 +165,9 @@ mono_images_init (void) loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal); loaded_images_refonly_hash = g_hash_table_new (g_str_hash, g_str_equal); - debug_assembly_unload = getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL; + debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL; + + mutex_inited = TRUE; } /** @@ -128,6 +182,8 @@ mono_images_cleanup (void) g_hash_table_destroy (loaded_images_hash); g_hash_table_destroy (loaded_images_refonly_hash); + + mutex_inited = FALSE; } /** @@ -158,6 +214,11 @@ mono_image_ensure_section_idx (MonoImage *image, int section) if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len) return FALSE; +#ifdef HOST_WIN32 + if (image->is_module_handle) + iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address; + else +#endif /* FIXME: we ignore the writable flag since we don't patch the binary */ iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr; return TRUE; @@ -228,7 +289,7 @@ load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo) { guint32 offset; - offset = mono_cli_rva_image_map (iinfo, iinfo->cli_header.datadir.pe_cli_header.rva); + offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva); if (offset == INVALID_ADDRESS) return FALSE; @@ -296,7 +357,7 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) guint32 pad; char *ptr; - offset = mono_cli_rva_image_map (iinfo, iinfo->cli_cli_header.ch_metadata.rva); + offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva); if (offset == INVALID_ADDRESS) return FALSE; @@ -306,6 +367,7 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) return FALSE; image->raw_metadata = image->raw_data + offset; + /* 24.2.1: Metadata root starts here */ ptr = image->raw_metadata; if (strncmp (ptr, "BSJB", 4) == 0){ @@ -313,9 +375,9 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo) ptr += 4; image->md_version_major = read16 (ptr); - ptr += 4; + ptr += 2; image->md_version_minor = read16 (ptr); - ptr += 4; + ptr += 6; version_string_len = read32 (ptr); ptr += 4; @@ -441,10 +503,6 @@ mono_image_check_for_module_cctor (MonoImage *image) MonoTableInfo *t, *mt; t = &image->tables [MONO_TABLE_TYPEDEF]; mt = &image->tables [MONO_TABLE_METHOD]; - if (mono_get_runtime_info ()->framework_version [0] == '1') { - image->checked_module_cctor = TRUE; - return; - } if (image->dynamic) { /* FIXME: */ image->checked_module_cctor = TRUE; @@ -506,7 +564,8 @@ mono_image_load_module (MonoImage *image, int idx) GList *list_iter, *valid_modules = NULL; MonoImageOpenStatus status; - g_assert (idx <= image->module_count); + if ((image->module_count == 0) || (idx > image->module_count || idx <= 0)) + return NULL; if (image->modules_loaded [idx - 1]) return image->modules [idx - 1]; @@ -544,6 +603,10 @@ mono_image_load_module (MonoImage *image, int idx) if (image->modules [idx - 1]) { mono_image_addref (image->modules [idx - 1]); image->modules [idx - 1]->assembly = image->assembly; +#ifdef HOST_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); @@ -577,48 +640,21 @@ class_next_value (gpointer value) void mono_image_init (MonoImage *image) { - image->mempool = mono_mempool_new (); - image->method_cache = g_hash_table_new (NULL, NULL); + image->mempool = mono_mempool_new_size (512); mono_internal_hash_table_init (&image->class_cache, g_direct_hash, class_key_extract, class_next_value); image->field_cache = g_hash_table_new (NULL, NULL); - image->delegate_begin_invoke_cache = - g_hash_table_new ((GHashFunc)mono_signature_hash, - (GCompareFunc)mono_metadata_signature_equal); - image->delegate_end_invoke_cache = - g_hash_table_new ((GHashFunc)mono_signature_hash, - (GCompareFunc)mono_metadata_signature_equal); - image->delegate_invoke_cache = - g_hash_table_new ((GHashFunc)mono_signature_hash, - (GCompareFunc)mono_metadata_signature_equal); - image->runtime_invoke_cache = - g_hash_table_new ((GHashFunc)mono_signature_hash, - (GCompareFunc)mono_metadata_signature_equal); - - image->managed_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->native_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->remoting_invoke_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->cominterop_invoke_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->cominterop_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->synchronized_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->unbox_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - - image->ldfld_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->ldflda_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->ldfld_remote_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->stfld_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->stfld_remote_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->castclass_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->proxy_isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL); - image->typespec_cache = g_hash_table_new (NULL, NULL); image->memberref_signatures = g_hash_table_new (NULL, NULL); image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal); image->method_signatures = g_hash_table_new (NULL, NULL); + + image->property_hash = mono_property_hash_new (); + InitializeCriticalSection (&image->lock); + InitializeCriticalSection (&image->szarray_cache_lock); } #if G_BYTE_ORDER != G_LITTLE_ENDIAN @@ -641,6 +677,9 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset) { MonoDotNetHeader64 header64; +#ifdef HOST_WIN32 + if (!image->is_module_handle) +#endif if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len) return -1; @@ -759,26 +798,28 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset) SWAPPDE (header->datadir.pe_cli_header); SWAPPDE (header->datadir.pe_reserved); +#ifdef HOST_WIN32 + if (image->is_module_handle) + image->raw_data_len = header->nt.pe_image_size; +#endif + return offset; } -static MonoImage * -do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, - gboolean care_about_cli) +gboolean +mono_image_load_pe_data (MonoImage *image) { MonoCLIImageInfo *iinfo; MonoDotNetHeader *header; MonoMSDOSHeader msdos; gint32 offset = 0; - mono_image_init (image); - iinfo = image->image_info; header = &iinfo->cli_header; - - if (status) - *status = MONO_IMAGE_IMAGE_INVALID; +#ifdef HOST_WIN32 + if (!image->is_module_handle) +#endif if (offset + sizeof (msdos) > image->raw_data_len) goto invalid_image; memcpy (&msdos, image->raw_data + offset, sizeof (msdos)); @@ -823,55 +864,122 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, if (!load_section_tables (image, iinfo, offset)) goto invalid_image; - - if (care_about_cli == FALSE) { - goto done; - } - + + return TRUE; + +invalid_image: + return FALSE; +} + +gboolean +mono_image_load_cli_data (MonoImage *image) +{ + MonoCLIImageInfo *iinfo; + MonoDotNetHeader *header; + + iinfo = image->image_info; + header = &iinfo->cli_header; + /* Load the CLI header */ if (!load_cli_header (image, iinfo)) - goto invalid_image; + return FALSE; if (!load_metadata (image, iinfo)) - goto invalid_image; + return FALSE; + + return TRUE; +} +void +mono_image_load_names (MonoImage *image) +{ /* modules don't have an assembly table row */ - if (image->tables [MONO_TABLE_ASSEMBLY].rows) + if (image->tables [MONO_TABLE_ASSEMBLY].rows) { image->assembly_name = mono_metadata_string_heap (image, mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_NAME)); + } image->module_name = mono_metadata_string_heap (image, mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE], 0, MONO_MODULE_NAME)); +} + +static MonoImage * +do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, + gboolean care_about_cli, gboolean care_about_pecoff) +{ + MonoCLIImageInfo *iinfo; + MonoDotNetHeader *header; + GSList *errors = NULL; + + mono_profiler_module_event (image, MONO_PROFILE_START_LOAD); + + mono_image_init (image); + + iinfo = image->image_info; + header = &iinfo->cli_header; + + if (status) + *status = MONO_IMAGE_IMAGE_INVALID; + + if (care_about_pecoff == FALSE) + goto done; + + if (!mono_verifier_verify_pe_data (image, &errors)) + goto invalid_image; + + if (!mono_image_load_pe_data (image)) + goto invalid_image; + + if (care_about_cli == FALSE) { + goto done; + } + + if (!mono_verifier_verify_cli_data (image, &errors)) + goto invalid_image; + + if (!mono_image_load_cli_data (image)) + goto invalid_image; + + if (!mono_verifier_verify_table_data (image, &errors)) + goto invalid_image; + + mono_image_load_names (image); load_modules (image); done: + mono_profiler_module_loaded (image, MONO_PROFILE_OK); if (status) *status = MONO_IMAGE_OK; return image; invalid_image: + if (errors) { + MonoVerifyInfo *info = errors->data; + g_warning ("Could not load image %s due to %s", image->name, info->message); + mono_free_verify_list (errors); + } + mono_profiler_module_loaded (image, MONO_PROFILE_FAILED); mono_image_close (image); - return NULL; + return NULL; } static MonoImage * do_mono_image_open (const char *fname, MonoImageOpenStatus *status, - gboolean care_about_cli, gboolean refonly) + gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly) { MonoCLIImageInfo *iinfo; MonoImage *image; - FILE *filed; - struct stat stat_buf; + MonoFileMap *filed; - if ((filed = fopen (fname, "rb")) == NULL){ + if ((filed = mono_file_map_open (fname)) == NULL){ if (IS_PORTABILITY_SET) { - gchar *ffname = mono_portability_find_file (fname, FALSE); + gchar *ffname = mono_portability_find_file (fname, TRUE); if (ffname) { - filed = fopen (ffname, "rb"); + filed = mono_file_map_open (ffname); g_free (ffname); } } @@ -883,25 +991,27 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status, } } - if (fstat (fileno (filed), &stat_buf)) { - fclose (filed); + image = g_new0 (MonoImage, 1); + image->raw_buffer_used = TRUE; + image->raw_data_len = mono_file_map_size (filed); + image->raw_data = mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle); + if (!image->raw_data) { + mono_file_map_close (filed); + g_free (image); if (status) - *status = MONO_IMAGE_ERROR_ERRNO; + *status = MONO_IMAGE_IMAGE_INVALID; return NULL; } - image = g_new0 (MonoImage, 1); - image->raw_buffer_used = TRUE; - image->raw_data_len = stat_buf.st_size; - image->raw_data = mono_raw_buffer_load (fileno (filed), FALSE, 0, stat_buf.st_size); iinfo = g_new0 (MonoCLIImageInfo, 1); image->image_info = iinfo; image->name = mono_path_resolve_symlinks (fname); image->ref_only = refonly; image->ref_count = 1; + /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */ + image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image); - fclose (filed); - - return do_mono_image_load (image, status, care_about_cli); + mono_file_map_close (filed); + return do_mono_image_load (image, status, care_about_cli, care_about_pecoff); } MonoImage * @@ -993,7 +1103,7 @@ register_image (MonoImage *image) } MonoImage * -mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly) +mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name) { MonoCLIImageInfo *iinfo; MonoImage *image; @@ -1019,24 +1129,55 @@ mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy image->raw_data = datac; image->raw_data_len = data_len; image->raw_data_allocated = need_copy; - image->name = g_strdup_printf ("data-%p", datac); + image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name); iinfo = g_new0 (MonoCLIImageInfo, 1); image->image_info = iinfo; image->ref_only = refonly; - image = do_mono_image_load (image, status, TRUE); + image = do_mono_image_load (image, status, TRUE, TRUE); if (image == NULL) return NULL; return register_image (image); } +MonoImage * +mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly) +{ + return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL); +} + MonoImage * mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status) { return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE); } +#ifdef HOST_WIN32 +/* fname is not duplicated. */ +MonoImage* +mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status) +{ + MonoImage* image; + MonoCLIImageInfo* iinfo; + + image = g_new0 (MonoImage, 1); + image->raw_data = (char*) module_handle; + image->is_module_handle = TRUE; + iinfo = g_new0 (MonoCLIImageInfo, 1); + image->image_info = iinfo; + image->name = fname; + image->ref_count = has_entry_point ? 0 : 1; + image->has_entry_point = has_entry_point; + + image = do_mono_image_load (image, status, TRUE, TRUE); + if (image == NULL) + return NULL; + + return register_image (image); +} +#endif + MonoImage * mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly) { @@ -1046,6 +1187,72 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r g_return_val_if_fail (fname != NULL, NULL); +#ifdef HOST_WIN32 + /* Load modules using LoadLibrary. */ + if (!refonly && coree_module_handle) { + HMODULE module_handle; + guint16 *fname_utf16; + DWORD last_error; + + absfname = mono_path_resolve_symlinks (fname); + fname_utf16 = NULL; + + /* There is little overhead because the OS loader lock is held by LoadLibrary. */ + mono_images_lock (); + image = g_hash_table_lookup (loaded_images_hash, absfname); + if (image) { + g_assert (image->is_module_handle); + if (image->has_entry_point && image->ref_count == 0) { + /* Increment reference count on images loaded outside of the runtime. */ + fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL); + /* The image is already loaded because _CorDllMain removes images from the hash. */ + module_handle = LoadLibrary (fname_utf16); + g_assert (module_handle == (HMODULE) image->raw_data); + } + mono_image_addref (image); + mono_images_unlock (); + if (fname_utf16) + g_free (fname_utf16); + g_free (absfname); + return image; + } + + fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL); + module_handle = MonoLoadImage (fname_utf16); + if (status && module_handle == NULL) + last_error = GetLastError (); + + /* mono_image_open_from_module_handle is called by _CorDllMain. */ + image = g_hash_table_lookup (loaded_images_hash, absfname); + if (image) + mono_image_addref (image); + mono_images_unlock (); + + g_free (fname_utf16); + + if (module_handle == NULL) { + g_assert (!image); + g_free (absfname); + if (status) { + if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT) + *status = MONO_IMAGE_IMAGE_INVALID; + else + *status = MONO_IMAGE_ERROR_ERRNO; + } + return NULL; + } + + if (image) { + g_assert (image->is_module_handle); + g_assert (image->has_entry_point); + g_free (absfname); + return image; + } + + return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status); + } +#endif + absfname = mono_path_canonicalize (fname); /* @@ -1066,7 +1273,7 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r } mono_images_unlock (); - image = do_mono_image_open (fname, status, TRUE, refonly); + image = do_mono_image_open (fname, status, TRUE, TRUE, refonly); if (image == NULL) return NULL; @@ -1105,7 +1312,75 @@ mono_pe_file_open (const char *fname, MonoImageOpenStatus *status) { g_return_val_if_fail (fname != NULL, NULL); - return(do_mono_image_open (fname, status, FALSE, FALSE)); + return(do_mono_image_open (fname, status, FALSE, TRUE, FALSE)); +} + +/** + * mono_image_open_raw + * @fname: filename that points to the module we want to open + * @status: An error condition is returned in this field + * + * Returns an image without loading neither pe or cli data. + * + * Use mono_image_load_pe_data and mono_image_load_cli_data to load them. + */ +MonoImage * +mono_image_open_raw (const char *fname, MonoImageOpenStatus *status) +{ + g_return_val_if_fail (fname != NULL, NULL); + + return(do_mono_image_open (fname, status, FALSE, FALSE, FALSE)); +} + +void +mono_image_fixup_vtable (MonoImage *image) +{ +#ifdef HOST_WIN32 + MonoCLIImageInfo *iinfo; + MonoPEDirEntry *de; + MonoVTableFixup *vtfixup; + int count; + gpointer slot; + guint16 slot_type; + int slot_count; + + g_assert (image->is_module_handle); + + iinfo = image->image_info; + de = &iinfo->cli_cli_header.ch_vtable_fixups; + if (!de->rva || !de->size) + return; + vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva); + if (!vtfixup) + return; + + count = de->size / sizeof (MonoVTableFixup); + while (count--) { + if (!vtfixup->rva || !vtfixup->count) + continue; + + slot = mono_image_rva_map (image, vtfixup->rva); + g_assert (slot); + slot_type = vtfixup->type; + slot_count = vtfixup->count; + if (slot_type & VTFIXUP_TYPE_32BIT) + while (slot_count--) { + *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type); + slot = ((guint32*) slot) + 1; + } + else if (slot_type & VTFIXUP_TYPE_64BIT) + while (slot_count--) { + *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type); + slot = ((guint32*) slot) + 1; + } + else + g_assert_not_reached(); + + vtfixup++; + } +#else + g_assert_not_reached(); +#endif } static void @@ -1122,12 +1397,6 @@ free_mr_signatures (gpointer key, gpointer val, gpointer user_data) } */ -static void -free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data) -{ - g_free (key); -} - static void free_remoting_wrappers (gpointer key, gpointer val, gpointer user_data) { @@ -1164,64 +1433,109 @@ mono_dynamic_stream_reset (MonoDynamicStream* stream) } } -/** - * mono_image_close: - * @image: The image file we wish to close - * - * Closes an image file, deallocates all memory consumed and - * unmaps all possible sections of the file +static inline void +free_hash (GHashTable *hash) +{ + if (hash) + g_hash_table_destroy (hash); +} + +/* + * Returns whether mono_image_close_finish() must be called as well. + * We must unload images in two steps because clearing the domain in + * SGen requires the class metadata to be intact, but we need to free + * the mono_g_hash_tables in case a collection occurs during domain + * unloading and the roots would trip up the GC. */ -void -mono_image_close (MonoImage *image) +gboolean +mono_image_close_except_pools (MonoImage *image) { MonoImage *image2; GHashTable *loaded_images; int i; + GSList *free_list; - g_return_if_fail (image != NULL); + g_return_val_if_fail (image != NULL, FALSE); - if (InterlockedDecrement (&image->ref_count) > 0) - return; + /* + * Atomically decrement the refcount and remove ourselves from the hash tables, so + * register_image () can't grab an image which is being closed. + */ + mono_images_lock (); + + if (InterlockedDecrement (&image->ref_count) > 0) { + mono_images_unlock (); + return FALSE; + } + + loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash; + image2 = g_hash_table_lookup (loaded_images, image->name); + if (image == image2) { + /* This is not true if we are called from mono_image_open () */ + g_hash_table_remove (loaded_images, image->name); + } + if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image)) + g_hash_table_remove (loaded_images, (char *) image->assembly_name); + + mono_images_unlock (); + +#ifdef HOST_WIN32 + if (image->is_module_handle && image->has_entry_point) { + mono_images_lock (); + if (image->ref_count == 0) { + /* Image will be closed by _CorDllMain. */ + FreeLibrary ((HMODULE) image->raw_data); + mono_images_unlock (); + return FALSE; + } + mono_images_unlock (); + } +#endif + + mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD); mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image); - mono_metadata_clean_for_image (image); + mono_image_invoke_unload_hook (image); + + free_list = mono_metadata_clean_for_image (image); /* * The caches inside a MonoImage might refer to metadata which is stored in referenced * assemblies, so we can't release these references in mono_assembly_close () since the * MonoImage might outlive its associated MonoAssembly. */ - if (image->references) { + if (image->references && !image->dynamic) { + MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF]; int i; - for (i = 0; image->references [i]; i++) { - if (image->references [i]) - mono_assembly_close (image->references [i]); + for (i = 0; i < t->rows; i++) { + if (image->references [i]) { + if (!mono_assembly_close_except_image_pools (image->references [i])) + image->references [i] = NULL; + } + } + } else { + if (image->references) { + g_free (image->references); + image->references = NULL; } - - g_free (image->references); - image->references = NULL; } +#ifdef HOST_WIN32 mono_images_lock (); - loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash; - image2 = g_hash_table_lookup (loaded_images, image->name); - if (image == image2) { - /* This is not true if we are called from mono_image_open () */ - g_hash_table_remove (loaded_images, image->name); - } - if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image)) - g_hash_table_remove (loaded_images, (char *) image->assembly_name); - + if (image->is_module_handle && !image->has_entry_point) + FreeLibrary ((HMODULE) image->raw_data); mono_images_unlock (); +#endif if (image->raw_buffer_used) { if (image->raw_data != NULL) - mono_raw_buffer_free (image->raw_data); + mono_file_unmap (image->raw_data, image->raw_data_handle); } if (image->raw_data_allocated) { + /* FIXME: do we need this? (image is disposed anyway) */ /* image->raw_metadata and cli_sections might lie inside image->raw_data */ MonoCLIImageInfo *ii = image->image_info; @@ -1246,40 +1560,49 @@ mono_image_close (MonoImage *image) g_free (image->files); } - g_hash_table_destroy (image->method_cache); + if (image->method_cache) + g_hash_table_destroy (image->method_cache); + if (image->methodref_cache) + g_hash_table_destroy (image->methodref_cache); mono_internal_hash_table_destroy (&image->class_cache); g_hash_table_destroy (image->field_cache); if (image->array_cache) { g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL); g_hash_table_destroy (image->array_cache); } + if (image->szarray_cache) + g_hash_table_destroy (image->szarray_cache); if (image->ptr_cache) g_hash_table_destroy (image->ptr_cache); if (image->name_cache) { g_hash_table_foreach (image->name_cache, free_hash_table, NULL); g_hash_table_destroy (image->name_cache); } - g_hash_table_destroy (image->native_wrapper_cache); - g_hash_table_destroy (image->managed_wrapper_cache); - g_hash_table_destroy (image->delegate_begin_invoke_cache); - g_hash_table_destroy (image->delegate_end_invoke_cache); - g_hash_table_destroy (image->delegate_invoke_cache); - g_hash_table_foreach (image->remoting_invoke_cache, free_remoting_wrappers, NULL); - g_hash_table_destroy (image->remoting_invoke_cache); - g_hash_table_destroy (image->runtime_invoke_cache); - g_hash_table_destroy (image->synchronized_cache); - g_hash_table_destroy (image->unbox_wrapper_cache); - g_hash_table_destroy (image->cominterop_invoke_cache); - g_hash_table_destroy (image->cominterop_wrapper_cache); - g_hash_table_destroy (image->typespec_cache); - g_hash_table_destroy (image->ldfld_wrapper_cache); - g_hash_table_destroy (image->ldflda_wrapper_cache); - g_hash_table_destroy (image->ldfld_remote_wrapper_cache); - g_hash_table_destroy (image->stfld_wrapper_cache); - g_hash_table_destroy (image->stfld_remote_wrapper_cache); - g_hash_table_destroy (image->isinst_cache); - g_hash_table_destroy (image->castclass_cache); - g_hash_table_destroy (image->proxy_isinst_cache); + + free_hash (image->native_wrapper_cache); + free_hash (image->managed_wrapper_cache); + free_hash (image->delegate_begin_invoke_cache); + free_hash (image->delegate_end_invoke_cache); + free_hash (image->delegate_invoke_cache); + free_hash (image->delegate_abstract_invoke_cache); + if (image->remoting_invoke_cache) + g_hash_table_foreach (image->remoting_invoke_cache, free_remoting_wrappers, NULL); + free_hash (image->remoting_invoke_cache); + free_hash (image->runtime_invoke_cache); + free_hash (image->runtime_invoke_direct_cache); + free_hash (image->runtime_invoke_vcall_cache); + free_hash (image->synchronized_cache); + free_hash (image->unbox_wrapper_cache); + free_hash (image->cominterop_invoke_cache); + free_hash (image->cominterop_wrapper_cache); + free_hash (image->typespec_cache); + free_hash (image->ldfld_wrapper_cache); + free_hash (image->ldflda_wrapper_cache); + free_hash (image->stfld_wrapper_cache); + free_hash (image->isinst_cache); + free_hash (image->castclass_cache); + free_hash (image->proxy_isinst_cache); + free_hash (image->thunk_invoke_cache); /* The ownership of signatures is not well defined */ //g_hash_table_foreach (image->memberref_signatures, free_mr_signatures, NULL); @@ -1288,6 +1611,15 @@ mono_image_close (MonoImage *image) g_hash_table_destroy (image->helper_signatures); g_hash_table_destroy (image->method_signatures); + if (image->rgctx_template_hash) + g_hash_table_destroy (image->rgctx_template_hash); + + if (image->property_hash) + mono_property_hash_destroy (image->property_hash); + + g_slist_free (image->reflection_info_unregister_classes); + image->reflection_info_unregister_classes = free_list; + if (image->interface_bitset) { mono_unload_interface_ids (image->interface_bitset); mono_bitset_free (image->interface_bitset); @@ -1303,16 +1635,62 @@ mono_image_close (MonoImage *image) } for (i = 0; i < image->module_count; ++i) { - if (image->modules [i]) - mono_image_close (image->modules [i]); + if (image->modules [i]) { + if (!mono_image_close_except_pools (image->modules [i])) + image->modules [i] = NULL; + } } - if (image->modules) - g_free (image->modules); if (image->modules_loaded) g_free (image->modules_loaded); - if (image->references) - g_free (image->references); + + DeleteCriticalSection (&image->szarray_cache_lock); + DeleteCriticalSection (&image->lock); + /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/ + if (image->dynamic) { + /* Dynamic images are GC_MALLOCed */ + g_free ((char*)image->module_name); + mono_dynamic_image_free ((MonoDynamicImage*)image); + } + + mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD); + + return TRUE; +} + +void +mono_image_close_finish (MonoImage *image) +{ + int i; + GSList *l; + + for (l = image->reflection_info_unregister_classes; l; l = l->next) + g_free (l->data); + g_slist_free (image->reflection_info_unregister_classes); + image->reflection_info_unregister_classes = NULL; + + if (image->references && !image->dynamic) { + MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF]; + int i; + + for (i = 0; i < t->rows; i++) { + if (image->references [i]) + mono_assembly_close_finish (image->references [i]); + } + + g_free (image->references); + image->references = NULL; + } + + for (i = 0; i < image->module_count; ++i) { + if (image->modules [i]) + mono_image_close_finish (image->modules [i]); + } + if (image->modules) + g_free (image->modules); + + mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool); + if (!image->dynamic) { if (debug_assembly_unload) mono_mempool_invalidate (image->mempool); @@ -1321,50 +1699,27 @@ mono_image_close (MonoImage *image) g_free (image); } } else { - /* Dynamic images are GC_MALLOCed */ - struct _MonoDynamicImage *di = (struct _MonoDynamicImage*)image; - int i; - g_free ((char*)image->module_name); - if (di->typespec) - g_hash_table_destroy (di->typespec); - if (di->typeref) - g_hash_table_destroy (di->typeref); - if (di->handleref) - g_hash_table_destroy (di->handleref); - if (di->tokens) - mono_g_hash_table_destroy (di->tokens); - if (di->blob_cache) { - g_hash_table_foreach (di->blob_cache, free_blob_cache_entry, NULL); - g_hash_table_destroy (di->blob_cache); - } - g_list_free (di->array_methods); - if (di->gen_params) - g_ptr_array_free (di->gen_params, TRUE); - if (di->token_fixups) - mono_g_hash_table_destroy (di->token_fixups); - if (di->method_to_table_idx) - g_hash_table_destroy (di->method_to_table_idx); - if (di->field_to_table_idx) - g_hash_table_destroy (di->field_to_table_idx); - if (di->method_aux_hash) - g_hash_table_destroy (di->method_aux_hash); - g_free (di->strong_name); - g_free (di->win32_res); - /*g_print ("string heap destroy for image %p\n", di);*/ - mono_dynamic_stream_reset (&di->sheap); - mono_dynamic_stream_reset (&di->code); - mono_dynamic_stream_reset (&di->resources); - mono_dynamic_stream_reset (&di->us); - mono_dynamic_stream_reset (&di->blob); - mono_dynamic_stream_reset (&di->tstream); - mono_dynamic_stream_reset (&di->guid); - for (i = 0; i < MONO_TABLE_NUM; ++i) { - g_free (di->tables [i].values); - } - mono_mempool_destroy (image->mempool); + if (debug_assembly_unload) + mono_mempool_invalidate (image->mempool); + else + mono_mempool_destroy (image->mempool); } } +/** + * mono_image_close: + * @image: The image file we wish to close + * + * Closes an image file, deallocates all memory consumed and + * unmaps all possible sections of the file + */ +void +mono_image_close (MonoImage *image) +{ + if (mono_image_close_except_pools (image)) + mono_image_close_finish (image); +} + /** * mono_image_strerror: * @status: an code indicating the result from a recent operation @@ -1406,23 +1761,18 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id, * Level 2 holds a directory entry for each language pointing to * the actual data. */ - name_offset = GUINT32_FROM_LE (entry->name_offset) & 0x7fffffff; - dir_offset = GUINT32_FROM_LE (entry->dir_offset) & 0x7fffffff; + is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry); + name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry); -#if G_BYTE_ORDER != G_LITTLE_ENDIAN - is_string = (GUINT32_FROM_LE (entry->name_offset) & 0x80000000) != 0; - is_dir = (GUINT32_FROM_LE (entry->dir_offset) & 0x80000000) != 0; -#else - is_string = entry->name_is_string; - is_dir = entry->is_dir; -#endif + is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry); + dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry); if(level==0) { - if((is_string==FALSE && name_offset!=res_id) || - (is_string==TRUE)) { - return(NULL); - } + if (is_string) + return NULL; } else if (level==1) { + if (res_id != name_offset) + return NULL; #if 0 if(name!=NULL && is_string==TRUE && name!=lookup (name_offset)) { @@ -1430,12 +1780,8 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id, } #endif } else if (level==2) { - if ((is_string == FALSE && - name_offset != lang_id && - lang_id != 0) || - (is_string == TRUE)) { - return(NULL); - } + if (is_string == TRUE || (is_string == FALSE && lang_id != 0 && name_offset != lang_id)) + return NULL; } else { g_assert_not_reached (); } @@ -1502,6 +1848,8 @@ mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, g return(NULL); } + mono_image_ensure_section_idx (image, MONO_SECTION_RSRC); + info=image->image_info; if(info==NULL) { return(NULL); @@ -1628,6 +1976,10 @@ mono_image_load_file_for_image (MonoImage *image, int fileidx) } image->files [fileidx - 1] = res; +#ifdef HOST_WIN32 + if (res->is_module_handle) + mono_image_fixup_vtable (res); +#endif } mono_loader_unlock (); g_free (name); @@ -1679,25 +2031,14 @@ mono_image_strong_name_position (MonoImage *image, guint32 *size) { MonoCLIImageInfo *iinfo = image->image_info; MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name; - const int top = iinfo->cli_section_count; - MonoSectionTable *tables = iinfo->cli_section_tables; - int i; - guint32 addr = de->rva; - + guint32 pos; + if (size) *size = de->size; if (!de->size || !de->rva) return 0; - for (i = 0; i < top; i++){ - if ((addr >= tables->st_virtual_address) && - (addr < tables->st_virtual_address + tables->st_raw_data_size)){ - return tables->st_raw_data_ptr + - (addr - tables->st_virtual_address); - } - tables++; - } - - return 0; + pos = mono_cli_rva_image_map (image, de->rva); + return pos == INVALID_ADDRESS ? 0 : pos; } /** @@ -1718,6 +2059,12 @@ mono_image_get_public_key (MonoImage *image, guint32 *size) { const char *pubkey; guint32 len, tok; + + if (image->dynamic) { + if (size) + *size = ((MonoDynamicImage*)image)->public_key_len; + return (char*)((MonoDynamicImage*)image)->public_key; + } if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1) return NULL; tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY); @@ -1832,3 +2179,134 @@ mono_image_has_authenticode_entry (MonoImage *image) // the Authenticode "pre" (non ASN.1) header is 8 bytes long return ((de->rva != 0) && (de->size > 8)); } + +gpointer +mono_image_alloc (MonoImage *image, guint size) +{ + gpointer res; + + mono_perfcounters->loader_bytes += size; + mono_image_lock (image); + res = mono_mempool_alloc (image->mempool, size); + mono_image_unlock (image); + + return res; +} + +gpointer +mono_image_alloc0 (MonoImage *image, guint size) +{ + gpointer res; + + mono_perfcounters->loader_bytes += size; + mono_image_lock (image); + res = mono_mempool_alloc0 (image->mempool, size); + mono_image_unlock (image); + + return res; +} + +char* +mono_image_strdup (MonoImage *image, const char *s) +{ + char *res; + + mono_perfcounters->loader_bytes += strlen (s); + mono_image_lock (image); + res = mono_mempool_strdup (image->mempool, s); + mono_image_unlock (image); + + return res; +} + +GList* +g_list_prepend_image (MonoImage *image, GList *list, gpointer data) +{ + GList *new_list; + + new_list = mono_image_alloc (image, sizeof (GList)); + new_list->data = data; + new_list->prev = list ? list->prev : NULL; + new_list->next = list; + + if (new_list->prev) + new_list->prev->next = new_list; + if (list) + list->prev = new_list; + + return new_list; +} + +GSList* +g_slist_append_image (MonoImage *image, GSList *list, gpointer data) +{ + GSList *new_list; + + new_list = mono_image_alloc (image, sizeof (GSList)); + new_list->data = data; + new_list->next = NULL; + + return g_slist_concat (list, new_list); +} + +void +mono_image_lock (MonoImage *image) +{ + mono_locks_acquire (&image->lock, ImageDataLock); +} + +void +mono_image_unlock (MonoImage *image) +{ + mono_locks_release (&image->lock, ImageDataLock); +} + + +/** + * mono_image_property_lookup: + * + * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod. + * + * LOCKING: Takes the image lock + */ +gpointer +mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property) +{ + gpointer res; + + mono_image_lock (image); + res = mono_property_hash_lookup (image->property_hash, subject, property); + mono_image_unlock (image); + + return res; +} + +/** + * mono_image_property_insert: + * + * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod. + * + * LOCKING: Takes the image lock + */ +void +mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value) +{ + mono_image_lock (image); + mono_property_hash_insert (image->property_hash, subject, property, value); + mono_image_unlock (image); +} + +/** + * mono_image_property_remove: + * + * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod. + * + * LOCKING: Takes the image lock + */ +void +mono_image_property_remove (MonoImage *image, gpointer subject) +{ + mono_image_lock (image); + mono_property_hash_remove_object (image->property_hash, subject); + mono_image_unlock (image); +}