2007-12-29 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / assembly.c
index 0360aae15b11f82f3dec6972fd661f9191aaf044..39d75bec9a13147aef37a52c2b6cd9a6d2f6614f 100644 (file)
 #include <stdlib.h>
 #include "assembly.h"
 #include "image.h"
-#include "cil-coff.h"
 #include "rawbuffer.h"
+#include "object-internals.h"
 #include <mono/metadata/loader.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/profiler-private.h>
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/domain-internals.h>
 #include <mono/metadata/mono-endian.h>
+#include <mono/metadata/mono-debug.h>
 #include <mono/io-layer/io-layer.h>
 #include <mono/utils/mono-uri.h>
 #include <mono/metadata/mono-config.h>
@@ -119,12 +121,6 @@ static MonoAssembly *corlib;
 #define mono_assemblies_unlock() LeaveCriticalSection (&assemblies_mutex)
 static CRITICAL_SECTION assemblies_mutex;
 
-/* A hastable of thread->assembly list mappings */
-static GHashTable *assemblies_loading;
-
-/* A hashtable of reflection only load thread->assemblies mappings */
-static GHashTable *assemblies_refonly_loading;
-
 /* If defined, points to the bundled assembly information */
 const MonoBundledAssembly **bundles;
 
@@ -379,26 +375,11 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
 static MonoAssembly*
 search_loaded (MonoAssemblyName* aname, gboolean refonly)
 {
-       GList *tmp;
        MonoAssembly *ass;
-       GList *loading;
 
        ass = mono_assembly_invoke_search_hook_internal (aname, refonly, FALSE);
        if (ass)
                return ass;
-       
-       /*
-        * The assembly might be under load by this thread. In this case, it is
-        * safe to return an incomplete instance to prevent loops.
-        */
-       loading = g_hash_table_lookup (refonly ? assemblies_refonly_loading : assemblies_loading, (gpointer)GetCurrentThreadId ());
-       for (tmp = loading; tmp; tmp = tmp->next) {
-               ass = tmp->data;
-               if (!mono_assembly_names_equal (aname, &ass->aname))
-                       continue;
-
-               return ass;
-       }
 
        return NULL;
 }
@@ -646,9 +627,6 @@ mono_assemblies_init (void)
        check_extra_gac_path_env ();
 
        InitializeCriticalSection (&assemblies_mutex);
-
-       assemblies_loading = g_hash_table_new (NULL, NULL);
-       assemblies_refonly_loading = g_hash_table_new (NULL, NULL);
 }
 
 gboolean
@@ -854,8 +832,11 @@ mono_assembly_load_reference (MonoImage *image, int index)
         * it inside a critical section.
         */
        mono_assemblies_lock ();
-       if (!image->references)
-               mono_assembly_load_references (image, &status);
+       if (!image->references) {
+               MonoTableInfo *t = &image->tables [MONO_TABLE_ASSEMBLYREF];
+       
+               image->references = g_new0 (MonoAssembly *, t->rows + 1);
+       }
        reference = image->references [index];
        mono_assemblies_unlock ();
        if (reference)
@@ -867,8 +848,13 @@ mono_assembly_load_reference (MonoImage *image, int index)
                /* We use the loaded corlib */
                if (!strcmp (aname.name, "mscorlib"))
                        reference = mono_assembly_load_full (&aname, image->assembly->basedir, &status, FALSE);
-               else
+               else {
                        reference = mono_assembly_loaded_full (&aname, TRUE);
+                       if (!reference)
+                               /* Try a postload search hook */
+                               reference = mono_assembly_invoke_search_hook_internal (&aname, TRUE, TRUE);
+               }
+
                /*
                 * Here we must advice that the error was due to
                 * a non loaded reference using the ReflectionOnly api
@@ -932,13 +918,8 @@ mono_assembly_load_reference (MonoImage *image, int index)
 void
 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
 {
-       MonoTableInfo *t;
-
+       /* This is a no-op now but it is part of the embedding API so we can't remove it */
        *status = MONO_IMAGE_OK;
-
-       t = &image->tables [MONO_TABLE_ASSEMBLYREF];
-       
-       image->references = g_new0 (MonoAssembly *, t->rows + 1);
 }
 
 typedef struct AssemblyLoadHook AssemblyLoadHook;
