Merge pull request #819 from brendanzagaeski/patch-1
[mono.git] / mono / metadata / image.c
index 37928bbd1fff1a7980efa023da7ea74e6933c93a..dcb5c399a62edab973fd29eba6650b7071ab56ba 100644 (file)
 #include "marshal.h"
 #include "coree.h"
 #include <mono/io-layer/io-layer.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-path.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/mono-io-portability.h>
+#include <mono/utils/atomic.h>
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/object-internals.h>
+#include <mono/metadata/security-core-clr.h>
+#include <mono/metadata/verify-internals.h>
+#include <mono/metadata/verify.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #ifdef HAVE_UNISTD_H
@@ -50,10 +54,62 @@ 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 {
+       MonoImageUnloadFunc func;
+       gpointer user_data;
+};
+
+GSList *image_unload_hooks;
+
+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;
+       image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
+}
+
+void
+mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
+{
+       GSList *l;
+       ImageUnloadHook *hook;
+
+       for (l = image_unload_hooks; l; l = l->next) {
+               hook = l->data;
+
+               if (hook->func == func && hook->user_data == user_data) {
+                       g_free (hook);
+                       image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
+                       break;
+               }
+       }
+}
+
+static void
+mono_image_invoke_unload_hook (MonoImage *image)
+{
+       GSList *l;
+       ImageUnloadHook *hook;
+
+       for (l = image_unload_hooks; l; l = l->next) {
+               hook = l->data;
+
+               hook->func (image, hook->user_data);
+       }
+}
+
 /* returns offset relative to image->raw_data */
 guint32
 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
@@ -66,7 +122,7 @@ mono_cli_rva_image_map (MonoImage *image, 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 PLATFORM_WIN32
+#ifdef HOST_WIN32
                        if (image->is_module_handle)
                                return addr;
 #endif
@@ -95,7 +151,16 @@ mono_image_rva_map (MonoImage *image, guint32 addr)
        const int top = iinfo->cli_section_count;
        MonoSectionTable *tables = iinfo->cli_section_tables;
        int i;
-       
+
+#ifdef HOST_WIN32
+       if (image->is_module_handle) {
+               if (addr && addr < image->raw_data_len)
+                       return image->raw_data + addr;
+               else
+                       return NULL;
+       }
+#endif
+
        for (i = 0; i < top; i++){
                if ((addr >= tables->st_virtual_address) &&
                    (addr < tables->st_virtual_address + tables->st_raw_data_size)){
@@ -103,10 +168,6 @@ mono_image_rva_map (MonoImage *image, guint32 addr)
                                if (!mono_image_ensure_section_idx (image, i))
                                        return NULL;
                        }
-#ifdef PLATFORM_WIN32
-                       if (image->is_module_handle)
-                               return image->raw_data + addr;
-#endif
                        return (char*)iinfo->cli_sections [i] +
                                (addr - tables->st_virtual_address);
                }
@@ -128,7 +189,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;
 }
 
 /**
@@ -139,10 +202,19 @@ mono_images_init (void)
 void
 mono_images_cleanup (void)
 {
+       GHashTableIter iter;
+       MonoImage *image;
+
        DeleteCriticalSection (&images_mutex);
 
+       g_hash_table_iter_init (&iter, loaded_images_hash);
+       while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
+
        g_hash_table_destroy (loaded_images_hash);
        g_hash_table_destroy (loaded_images_refonly_hash);
+
+       mutex_inited = FALSE;
 }
 
 /**
@@ -173,7 +245,7 @@ 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 PLATFORM_WIN32
+#ifdef HOST_WIN32
        if (image->is_module_handle)
                iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
        else
@@ -326,6 +398,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){
@@ -333,9 +406,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;
@@ -461,10 +534,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_framework_version () == 1) {
-               image->checked_module_cctor = TRUE;
-               return;
-       }
        if (image->dynamic) {
                /* FIXME: */
                image->checked_module_cctor = TRUE;
@@ -526,7 +595,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];
 
@@ -564,7 +634,7 @@ 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 PLATFORM_WIN32
+#ifdef HOST_WIN32
                                if (image->modules [idx - 1]->is_module_handle)
                                        mono_image_fixup_vtable (image->modules [idx - 1]);
 #endif
@@ -615,6 +685,7 @@ mono_image_init (MonoImage *image)
 
        image->property_hash = mono_property_hash_new ();
        InitializeCriticalSection (&image->lock);
+       InitializeCriticalSection (&image->szarray_cache_lock);
 }
 
 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
