last merge 100420:100549
[mono.git] / mono / metadata / assembly.c
index 4a50672bd797c48753b0a1e36404db3de48b0319..0314d2e585d0c7e443df5c6d57bd1388de16f02b 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>
@@ -72,7 +74,6 @@ static const AssemblyVersionMap framework_assemblies [] = {
        {"Mono.Cairo", 0},
        {"Mono.CompilerServices.SymbolWriter", 0},
        {"Mono.Data", 0},
-       {"Mono.Data.SqliteClient", 0},
        {"Mono.Data.SybaseClient", 0},
        {"Mono.Data.Tds", 0},
        {"Mono.Data.TdsClient", 0},
@@ -120,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;
 
@@ -151,11 +146,25 @@ encode_public_tok (const guchar *token, gint32 len)
        return res;
 }
 
+/**
+ * mono_public_tokens_are_equal:
+ * @pubt1: first public key token
+ * @pubt2: second public key token
+ *
+ * Compare two public key tokens and return #TRUE is they are equal and #FALSE
+ * otherwise.
+ */
+gboolean
+mono_public_tokens_are_equal (const unsigned char *pubt1, const unsigned char *pubt2)
+{
+       return g_strcasecmp ((char*)pubt1, (char*)pubt2) == 0;
+}
+
 static void
 check_path_env (void)
 {
        const char *path;
-       char **splitted;
+       char **splitted, **dest;
        
        path = g_getenv ("MONO_PATH");
        if (!path)
@@ -164,7 +173,14 @@ check_path_env (void)
        splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
        if (assemblies_path)
                g_strfreev (assemblies_path);
-       assemblies_path = splitted;
+       assemblies_path = dest = splitted;
+       while (*splitted){
+               if (**splitted)
+                       *dest++ = *splitted;
+               splitted++;
+       }
+       *dest = *splitted;
+       
        if (g_getenv ("MONO_DEBUG") == NULL)
                return;
 
@@ -179,7 +195,7 @@ check_path_env (void)
 static void
 check_extra_gac_path_env (void) {
        const char *path;
-       char **splitted;
+       char **splitted, **dest;
        
        path = g_getenv ("MONO_GAC_PREFIX");
        if (!path)
@@ -188,7 +204,14 @@ check_extra_gac_path_env (void) {
        splitted = g_strsplit (path, G_SEARCHPATH_SEPARATOR_S, 1000);
        if (extra_gac_paths)
                g_strfreev (extra_gac_paths);
-       extra_gac_paths = splitted;
+       extra_gac_paths = dest = splitted;
+       while (*splitted){
+               if (**splitted)
+                       *dest++ = *splitted;
+               splitted++;
+       }
+       *dest = *splitted;
+       
        if (g_getenv ("MONO_DEBUG") == NULL)
                return;
 
@@ -215,7 +238,7 @@ assembly_binding_maps_name (MonoAssemblyBindingInfo *info, MonoAssemblyName *ana
        if (info->culture && strcmp (info->culture, aname->culture))
                return FALSE;
        
-       if (strcmp ((const char *)info->public_key_token, (const char *)aname->public_key_token))
+       if (!mono_public_tokens_are_equal (info->public_key_token, aname->public_key_token))
                return FALSE;
 
        return TRUE;
@@ -331,6 +354,7 @@ check_policy_versions (MonoAssemblyBindingInfo *info, MonoAssemblyName *name)
  * @r: second assembly.
  *
  * Compares two MonoAssemblyNames and returns whether they are equal.
+ *
  * This compares the names, the cultures, the release version and their
  * public tokens.
  *
@@ -356,7 +380,7 @@ mono_assembly_names_equal (MonoAssemblyName *l, MonoAssemblyName *r)
        if (!l->public_key_token [0] || !r->public_key_token [0])
                return TRUE;
 
-       if (strcmp ((char*)l->public_key_token, (char*)r->public_key_token))
+       if (!mono_public_tokens_are_equal (l->public_key_token, r->public_key_token))
                return FALSE;
 
        return TRUE;
@@ -365,26 +389,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;
 }
@@ -411,8 +420,10 @@ load_in_path (const char *basename, const char** search_path, MonoImageOpenStatu
  * @root_dir: The pathname of the root directory where we will locate assemblies
  *
  * This routine sets the internal default root directory for looking up
- * assemblies.  This is used by Windows installations to compute dynamically
- * the place where the Mono assemblies are located.
+ * assemblies.
+ *
+ * This is used by Windows installations to compute dynamically the
+ * place where the Mono assemblies are located.
  *
  */
 void
@@ -427,8 +438,10 @@ mono_assembly_setrootdir (const char *root_dir)
 
 /**
  * mono_assembly_getrootdir:
+ * 
+ * Obtains the root directory used for looking up assemblies.
  *
- * Returns: The internal root directory used for looking up assemblies
+ * Returns: a string with the directory, this string should not be freed.
  */
 G_CONST_RETURN gchar *
 mono_assembly_getrootdir (void)
@@ -442,10 +455,11 @@ mono_assembly_getrootdir (void)
  * @config_dir: the base directory for configuration files
  *
  * This routine is used internally and by developers embedding
- * the runtime into their own applications.  There are a number
- * of cases to consider: Mono as a system-installed package that
- * is available on the location preconfigured or Mono in a relocated
- * location.
+ * the runtime into their own applications.
+ *
+ * There are a number of cases to consider: Mono as a system-installed
+ * package that is available on the location preconfigured or Mono in
+ * a relocated location.
  *
  * If you are using a system-installed Mono, you can pass NULL
  * to both parameters.  If you are not, you should compute both
@@ -627,9 +641,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
@@ -654,16 +665,18 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
        aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
        aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
        if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
-               gchar* token = g_malloc (8);
+               guchar* token = g_malloc (8);
                gchar* encoded;
+               const gchar* pkey;
                int len;
 
-               aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
-               len = mono_metadata_decode_blob_size (aname->public_key, (const char**)&aname->public_key);
+               pkey = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
+               len = mono_metadata_decode_blob_size (pkey, &pkey);
+               aname->public_key = (guchar*)pkey;
 
                mono_digest_get_public_token (token, aname->public_key, len);
                encoded = encode_public_tok (token, 8);
-               g_strlcpy (aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+               g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
 
                g_free (encoded);
                g_free (token);
@@ -674,7 +687,7 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
        }
 
        if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
-               aname->public_key = mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
+               aname->public_key = (guchar*)mono_metadata_blob_heap (image, cols [MONO_ASSEMBLY_PUBLIC_KEY]);
        }
        else
                aname->public_key = 0;
@@ -682,22 +695,26 @@ mono_assembly_fill_assembly_name (MonoImage *image, MonoAssemblyName *aname)
        return TRUE;
 }
 
-/*
+/**
  * mono_stringify_assembly_name:
+ * @aname: the assembly name.
  *
- *   Convert @aname into its string format. The returned string is dynamically
+ * Convert @aname into its string format. The returned string is dynamically
  * allocated and should be freed by the caller.
+ *
+ * Returns: a newly allocated string with a string representation of
+ * the assembly name.
  */
 char*
 mono_stringify_assembly_name (MonoAssemblyName *aname)
 {
        return g_strdup_printf (
-               "%s, Version=%d.%d.%d.%d, Culture=%s%s%s",
+               "%s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s",
                aname->name,
                aname->major, aname->minor, aname->build, aname->revision,
                aname->culture && *aname->culture? aname->culture: "neutral",
-               aname->public_key_token [0] ? ", PublicKeyToken=" : "",
-               aname->public_key_token [0] ? (char *)aname->public_key_token : "");
+               aname->public_key_token [0] ? (char *)aname->public_key_token : "null",
+               (aname->flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : "");
 }
 
 static gchar*
@@ -710,12 +727,12 @@ assemblyref_public_tok (MonoImage *image, guint32 key_index, guint32 flags)
        len = mono_metadata_decode_blob_size (public_tok, &public_tok);
 
        if (flags & ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG) {
-               gchar token [8];
-               mono_digest_get_public_token (token, public_tok, len);
+               guchar token [8];
+               mono_digest_get_public_token (token, (guchar*)public_tok, len);
                return encode_public_tok (token, 8);
        }
 
-       return encode_public_tok (public_tok, len);
+       return encode_public_tok ((guchar*)public_tok, len);
 }
 
 /**
@@ -810,7 +827,7 @@ mono_assembly_get_assemblyref (MonoImage *image, int index, MonoAssemblyName *an
 
        if (cols [MONO_ASSEMBLYREF_PUBLIC_KEY]) {
                gchar *token = assemblyref_public_tok (image, cols [MONO_ASSEMBLYREF_PUBLIC_KEY], aname->flags);
-               g_strlcpy (aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+               g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
                g_free (token);
        } else {
                memset (aname->public_key_token, 0, MONO_PUBLIC_KEY_TOKEN_LENGTH);
@@ -829,6 +846,11 @@ mono_assembly_load_reference (MonoImage *image, int index)
         * it inside a critical section.
         */
        mono_assemblies_lock ();
+       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)
@@ -836,12 +858,17 @@ mono_assembly_load_reference (MonoImage *image, int index)
 
        mono_assembly_get_assemblyref (image, index, &aname);
 