@@ -1340,15 +1321,19 @@ mono_assembly_open_full (const char *filename, MonoImageOpenStatus *status, gboo
 }
 
 /*
- * load_friend_assemblies:
+ * mono_load_friend_assemblies:
  * @ass: an assembly
  *
  * Load the list of friend assemblies that are allowed to access
  * the assembly's internal types and members. They are stored as assembly
  * names in custom attributes.
+ *
+ * This is an internal method, we need this because when we load mscorlib
+ * we do not have the mono_defaults.internals_visible_class loaded yet,
+ * so we need to load these after we initialize the runtime. 
  */
-static void
-load_friend_assemblies (MonoAssembly* ass)
+void
+mono_assembly_load_friends (MonoAssembly* ass)
 {
        int i;
        MonoCustomAttrInfo* attrs = mono_custom_attrs_from_assembly (ass);
@@ -1404,8 +1389,6 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
 {
        MonoAssembly *ass, *ass2;
        char *base_dir;
-       GList *loading;
-       GHashTable *ass_loading;
 
        if (!image->tables [MONO_TABLE_ASSEMBLY].rows) {
                /* 'image' doesn't have a manifest -- maybe someone is trying to Assembly.Load a .netmodule */
@@ -1413,7 +1396,6 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
                return NULL;
        }
 
-
 #if defined (PLATFORM_WIN32)
        {
                gchar *tmp_fn;
@@ -1432,14 +1414,6 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
        base_dir = absolute_dir (fname);
 #endif
 
-       /*
-        * To avoid deadlocks and scalability problems, we load assemblies outside
-        * the assembly lock. This means that multiple threads might try to load
-        * the same assembly at the same time. The first one to load it completely
-        * "wins", the other threads free their copy and use the one loaded by
-        * the winning thread.
-        */
-
        /*
         * Create assembly struct, and enter it into the assembly cache
         */
@@ -1448,11 +1422,13 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
        ass->ref_only = refonly;
        ass->image = image;
 
-       /* Add a non-temporary reference because of ass->image */
-       mono_image_addref (image);
+       mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD);
 
        mono_assembly_fill_assembly_name (image, &ass->aname);
 
+       /* Add a non-temporary reference because of ass->image */
+       mono_image_addref (image);
+
        mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Image addref %s %p -> %s %p: %d\n", ass->aname.name, ass, image->name, image, image->ref_count);
 
        /* 
@@ -1471,49 +1447,19 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
                        return ass2;
                }
        }
-       ass_loading = refonly ? assemblies_refonly_loading : assemblies_loading;
-       loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ());
-       loading = g_list_prepend (loading, ass);
-       g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading);
-       mono_assemblies_unlock ();
 
        g_assert (image->assembly == NULL);
        image->assembly = ass;
 
-       mono_assembly_load_references (image, status);
-
-       mono_assemblies_lock ();
-
-       loading = g_hash_table_lookup (ass_loading, (gpointer)GetCurrentThreadId ());
-       loading = g_list_remove (loading, ass);
-       if (loading == NULL)
-               /* Prevent memory leaks */
-               g_hash_table_remove (ass_loading, (gpointer)GetCurrentThreadId ());
-       else
-               g_hash_table_insert (ass_loading, (gpointer)GetCurrentThreadId (), loading);
-       if (*status != MONO_IMAGE_OK) {
-               mono_assemblies_unlock ();
-               mono_assembly_close (ass);
-               return NULL;
-       }
-
-       if (ass->aname.name) {
-               ass2 = search_loaded (&ass->aname, refonly);
-               if (ass2) {
-                       /* Somebody else has loaded the assembly before us */
-                       mono_assemblies_unlock ();
-                       mono_assembly_close (ass);
-                       return ass2;
-               }
-       }
-
        loaded_assemblies = g_list_prepend (loaded_assemblies, ass);
        if (mono_defaults.internals_visible_class)
-               load_friend_assemblies (ass);
+               mono_assembly_load_friends (ass);
        mono_assemblies_unlock ();
 
        mono_assembly_invoke_load_hook (ass);
 
+       mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
+       
        return ass;
 }
 
@@ -1916,7 +1862,13 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta
 
        if (res)
                res->in_gac = TRUE;
-
+       else {
+               MonoDomain *domain = mono_domain_get ();
+               MonoReflectionAssembly *refasm = mono_try_assembly_resolve (domain, mono_string_new (domain, name), FALSE);
+               if (refasm)
+                       res = refasm->assembly;
+       }
+       
        g_free (fullname);
        mono_assembly_name_free (aname);
 
@@ -2169,24 +2121,10 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
        return corlib;
 }
 
