2010-02-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / image.c
index da552e6fa65c971a1674302873f03a585e4633f8..114edd4c56d8b920be2f04940f051f2f21396c52 100644 (file)
@@ -52,8 +52,9 @@ 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;
 
 /* returns offset relative to image->raw_data */
@@ -68,7 +69,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
@@ -105,7 +106,7 @@ mono_image_rva_map (MonoImage *image, guint32 addr)
                                if (!mono_image_ensure_section_idx (image, i))
                                        return NULL;
                        }
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
                        if (image->is_module_handle)
                                return image->raw_data + addr;
 #endif
@@ -131,6 +132,8 @@ mono_images_init (void)
        loaded_images_refonly_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
        debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
+
+       mutex_inited = TRUE;
 }
 
 /**
@@ -145,6 +148,8 @@ mono_images_cleanup (void)
 
        g_hash_table_destroy (loaded_images_hash);
        g_hash_table_destroy (loaded_images_refonly_hash);
+
+       mutex_inited = FALSE;
 }
 
 /**
@@ -175,7 +180,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
@@ -328,6 +333,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){
@@ -528,7 +534,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))
+               return NULL;
        if (image->modules_loaded [idx - 1])
                return image->modules [idx - 1];
 
@@ -566,7 +573,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
@@ -640,7 +647,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)
@@ -761,7 +768,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
@@ -780,7 +787,7 @@ mono_image_load_pe_data (MonoImage *image)
        iinfo = image->image_info;
        header = &iinfo->cli_header;
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        if (!image->is_module_handle)
 #endif
        if (offset + sizeof (msdos) > image->raw_data_len)
@@ -853,6 +860,21 @@ mono_image_load_cli_data (MonoImage *image)
        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, 
+                       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)
@@ -889,16 +911,10 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
        if (!mono_image_load_cli_data (image))
                goto invalid_image;
 
-       /* modules don't have an assembly table row */
-       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));
-       }
+       if (!mono_verifier_verify_table_data (image, NULL))
+               goto invalid_image;
 
-       image->module_name = mono_metadata_string_heap (image, 
-                       mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
-                                       0, MONO_MODULE_NAME));
+       mono_image_load_names (image);
 
        load_modules (image);
 
@@ -1051,7 +1067,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;
@@ -1077,7 +1093,7 @@ 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;
@@ -1089,13 +1105,19 @@ mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy
        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)
@@ -1129,7 +1151,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;
@@ -1277,7 +1299,7 @@ mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
 void
 mono_image_fixup_vtable (MonoImage *image)
 {
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        MonoCLIImageInfo *iinfo;
        MonoPEDirEntry *de;
        MonoVTableFixup *vtfixup;
@@ -1382,33 +1404,53 @@ 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;
+       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);     
 
-#ifdef PLATFORM_WIN32
+       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 ();
        }
@@ -1418,7 +1460,7 @@ mono_image_close (MonoImage *image)
 
        mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
 
-       mono_metadata_clean_for_image (image);
+       free_list = mono_metadata_clean_for_image (image);
 
        /*
         * The caches inside a MonoImage might refer to metadata which is stored in referenced 
@@ -1430,30 +1472,24 @@ mono_image_close (MonoImage *image)
                int i;
 
                for (i = 0; i < t->rows; i++) {
-                       if (image->references [i])
-                               mono_assembly_close (image->references [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);     
-
-#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)
@@ -1487,7 +1523,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);
@@ -1529,7 +1565,6 @@ 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);
 
        /* The ownership of signatures is not well defined */
        //g_hash_table_foreach (image->memberref_signatures, free_mr_signatures, NULL);
@@ -1538,15 +1573,15 @@ mono_image_close (MonoImage *image)
        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);
 
+       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);
@@ -1562,21 +1597,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);
-       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;
+       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);
@@ -1585,13 +1661,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);
 }
 
 /** 
@@ -1850,7 +1938,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