-       if (image->assembly->ref_only) {
+       if (image->assembly && image->assembly->ref_only) {
                /* 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
@@ -849,7 +876,7 @@ mono_assembly_load_reference (MonoImage *image, int index)
                if (!reference)
                        reference = REFERENCE_MISSING;
        } else
-               reference = mono_assembly_load (&aname, image->assembly->basedir, &status);
+               reference = mono_assembly_load (&aname, image->assembly? image->assembly->basedir: NULL, &status);
 
        if (reference == NULL){
                char *extra_msg = g_strdup ("");
@@ -870,7 +897,7 @@ mono_assembly_load_reference (MonoImage *image, int index)
                                   "     Public Key: %s\n%s",
                                   image->name, aname.name, index,
                                   aname.major, aname.minor, aname.build, aname.revision,
-                                  strlen(aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
+                                  strlen ((char*)aname.public_key_token) == 0 ? "(none)" : (char*)aname.public_key_token, extra_msg);
                g_free (extra_msg);
        }
 
@@ -883,10 +910,12 @@ mono_assembly_load_reference (MonoImage *image, int index)
        if (!image->references [index]) {
                if (reference != REFERENCE_MISSING){
                        mono_assembly_addref (reference);
-                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n",
+                       if (image->assembly)
+                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly Ref addref %s %p -> %s %p: %d\n",
                                    image->assembly->aname.name, image->assembly, reference->aname.name, reference, reference->ref_count);
                } else {
-                       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
+                       if (image->assembly)
+                               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Failed to load assembly %s %p\n",
                                    image->assembly->aname.name, image->assembly);
                }
                
@@ -903,22 +932,8 @@ mono_assembly_load_reference (MonoImage *image, int index)
 void
 mono_assembly_load_references (MonoImage *image, MonoImageOpenStatus *status)
 {
-       MonoTableInfo *t;
-       int i;
-
+       /* 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);
-
-       /* resolve assembly references for modules */
-       for (i = 0; i < image->module_count; i++){
-               if (image->modules [i]) {
-                       image->modules [i]->assembly = image->assembly;
-                       mono_assembly_load_references (image->modules [i], status);
-               }
-       }
 }
 
 typedef struct AssemblyLoadHook AssemblyLoadHook;
@@ -1171,11 +1186,12 @@ absolute_dir (const gchar *filename)
        list = g_list_reverse (list);
 
        /* Ignores last data pointer, which should be the filename */
-       for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next)
+       for (tmp = list; tmp && tmp->next != NULL; tmp = tmp->next){
                if (tmp->data)
                        g_string_append_printf (result, "%s%c", (char *) tmp->data,
                                                                G_DIR_SEPARATOR);
-       
+       }
+
        res = result->str;
        g_string_free (result, FALSE);
        g_list_free (list);