-/**
- * mono_assembly_load_full:
- * @aname: A MonoAssemblyName with the assembly name to load.
- * @basedir: A directory to look up the assembly at.
- * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
- * @refonly: Whether this assembly is being opened in "reflection-only" mode.
- *
- * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
- * attempts to load the assembly from that directory before probing the standard locations.
- *
- * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
- * assembly binding takes place.
- *
- * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
- * value pointed by status is updated with an error code.
- */
-MonoAssembly*
-mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
+MonoAssembly* mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
+                                               const char       *basedir, 
+                                               MonoImageOpenStatus *status,
+                                               gboolean refonly)
 {
        MonoAssembly *result;
        char *fullpath, *filename;
@@ -2254,9 +2192,33 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage
                        return result;
        }
 
-       /* Try a postload search hook */
-       result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
+       return result;
+}
 
+/**
+ * mono_assembly_load_full:
+ * @aname: A MonoAssemblyName with the assembly name to load.
+ * @basedir: A directory to look up the assembly at.
+ * @status: a pointer to a MonoImageOpenStatus to return the status of the load operation
+ * @refonly: Whether this assembly is being opened in "reflection-only" mode.
+ *
+ * Loads the assembly referenced by @aname, if the value of @basedir is not NULL, it
+ * attempts to load the assembly from that directory before probing the standard locations.
+ *
+ * If the assembly is being opened in reflection-only mode (@refonly set to TRUE) then no 
+ * assembly binding takes place.
+ *
+ * Returns: the assembly referenced by @aname loaded or NULL on error.   On error the
+ * value pointed by status is updated with an error code.
+ */
+MonoAssembly*
+mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status, gboolean refonly)
+{
+       MonoAssembly *result = mono_assembly_load_full_nosearch (aname, basedir, status, refonly);
+       
+       if (!result)
+               /* Try a postload search hook */
+               result = mono_assembly_invoke_search_hook_internal (aname, refonly, TRUE);
        return result;
 }
 
@@ -2326,24 +2288,16 @@ mono_assembly_close (MonoAssembly *assembly)
        if (InterlockedDecrement (&assembly->ref_count) > 0)
                return;
 
+       mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD);
+
        mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly);
 
+       mono_debug_close_image (assembly->image);
+
        mono_assemblies_lock ();
        loaded_assemblies = g_list_remove (loaded_assemblies, assembly);
        mono_assemblies_unlock ();
 
-       if (assembly->image->references) {
-               int i;
-
-               for (i = 0; assembly->image->references [i]; i++) {
-                       if (assembly->image->references [i])
-                               mono_assembly_close (assembly->image->references [i]);
-               }
-
-               g_free (assembly->image->references);
-               assembly->image->references = NULL;
-       }
-
        assembly->image->assembly = NULL;
 
        mono_image_close (assembly->image);
@@ -2360,19 +2314,14 @@ mono_assembly_close (MonoAssembly *assembly)
        } else {
                g_free (assembly);
        }
+
+       mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD);
 }
 
 MonoImage*
 mono_assembly_load_module (MonoAssembly *assembly, guint32 idx)
 {
-       MonoImageOpenStatus status;
-       MonoImage *module;
-
-       module = mono_image_load_file_for_image (assembly->image, idx);
-       if (module)
-               mono_assembly_load_references (module, &status);
-
-       return module;
+       return mono_image_load_file_for_image (assembly->image, idx);
 }
 
 void
@@ -2405,9 +2354,6 @@ mono_assemblies_cleanup (void)
 
        DeleteCriticalSection (&assemblies_mutex);
 
-       g_hash_table_destroy (assemblies_loading);
-       g_hash_table_destroy (assemblies_refonly_loading);
-
        for (l = loaded_assembly_bindings; l; l = l->next) {
                MonoAssemblyBindingInfo *info = l->data;