@@ -637,7 +708,7 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
 {
        MonoDotNetHeader64 header64;
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        if (!image->is_module_handle)
 #endif
        if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
@@ -758,7 +829,7 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
        SWAPPDE (header->datadir.pe_cli_header);
        SWAPPDE (header->datadir.pe_reserved);
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        if (image->is_module_handle)
                image->raw_data_len = header->nt.pe_image_size;
 #endif
@@ -766,26 +837,18 @@ do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
        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_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;
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        if (!image->is_module_handle)
 #endif
        if (offset + sizeof (msdos) > image->raw_data_len)
@@ -832,18 +895,35 @@ 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) {
                image->assembly_name = mono_metadata_string_heap (image, 
@@ -854,6 +934,49 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
        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);
 
@@ -865,14 +988,19 @@ done:
        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;
@@ -898,6 +1026,12 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
        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 defined(HAVE_MMAP) && !defined (HOST_WIN32)
+       if (!image->raw_data) {
+               image->fileio_used = TRUE;
+               image->raw_data = mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
+       }
+#endif
        if (!image->raw_data) {
                mono_file_map_close (filed);
                g_free (image);
@@ -910,9 +1044,11 @@ do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
        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);
 
        mono_file_map_close (filed);
-       return do_mono_image_load (image, status, care_about_cli);
+       return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
 }
 
 MonoImage *
@@ -1004,7 +1140,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;
@@ -1030,25 +1166,31 @@ 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 PLATFORM_WIN32
+#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)
@@ -1065,7 +1207,7 @@ mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean
        image->ref_count = has_entry_point ? 0 : 1;
        image->has_entry_point = has_entry_point;
 
-       image = do_mono_image_load (image, status, TRUE);
+       image = do_mono_image_load (image, status, TRUE, TRUE);
        if (image == NULL)
                return NULL;
 
@@ -1082,7 +1224,7 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r
        
        g_return_val_if_fail (fname != NULL, NULL);
        
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        /* Load modules using LoadLibrary. */
        if (!refonly && coree_module_handle) {
                HMODULE module_handle;
@@ -1131,8 +1273,12 @@ mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean r
                        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;
+                               else {
+                                       if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
+                                               errno = ENOENT;
+                                       else
+                                               errno = 0;
+                               }
                        }
                        return NULL;
                }
@@ -1168,7 +1314,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;
 
@@ -1207,13 +1353,30 @@ 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 PLATFORM_WIN32
+#ifdef HOST_WIN32
        MonoCLIImageInfo *iinfo;
        MonoPEDirEntry *de;
        MonoVTableFixup *vtfixup;
@@ -1244,12 +1407,12 @@ mono_image_fixup_vtable (MonoImage *image)
                if (slot_type & VTFIXUP_TYPE_32BIT)
                        while (slot_count--) {
                                *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
-                               ((guint32*) slot)++;
+                               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);
-                               ((guint64*) slot)++;
+                               slot = ((guint32*) slot) + 1;
                        }
                else
                        g_assert_not_reached();
@@ -1275,12 +1438,6 @@ free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
 }
 */
 
-static void
-free_remoting_wrappers (gpointer key, gpointer val, gpointer user_data)
-{
-       g_free (val);
-}
-
 static void
 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
 {
@@ -1318,33 +1475,52 @@ free_hash (GHashTable *hash)
                g_hash_table_destroy (hash);
 }
 
-/**
- * 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
+/*
+ * 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;
 
-       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 ();
 
-#ifdef PLATFORM_WIN32
+       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;
+                       return FALSE;
                }
                mono_images_unlock ();
        }
@@ -1354,6 +1530,8 @@ mono_image_close (MonoImage *image)
 
        mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
 
+       mono_image_invoke_unload_hook (image);
+
        mono_metadata_clean_for_image (image);
 
        /*
@@ -1362,38 +1540,35 @@ mono_image_close (MonoImage *image)
         * MonoImage might outlive its associated MonoAssembly.
         */
        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 (image->references [i]);
+               for (i = 0; i < image->nreferences; i++) {
+                       if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
+                               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);     
-
-#ifdef PLATFORM_WIN32
        if (image->is_module_handle && !image->has_entry_point)
                FreeLibrary ((HMODULE) image->raw_data);
-#endif
-
        mono_images_unlock ();
+#endif
 
        if (image->raw_buffer_used) {
-               if (image->raw_data != NULL)
-                       mono_file_unmap (image->raw_data, image->raw_data_handle);
+               if (image->raw_data != NULL) {
+#ifndef HOST_WIN32
+                       if (image->fileio_used)
+                               mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
+                       else
+#endif
+                               mono_file_unmap (image->raw_data, image->raw_data_handle);
+               }
        }
        
        if (image->raw_data_allocated) {
@@ -1423,7 +1598,7 @@ mono_image_close (MonoImage *image)
        }
 
        if (image->method_cache)
-               mono_value_hash_table_destroy (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);
@@ -1432,6 +1607,8 @@ mono_image_close (MonoImage *image)
                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) {
@@ -1445,11 +1622,16 @@ mono_image_close (MonoImage *image)
        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->delegate_bound_static_invoke_cache);
+       free_hash (image->delegate_invoke_generic_cache);
+       free_hash (image->delegate_begin_invoke_generic_cache);
+       free_hash (image->delegate_end_invoke_generic_cache);
+       free_hash (image->synchronized_generic_cache);
        free_hash (image->remoting_invoke_cache);
        free_hash (image->runtime_invoke_cache);