@@ -1197,17 +1213,23 @@ absolute_dir (const gchar *filename)
  * defined bundles, if found, returns the MonoImage for it, if not found
  * returns NULL
  */
-static MonoImage *
+MonoImage *
 mono_assembly_open_from_bundle (const char *filename, MonoImageOpenStatus *status, gboolean refonly)
 {
        int i;
-       char *name = g_path_get_basename (filename);
+       char *name;
        MonoImage *image = NULL;
 
        /*
         * we do a very simple search for bundled assemblies: it's not a general 
         * purpose assembly loading mechanism.
         */
+
+       if (!bundles)
+               return NULL;
+
+       name = g_path_get_basename (filename);
+
        mono_assemblies_lock ();
        for (i = 0; !image && bundles [i]; ++i) {
                if (strcmp (bundles [i]->name, name) == 0) {
@@ -1313,15 +1335,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);
@@ -1330,21 +1356,21 @@ load_friend_assemblies (MonoAssembly* ass)
        for (i = 0; i < attrs->num_attrs; ++i) {
                MonoCustomAttrEntry *attr = &attrs->attrs [i];
                MonoAssemblyName *aname;
-               const guchar *data;
+               const gchar *data;
                guint slen;
                /* Do some sanity checking */
                if (!attr->ctor || attr->ctor->klass != mono_defaults.internals_visible_class)
                        continue;
                if (attr->data_size < 4)
                        continue;
-               data = attr->data;
+               data = (const char*)attr->data;
                /* 0xFF means null string, see custom attr format */
-               if (data [0] != 1 || data [1] != 0 || data [2] == 0xFF)
+               if (data [0] != 1 || data [1] != 0 || (data [2] & 0xFF) == 0xFF)
                        continue;
                slen = mono_metadata_decode_value (data + 2, &data);
                aname = g_new0 (MonoAssemblyName, 1);
                /*g_print ("friend ass: %s\n", data);*/
-               if (mono_assembly_name_parse_full (data, aname, TRUE, NULL)) {
+               if (mono_assembly_name_parse_full (data, aname, TRUE, NULL, NULL)) {
                        ass->friend_assembly_names = g_slist_prepend (ass->friend_assembly_names, aname);
                } else {
                        g_free (aname);
@@ -1377,8 +1403,12 @@ 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 */
+               *status = MONO_IMAGE_IMAGE_INVALID;
+               return NULL;
+       }
 
 #if defined (PLATFORM_WIN32)
        {
@@ -1398,14 +1428,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
         */
@@ -1414,11 +1436,22 @@ 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);
 
+       if (mono_defaults.corlib && strcmp (ass->aname.name, "mscorlib") == 0) {
+               // MS.NET doesn't support loading other mscorlibs
+               g_free (ass);
+               g_free (base_dir);
+               mono_image_addref (mono_defaults.corlib);
+               *status = MONO_IMAGE_OK;
+               return mono_defaults.corlib->assembly;
+       }
+
+       /* 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);
 
        /* 
@@ -1429,57 +1462,27 @@ mono_assembly_load_from_full (MonoImage *image, const char*fname,
                /* avoid loading the same assembly twice for now... */
                ass2 = search_loaded (&ass->aname, refonly);
                if (ass2) {
+                       mono_assemblies_unlock ();
                        g_free (ass);
                        g_free (base_dir);
                        mono_image_close (image);
                        *status = MONO_IMAGE_OK;
-                       mono_assemblies_unlock ();
                        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;
 }
 
@@ -1491,12 +1494,12 @@ mono_assembly_load_from (MonoImage *image, const char *fname,
 }
 
 /**
-* mono_assembly_name_free:
-* @aname: assembly name to free
-* 
-* Frees the provided assembly name object.
-* (it does not frees the object itself, only the name members).
-*/
+ * mono_assembly_name_free:
+ * @aname: assembly name to free
+ 
+ * Frees the provided assembly name object.
+ * (it does not frees the object itself, only the name members).
+ */
 void
 mono_assembly_name_free (MonoAssemblyName *aname)
 {
@@ -1583,24 +1586,36 @@ parse_public_key (const gchar *key, gchar** pubkey)
 }
 
 static gboolean
-build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, MonoAssemblyName *aname, gboolean save_public_key)
+build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, guint32 flags, MonoAssemblyName *aname, gboolean save_public_key)
 {
        gint major, minor, build, revision;
        gint len;
+       gint version_parts;
        gchar *pkey, *pkeyptr, *encoded, tok [8];
 
        memset (aname, 0, sizeof (MonoAssemblyName));
 
        if (version) {
-               if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
+               version_parts = sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision);
+               if (version_parts < 2 || version_parts > 4)
                        return FALSE;
 
+               /* FIXME: we should set build & revision to -1 (instead of 0)
+               if these are not set in the version string. That way, later on,
+               we can still determine if these were specified. */
                aname->major = major;
                aname->minor = minor;
-               aname->build = build;
-               aname->revision = revision;
+               if (version_parts >= 3)
+                       aname->build = build;
+               else
+                       aname->build = 0;
+               if (version_parts == 4)
+                       aname->revision = revision;
+               else
+                       aname->revision = 0;
        }
        
+       aname->flags = flags;
        aname->name = g_strdup (name);
        
        if (culture) {
@@ -1611,13 +1626,19 @@ build_assembly_name (const char *name, const char *version, const char *culture,
        }
        
        if (token && strncmp (token, "null", 4) != 0) {
-               char *lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+               char *lower;
+
+               /* the constant includes the ending NULL, hence the -1 */
+               if (strlen (token) != (MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)) {
+                       return FALSE;
+               }
+               lower = g_ascii_strdown (token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
                g_strlcpy ((char*)aname->public_key_token, lower, MONO_PUBLIC_KEY_TOKEN_LENGTH);
                g_free (lower);
        }
 
-       if (key && strncmp (key, "null", 4) != 0) {
-               if (!parse_public_key (key, &pkey)) {
+       if (key) {
+               if (strcmp (key, "null") == 0 || !parse_public_key (key, &pkey)) {
                        mono_assembly_name_free (aname);
                        return FALSE;
                }
@@ -1634,7 +1655,7 @@ build_assembly_name (const char *name, const char *version, const char *culture,
                else
                        g_free (pkey);
        }
-       
+
        return TRUE;
 }
 
@@ -1650,30 +1671,36 @@ parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemb
                return FALSE;
        }
        
-       res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, aname, FALSE);
+       res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, 0, aname, FALSE);
        g_strfreev (parts);
        return res;
 }
 
 gboolean
-mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined)
+mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboolean save_public_key, gboolean *is_version_defined, gboolean *is_token_defined)
 {
        gchar *dllname;
        gchar *version = NULL;
        gchar *culture = NULL;
        gchar *token = NULL;
        gchar *key = NULL;
+       gchar *retargetable = NULL;
        gboolean res;
        gchar *value;
        gchar **parts;
        gchar **tmp;
        gboolean version_defined;
+       gboolean token_defined;
+       guint32 flags = 0;
 
        if (!is_version_defined)
                is_version_defined = &version_defined;
        *is_version_defined = FALSE;
+       if (!is_token_defined)
+               is_token_defined = &token_defined;
+       *is_token_defined = FALSE;
        
-       parts = tmp = g_strsplit (name, ",", 4);
+       parts = tmp = g_strsplit (name, ",", 6);
        if (!tmp || !*tmp) {
                g_strfreev (tmp);
                return FALSE;
@@ -1688,51 +1715,90 @@ mono_assembly_name_parse_full (const char *name, MonoAssemblyName *aname, gboole
                if (!g_ascii_strncasecmp (value, "Version=", 8)) {
                        *is_version_defined = TRUE;
                        version = g_strstrip (value + 8);
+                       if (strlen (version) == 0) {
+                               return FALSE;
+                       }
                        tmp++;
                        continue;
                }
 
                if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
                        culture = g_strstrip (value + 8);
+                       if (strlen (culture) == 0) {
+                               return FALSE;
+                       }
                        tmp++;
                        continue;
                }
 
                if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
+                       *is_token_defined = TRUE;
                        token = g_strstrip (value + 15);
+                       if (strlen (token) == 0) {
+                               return FALSE;
+                       }
                        tmp++;
                        continue;
                }
 
                if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) {
                        key = g_strstrip (value + 10);
+                       if (strlen (key) == 0) {
+                               return FALSE;
+                       }
                        tmp++;
                        continue;
                }
-               
+
+               if (!g_ascii_strncasecmp (value, "Retargetable=", 13)) {
+                       retargetable = g_strstrip (value + 13);
+                       if (strlen (retargetable) == 0) {
+                               return FALSE;
+                       }
+                       if (!g_ascii_strcasecmp (retargetable, "yes")) {
+                               flags |= ASSEMBLYREF_RETARGETABLE_FLAG;
+                       } else if (g_ascii_strcasecmp (retargetable, "no")) {
+                               return FALSE;
+                       }
+                       tmp++;
+                       continue;
+               }
+
+               if (!g_ascii_strncasecmp (value, "ProcessorArchitecture=", 22)) {
+                       /* this is ignored for now, until we can change MonoAssemblyName */
+                       tmp++;
+                       continue;
+               }
+
                g_strfreev (parts);
                return FALSE;
        }
 
-       res = build_assembly_name (dllname, version, culture, token, key, aname, save_public_key);
+       /* if retargetable flag is set, then we must have a fully qualified name */
+       if (retargetable != NULL && (version == NULL || culture == NULL || (key == NULL && token == NULL))) {
+               return FALSE;
+       }
+
+       res = build_assembly_name (dllname, version, culture, token, key, flags,
+               aname, save_public_key);
        g_strfreev (parts);
        return res;
 }
 
 /**
-* mono_assembly_name_parse:
-* @name: name to parse
-* @aname: the destination assembly name
-* 
-* Parses an assembly qualified type name and assigns the name,
-* version, culture and token to the provided assembly name object.
-*
-* Returns: true if the name could be parsed.
-*/
+ * mono_assembly_name_parse:
+ * @name: name to parse
+ * @aname: the destination assembly name
+ 
+ * Parses an assembly qualified type name and assigns the name,
+ * version, culture and token to the provided assembly name object.
+ *
+ * Returns: true if the name could be parsed.
+ */
 gboolean
 mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
 {
-       return mono_assembly_name_parse_full (name, aname, FALSE, NULL);
+       return mono_assembly_name_parse_full (name, aname, FALSE, NULL, NULL);
 }
 
 static MonoAssembly*