+       free_hash (image->runtime_invoke_vtype_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);
@@ -1462,24 +1644,32 @@ mono_image_close (MonoImage *image)
        free_hash (image->castclass_cache);
        free_hash (image->proxy_isinst_cache);
        free_hash (image->thunk_invoke_cache);
-       free_hash (image->static_rgctx_invoke_cache);
+       free_hash (image->var_cache_slow);
+       free_hash (image->mvar_cache_slow);
+       free_hash (image->wrapper_param_names);
+       free_hash (image->native_wrapper_aot_cache);
+       free_hash (image->pinvoke_scopes);
+       free_hash (image->pinvoke_scope_filenames);
+       free_hash (image->gsharedvt_types);
 
        /* The ownership of signatures is not well defined */
-       //g_hash_table_foreach (image->memberref_signatures, free_mr_signatures, NULL);
        g_hash_table_destroy (image->memberref_signatures);
-       //g_hash_table_foreach (image->helper_signatures, free_mr_signatures, NULL);
        g_hash_table_destroy (image->helper_signatures);
        g_hash_table_destroy (image->method_signatures);
 
-       if (image->generic_class_cache)
-               g_hash_table_destroy (image->generic_class_cache);
-
        if (image->rgctx_template_hash)
                g_hash_table_destroy (image->rgctx_template_hash);
 
        if (image->property_hash)
                mono_property_hash_destroy (image->property_hash);
 
+       /*
+       reflection_info_unregister_classes is only required by dynamic images, which will not be properly
+       cleared during shutdown as we don't perform regular appdomain unload for the root one.
+       */
+       g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
+       image->reflection_info_unregister_classes = NULL;
+
        if (image->interface_bitset) {
                mono_unload_interface_ids (image->interface_bitset);
                mono_bitset_free (image->interface_bitset);
@@ -1495,20 +1685,55 @@ 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);
-       mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
 
+       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;
+
+       if (image->references && !image->dynamic) {
+               for (i = 0; i < image->nreferences; i++) {
+                       if (image->references [i] && image->references [i] != REFERENCE_MISSING)
+                               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);
+
+#ifndef DISABLE_PERFCOUNTERS
+       mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
+#endif
+
        if (!image->dynamic) {
                if (debug_assembly_unload)
                        mono_mempool_invalidate (image->mempool);
@@ -1517,13 +1742,25 @@ mono_image_close (MonoImage *image)
                        g_free (image);
                }
        } else {
-               /* Dynamic images are GC_MALLOCed */
-               g_free ((char*)image->module_name);
-               mono_dynamic_image_free ((MonoDynamicImage*)image);
-               mono_mempool_destroy (image->mempool);
+               if (debug_assembly_unload)
+                       mono_mempool_invalidate (image->mempool);
+               else
+                       mono_mempool_destroy (image->mempool);
        }
+}
 
-       mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
+/**
+ * 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);
 }
 
 /** 
@@ -1574,11 +1811,11 @@ mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
        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)) {
@@ -1586,12 +1823,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 ();
        }
@@ -1658,6 +1891,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);
@@ -1784,7 +2019,7 @@ mono_image_load_file_for_image (MonoImage *image, int fileidx)
                }
 
                image->files [fileidx - 1] = res;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
                if (res->is_module_handle)
                        mono_image_fixup_vtable (res);
 #endif
@@ -1993,7 +2228,9 @@ mono_image_alloc (MonoImage *image, guint size)
 {
        gpointer res;
 
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_bytes += size;
+#endif
        mono_image_lock (image);
        res = mono_mempool_alloc (image->mempool, size);
        mono_image_unlock (image);
@@ -2006,7 +2243,9 @@ mono_image_alloc0 (MonoImage *image, guint size)
 {
        gpointer res;
 
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_bytes += size;
+#endif
        mono_image_lock (image);
        res = mono_mempool_alloc0 (image->mempool, size);
        mono_image_unlock (image);
@@ -2019,7 +2258,9 @@ mono_image_strdup (MonoImage *image, const char *s)
 {
        char *res;
 
+#ifndef DISABLE_PERFCOUNTERS
        mono_perfcounters->loader_bytes += strlen (s);
+#endif
        mono_image_lock (image);
        res = mono_mempool_strdup (image->mempool, s);
        mono_image_unlock (image);
@@ -2060,13 +2301,13 @@ g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
 void
 mono_image_lock (MonoImage *image)
 {
-       EnterCriticalSection (&image->lock);
+       mono_locks_acquire (&image->lock, ImageDataLock);
 }
 
 void
 mono_image_unlock (MonoImage *image)
 {
-       LeaveCriticalSection (&image->lock);
+       mono_locks_release (&image->lock, ImageDataLock);
 }
 
 
@@ -2118,3 +2359,13 @@ mono_image_property_remove (MonoImage *image, gpointer subject)
        mono_property_hash_remove_object (image->property_hash, subject);
        mono_image_unlock (image);
 }
+
+void
+mono_image_append_class_to_reflection_info_set (MonoClass *class)
+{
+       MonoImage *image = class->image;
+       g_assert (image->dynamic);
+       mono_image_lock (image);
+       image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, class);
+       mono_image_unlock (image);
+}