@@ -1754,13 +1820,14 @@ probe_for_partial_name (const char *basepath, const char *fullname, MonoAssembly
        while ((direntry = g_dir_read_name (dirhandle))) {
                gboolean match = TRUE;
                
-               parse_assembly_directory_name (aname->name, direntry, &gac_aname);
+               if(!parse_assembly_directory_name (aname->name, direntry, &gac_aname))
+                       continue;
                
                if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
                        match = FALSE;
                        
                if (match && strlen ((char*)aname->public_key_token) > 0 && 
-                               strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0)
+                               !mono_public_tokens_are_equal (aname->public_key_token, gac_aname.public_key_token))
                        match = FALSE;
                
                if (match) {
@@ -1864,7 +1931,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);
 
@@ -2026,6 +2099,7 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImag
        gchar *name, *version, *culture, *fullpath, *subpath;
        gint32 len;
        gchar **paths;
+       char *pubtok;
 
        if (aname->public_key_token [0] == 0) {
                return NULL;
@@ -2046,9 +2120,11 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname,  gchar *filename, MonoImag
                culture = g_strdup ("");
        }
 
+       pubtok = g_ascii_strdown ((char*)aname->public_key_token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
        version = g_strdup_printf ("%d.%d.%d.%d_%s_%s", aname->major,
                        aname->minor, aname->build, aname->revision,
-                       culture, aname->public_key_token);
+                       culture, pubtok);
+       g_free (pubtok);
        
        subpath = g_build_path (G_DIR_SEPARATOR_S, name, version, filename, NULL);
        g_free (name);
@@ -2117,24 +2193,11 @@ 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)
+mono_assembly_load_full_nosearch (MonoAssemblyName *aname, 
+                                                                 const char       *basedir, 
+                                                                 MonoImageOpenStatus *status,
+                                                                 gboolean refonly)
 {
        MonoAssembly *result;
        char *fullpath, *filename;
@@ -2202,9 +2265,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;
 }
 
@@ -2274,24 +2361,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);
@@ -2308,19 +2387,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
@@ -2353,9 +2427,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;