2006-05-31 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / appdomain.c
index ed3af6d366f0d8c4015295d5dd4788de32d85d2c..6efa0690bab61862c5cd21ae576ab9d556b492bb 100644 (file)
 #include <mono/metadata/socket-io.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/gc-internal.h>
+#include <mono/metadata/mono-gc.h>
 #include <mono/metadata/marshal.h>
+#include <mono/metadata/monitor.h>
 #include <mono/metadata/threadpool.h>
 #include <mono/utils/mono-uri.h>
+#include <mono/utils/mono-logger.h>
 
-#define MONO_CORLIB_VERSION 31
+#define MONO_CORLIB_VERSION 52
 
 CRITICAL_SECTION mono_delegate_section;
 
@@ -46,11 +49,15 @@ static MonoAssembly *
 mono_domain_assembly_search (MonoAssemblyName *aname,
                                                         gpointer user_data);
 
+static MonoAssembly *
+mono_domain_assembly_postload_search (MonoAssemblyName *aname,
+                                                                         gpointer user_data);
+
 static void
 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
 
 static void
-add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass);
+add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
 
 static void
 mono_domain_unload (MonoDomain *domain);
@@ -77,11 +84,16 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
        MonoString *arg;
        
        MONO_GC_PRE_INIT ();
+       mono_monitor_init ();
        mono_thread_pool_init ();
        mono_marshal_init ();
 
-       mono_install_assembly_preload_hook (mono_domain_assembly_preload, NULL);
-       mono_install_assembly_search_hook (mono_domain_assembly_search, NULL);
+       mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
+       mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
+       mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
+       mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
+       mono_install_assembly_postload_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
+       mono_install_assembly_postload_refonly_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
        mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
        mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
 
@@ -98,6 +110,7 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
 
        InitializeCriticalSection (&mono_delegate_section);
 
+       mono_thread_attach (domain);
        mono_context_init (domain);
        mono_context_set (domain->default_context);
 
@@ -171,7 +184,13 @@ mono_context_init (MonoDomain *domain)
        domain->default_context = context;
 }
 
-/* This must not be called while there are still running threads executing
+/**
+ * mono_runtime_cleanup:
+ * @domain: unused.
+ *
+ * Internal routine.
+ *
+ * This must not be called while there are still running threads executing
  * managed code.
  */
 void
@@ -182,7 +201,11 @@ mono_runtime_cleanup (MonoDomain *domain)
        /* This ends up calling any pending pending (for at most 2 seconds) */
        mono_gc_cleanup ();
 
+       mono_thread_cleanup ();
+
        mono_network_cleanup ();
+
+       mono_marshal_cleanup ();
 }
 
 static MonoDomainFunc quit_function = NULL;
@@ -200,12 +223,40 @@ mono_runtime_quit ()
                quit_function (mono_get_root_domain (), NULL);
 }
 
+/** 
+ * mono_runtime_set_shutting_down:
+ *
+ * Invoked by System.Environment.Exit to flag that the runtime
+ * is shutting down.
+ */
+void
+mono_runtime_set_shutting_down (void)
+{
+       shutting_down = TRUE;
+}
+
+/**
+ * mono_runtime_is_shutting_down:
+ *
+ * Returns whether the runtime has been flagged for shutdown.
+ *
+ * This is consumed by the P:System.Environment.HasShutdownStarted
+ * property.
+ *
+ */
 gboolean
 mono_runtime_is_shutting_down (void)
 {
        return shutting_down;
 }
 
+/**
+ * mono_domain_has_type_resolve:
+ * @domain: application domains being looked up
+ *
+ * Returns true if the AppDomain.TypeResolve field has been
+ * set.
+ */
 gboolean
 mono_domain_has_type_resolve (MonoDomain *domain)
 {
@@ -213,12 +264,7 @@ mono_domain_has_type_resolve (MonoDomain *domain)
        MonoObject *o;
 
        if (field == NULL) {
-               MonoClass *klass = mono_defaults.appdomain_class;
-               int i;
-
-               for (i = 0; i < klass->field.count; ++i)
-                       if (strcmp (klass->fields [i].name, "TypeResolve") == 0)
-                               field = &klass->fields [i];
+               field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
                g_assert (field);
        }
 
@@ -226,6 +272,19 @@ mono_domain_has_type_resolve (MonoDomain *domain)
        return o != NULL;
 }
 
+/**
+ * mono_domain_try_type_resolve:
+ * @domain: application domainwhere the name where the type is going to be resolved
+ * @name: the name of the type to resolve or NULL.
+ * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
+ *
+ * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
+ * the assembly that matches name.
+ *
+ * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
+ *
+ * Returns: A MonoReflectionAssembly or NULL if not found
+ */
 MonoReflectionAssembly *
 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
 {
@@ -253,12 +312,28 @@ mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
        return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
 }
 
+/**
+ * mono_domain_owns_vtable_slot:
+ *
+ *  Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
+ */
+gboolean
+mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
+{
+       gboolean res;
+
+       mono_domain_lock (domain);
+       res = mono_mempool_contains_addr (domain->mp, vtable_slot);
+       mono_domain_unlock (domain);
+       return res;
+}
+
 /**
  * mono_domain_set:
  * @domain: domain
  * @force: force setting.
  *
- *   Set the current appdomain to @domain. If @force is set, set it even
+ * Set the current appdomain to @domain. If @force is set, set it even
  * if it is being unloaded.
  *
  * Returns:
@@ -279,13 +354,15 @@ mono_domain_set (MonoDomain *domain, gboolean force)
 MonoObject *
 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
 {
-       MonoDomain *add = ad->data;
+       MonoDomain *add;
        MonoObject *o;
        char *str;
 
        MONO_ARCH_SAVE_REGS;
 
        g_assert (ad != NULL);
+       add = ad->data;
+       g_assert (add != NULL);
 
        if (name == NULL)
                mono_raise_exception (mono_get_exception_argument_null ("name"));
@@ -327,11 +404,13 @@ ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
 void
 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
 {
-       MonoDomain *add = ad->data;
+       MonoDomain *add;
 
        MONO_ARCH_SAVE_REGS;
 
        g_assert (ad != NULL);
+       add = ad->data;
+       g_assert (add != NULL);
 
        if (name == NULL)
                mono_raise_exception (mono_get_exception_argument_null ("name"));
@@ -376,19 +455,13 @@ ves_icall_System_AppDomain_getCurDomain ()
 }
 
 MonoAppDomain *
-ves_icall_System_AppDomain_getDomainByID (gint32 domain_id)
+ves_icall_System_AppDomain_getRootDomain ()
 {
-       MonoDomain *add = mono_domain_get_by_id (domain_id);
+       MonoDomain *root = mono_get_root_domain ();
 
        MONO_ARCH_SAVE_REGS;
 
-       return ((add == NULL) ? NULL : add->domain);
-}
-
-static void
-add_assembly_to_domain (gpointer key, gpointer value, gpointer user_data)
-{
-       add_assemblies_to_domain ((MonoDomain*)user_data, (MonoAssembly*)value);
+       return root->domain;
 }
 
 MonoAppDomain *
@@ -398,6 +471,7 @@ ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomai
        MonoClass *adclass;
        MonoAppDomain *ad;
        MonoDomain *data;
+       GSList *tmp;
        
        MONO_ARCH_SAVE_REGS;
 
@@ -416,52 +490,31 @@ ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomai
        if (!setup->application_base) {
                /* Inherit from the root domain since MS.NET does this */
                MonoDomain *root = mono_get_root_domain ();
-               setup->application_base = mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base));
+               if (root->setup->application_base)
+                       MONO_OBJECT_SETREF (setup, application_base, mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base)));
        }
 
        mono_context_init (data);
 
        /* The new appdomain should have all assemblies loaded */
-       mono_domain_lock (domain);
-       g_hash_table_foreach (domain->assemblies_by_name, add_assembly_to_domain, data);
-       mono_domain_unlock (domain);
+       mono_domain_assemblies_lock (domain);
+       /*g_print ("copy assemblies from domain %p (%s)\n", domain, domain->friendly_name);*/
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next)
+               add_assemblies_to_domain (data, tmp->data, NULL);
+       mono_domain_assemblies_unlock (domain);
 
        return ad;
 }
 
-typedef struct {
-       MonoArray *res;
-       MonoDomain *domain;
-       int idx, len;
-} add_assembly_helper_t;
-
-static void
-filter_assembly (gpointer key, gpointer value, gpointer user_data)
-{
-       add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
-       MonoAssembly *ass = (MonoAssembly*)value;
-
-       if (!ass->corlib_internal)
-               ah->len ++;
-}
-
-static void
-add_assembly (gpointer key, gpointer value, gpointer user_data)
-{
-       add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
-       MonoAssembly *ass = (MonoAssembly*)value;
-
-       if (!ass->corlib_internal)
-               mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, ass));
-}
-
 MonoArray *
-ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
+ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
 {
        MonoDomain *domain = ad->data; 
+       MonoAssembly* ass;
        static MonoClass *System_Reflection_Assembly;
        MonoArray *res;
-       add_assembly_helper_t ah;
+       GSList *tmp;
+       int i, count;
        
        MONO_ARCH_SAVE_REGS;
 
@@ -469,31 +522,39 @@ ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
                System_Reflection_Assembly = mono_class_from_name (
                        mono_defaults.corlib, "System.Reflection", "Assembly");
 
-       ah.domain = domain;
-       ah.idx = 0;
-       ah.len = 0;
-
+       count = 0;
        /* Need to skip internal assembly builders created by remoting */
-       mono_domain_lock (domain);
-       g_hash_table_foreach (domain->assemblies_by_name, filter_assembly, &ah);
-       mono_domain_unlock (domain);
-
-       res = mono_array_new (domain, System_Reflection_Assembly, ah.len);
-       ah.res = res;
-
-       mono_domain_lock (domain);
-       g_hash_table_foreach (domain->assemblies_by_name, add_assembly, &ah);
-       mono_domain_unlock (domain);
+       mono_domain_assemblies_lock (domain);
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
+               ass = tmp->data;
+               if (refonly && !ass->ref_only)
+                       continue;
+               if (!ass->corlib_internal)
+                       count++;
+       }
+       res = mono_array_new (domain, System_Reflection_Assembly, count);
+       i = 0;
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
+               ass = tmp->data;
+               if (refonly && !ass->ref_only)
+                       continue;
+               if (ass->corlib_internal)
+                       continue;
+               mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
+               ++i;
+       }
+       mono_domain_assemblies_unlock (domain);
 
        return res;
 }
 
 static MonoReflectionAssembly *
-try_assembly_resolve (MonoDomain *domain, MonoString *fname)
+try_assembly_resolve (MonoDomain *domain, MonoString *fname, gboolean refonly)
 {
        MonoClass *klass;
        MonoMethod *method;
-       void *params [1];
+       MonoBoolean isrefonly;
+       gpointer params [2];
 
        g_assert (domain != NULL && fname != NULL);
 
@@ -506,58 +567,116 @@ try_assembly_resolve (MonoDomain *domain, MonoString *fname)
                return NULL;
        }
 
-       *params = fname;
+       isrefonly = refonly ? 1 : 0;
+       params [0] = fname;
+       params [1] = &isrefonly;
        return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
 }
 
+static MonoAssembly *
+mono_domain_assembly_postload_search (MonoAssemblyName *aname,
+                                                                         gpointer user_data)
+{
+       gboolean refonly = GPOINTER_TO_UINT (user_data);
+       MonoReflectionAssembly *assembly;
+       MonoDomain *domain = mono_domain_get ();
+       char *aname_str;
+
+       aname_str = mono_stringify_assembly_name (aname);
+
+       /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
+       assembly = try_assembly_resolve (domain, mono_string_new (domain, aname_str), refonly);
+
+       g_free (aname_str);
+
+       if (assembly)
+               return assembly->assembly;
+       else
+               return NULL;
+}
+       
+/*
+ * LOCKING: assumes assemblies_lock in the domain is already locked.
+ */
 static void
-add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass)
+add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
 {
        gint i;
+       GSList *tmp;
+       gboolean destroy_ht = FALSE;
 
        if (!ass->aname.name)
                return;
 
-       mono_domain_lock (domain);
-
-       if (g_hash_table_lookup (domain->assemblies_by_name, ass->aname.name)) {
-               mono_domain_unlock (domain);
-               return; /* This is ok while no lazy loading of assemblies */
+       if (!ht) {
+               ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
+               destroy_ht = TRUE;
        }
 
-       g_hash_table_insert (domain->assemblies_by_name, (gpointer) ass->aname.name, ass);
-       domain->assemblies = g_list_prepend (domain->assemblies, ass);
-       mono_domain_unlock (domain);
+       /* FIXME: handle lazy loaded assemblies */
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
+               g_hash_table_insert (ht, tmp->data, tmp->data);
+       }
+       if (!g_hash_table_lookup (ht, ass)) {
+               mono_assembly_addref (ass);
+               g_hash_table_insert (ht, ass, ass);
+               domain->domain_assemblies = g_slist_prepend (domain->domain_assemblies, ass);
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s %p added to domain %s, ref_count=%d\n", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
+       }
 
-       if (ass->image->references)
-               for (i = 0; ass->image->references [i] != NULL; i++)
-                       add_assemblies_to_domain (domain, ass->image->references [i]);
+       if (ass->image->references) {
+               for (i = 0; ass->image->references [i] != NULL; i++) {
+                       if (!g_hash_table_lookup (ht, ass->image->references [i])) {
+                               add_assemblies_to_domain (domain, ass->image->references [i], ht);
+                       }
+               }
+       }
+       if (destroy_ht)
+               g_hash_table_destroy (ht);
 }
 
 static void
 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
 {
+       static MonoClassField *assembly_load_field;
+       static MonoMethod *assembly_load_method;
        MonoDomain *domain = mono_domain_get ();
        MonoReflectionAssembly *ref_assembly;
        MonoClass *klass;
-       MonoMethod *method;
+       gpointer load_value;
        void *params [1];
 
+       if (!domain->domain)
+               /* This can happen during startup */
+               return;
+
        klass = domain->domain->mbr.obj.vtable->klass;
 
-       method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
-       if (method == NULL) {
-               g_warning ("Method AppDomain.DoAssemblyLoad not found.\n");
-               return;
+       mono_domain_assemblies_lock (domain);
+       add_assemblies_to_domain (domain, assembly, NULL);
+       mono_domain_assemblies_unlock (domain);
+
+       if (assembly_load_field == NULL) {
+               assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
+               g_assert (assembly_load_field);
        }
 
-       add_assemblies_to_domain (domain, assembly);
+       mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
+       if (load_value == NULL) {
+               /* No events waiting to be triggered */
+               return;
+       }
 
        ref_assembly = mono_assembly_get_object (domain, assembly);
        g_assert (ref_assembly);
 
+       if (assembly_load_method == NULL) {
+               assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
+               g_assert (assembly_load_method);
+       }
+
        *params = ref_assembly;
-       mono_runtime_invoke (method, domain->domain, params, NULL);
+       mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
 }
 
 static gchar *
@@ -624,6 +743,8 @@ set_domain_search_path (MonoDomain *domain)
 
        if ((domain->search_path != NULL) && !domain->setup->path_changed)
                return;
+       if (!domain->setup)
+               return;
 
        setup = domain->setup;
        if (!setup->application_base)
@@ -724,21 +845,21 @@ set_domain_search_path (MonoDomain *domain)
 
 static gboolean
 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
-                                       const gchar *path3, const gchar *path4)
+                                       const gchar *path3, const gchar *path4, gboolean refonly)
 {
        gchar *fullpath;
 
        *assembly = NULL;
        fullpath = g_build_filename (path1, path2, path3, path4, NULL);
        if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
-               *assembly = mono_assembly_open (fullpath, NULL);
+               *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
 
        g_free (fullpath);
        return (*assembly != NULL);
 }
 
 static MonoAssembly *
-real_load (gchar **search_path, const gchar *culture, const gchar *name)
+real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
 {
        MonoAssembly *result = NULL;
        gchar **path;
@@ -762,22 +883,22 @@ real_load (gchar **search_path, const gchar *culture, const gchar *name)
                /* See test cases in bug #58992 and bug #57710 */
                /* 1st try: [culture]/[name].dll (culture may be empty) */
                strcpy (filename + len - 4, ".dll");
-               if (try_load_from (&result, *path, local_culture, "", filename))
+               if (try_load_from (&result, *path, local_culture, "", filename, refonly))
                        break;
 
                /* 2nd try: [culture]/[name].exe (culture may be empty) */
                strcpy (filename + len - 4, ".exe");
-               if (try_load_from (&result, *path, local_culture, "", filename))
+               if (try_load_from (&result, *path, local_culture, "", filename, refonly))
                        break;
 
                /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
                strcpy (filename + len - 4, ".dll");
-               if (try_load_from (&result, *path, local_culture, name, filename))
+               if (try_load_from (&result, *path, local_culture, name, filename, refonly))
                        break;
 
                /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
                strcpy (filename + len - 4, ".exe");
-               if (try_load_from (&result, *path, local_culture, name, filename))
+               if (try_load_from (&result, *path, local_culture, name, filename, refonly))
                        break;
        }
 
@@ -796,15 +917,16 @@ mono_domain_assembly_preload (MonoAssemblyName *aname,
 {
        MonoDomain *domain = mono_domain_get ();
        MonoAssembly *result = NULL;
+       gboolean refonly = GPOINTER_TO_UINT (user_data);
 
        set_domain_search_path (domain);
 
        if (domain->search_path && domain->search_path [0] != NULL) {
-               result = real_load (domain->search_path, aname->culture, aname->name);
+               result = real_load (domain->search_path, aname->culture, aname->name, refonly);
        }
 
        if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
-               result = real_load (assemblies_path, aname->culture, aname->name);
+               result = real_load (assemblies_path, aname->culture, aname->name, refonly);
        }
 
        return result;
@@ -818,26 +940,27 @@ mono_domain_assembly_search (MonoAssemblyName *aname,
                                                         gpointer user_data)
 {
        MonoDomain *domain = mono_domain_get ();
-       GList *tmp;
+       GSList *tmp;
        MonoAssembly *ass;
+       gboolean refonly = GPOINTER_TO_UINT (user_data);
 
-       mono_domain_lock (domain);
-       for (tmp = domain->assemblies; tmp; tmp = tmp->next) {
+       mono_domain_assemblies_lock (domain);
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
                ass = tmp->data;
                /* Dynamic assemblies can't match here in MS.NET */
-               if (ass->dynamic || !mono_assembly_names_equal (aname, &ass->aname))
+               if (ass->dynamic || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
                        continue;
 
-               mono_domain_unlock (domain);
+               mono_domain_assemblies_unlock (domain);
                return ass;
        }
-       mono_domain_unlock (domain);
+       mono_domain_assemblies_unlock (domain);
 
        return NULL;
 }
 
 MonoReflectionAssembly *
-ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
+ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
 {
        MonoDomain *domain = mono_domain_get ();
        char *name, *filename;
@@ -853,118 +976,36 @@ ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
                
        name = filename = mono_string_to_utf8 (fname);
 
-       ass = mono_assembly_open (filename, &status);
+       ass = mono_assembly_open_full (filename, &status, refOnly);
        
-       g_free (name);
-
        if (!ass){
-               MonoException *exc = mono_get_exception_file_not_found (fname);
+               MonoException *exc;
+
+               if (status == MONO_IMAGE_IMAGE_INVALID)
+                       exc = mono_get_exception_bad_image_format (name);
+               else
+                       exc = mono_get_exception_file_not_found (fname);
+               g_free (name);
                mono_raise_exception (exc);
        }
 
-       return mono_assembly_get_object (domain, ass);
-}
-
-static void
-free_assembly_name (MonoAssemblyName *aname)
-{
-       if (aname == NULL)
-               return;
-
-       g_free ((void *) aname->name);
-       g_free ((void *) aname->culture);
-       g_free ((void *) aname->hash_value);
-}
-
-static gboolean
-get_info_from_assembly_name (MonoString *assRef, MonoAssemblyName *aname)
-{
-       gchar *name;
-       gchar *value;
-       gchar **parts;
-       gchar **tmp;
-       gint major, minor, build, revision;
-
-       memset (aname, 0, sizeof (MonoAssemblyName));
-
-       name = mono_string_to_utf8 (assRef);
-       parts = tmp = g_strsplit (name, ",", 4);
        g_free (name);
-       if (!tmp || !*tmp) {
-               g_strfreev (tmp);
-               return FALSE;
-       }
-
-       value = g_strstrip (*tmp);
-       /* g_print ("Assembly name: %s\n", value); */
-       aname->name = g_strdup (value);
-       tmp++;
-       if (!*tmp) {
-               g_strfreev (parts);
-               return TRUE;
-       }
-
-       while (*tmp) {
-               value = g_strstrip (*tmp);
-               if (!g_ascii_strncasecmp (value, "Version=", 8)) {
-                       if (sscanf (value + 8, "%u.%u.%u.%u",
-                                   &major, &minor, &build, &revision) != 4) {
-                               g_strfreev (parts);
-                               return FALSE;
-                       }
-                       /* g_print ("Version: %u.%u.%u.%u\n", major, minor, build, revision); */
-                       aname->major = major;
-                       aname->minor = minor;
-                       aname->build = build;
-                       aname->revision = revision;
-                       tmp++;
-                       continue;
-               }
-
-               if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
-                       gchar *t = g_strdup (value + 8);
-                       g_strchug (t);
-                       aname->culture = g_strdup (g_strchomp (t));
-                       tmp++;
-                       g_free (t);
-                       if (g_strcasecmp (aname->culture, "neutral") == 0) {
-                               g_free ((void *) aname->culture);
-                               aname->culture = g_strdup ("");
-                       }
-                       continue;
-               }
-
-               if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
-                       tmp++;
-                       value += 15;
-                       if (*value && strncmp (value, "null", 4)) {
-                               gchar *t = g_strdup (value);
-                               g_strchug (t);
-                               g_strlcpy (aname->public_key_token, g_strchomp (value), MONO_PUBLIC_KEY_TOKEN_LENGTH);
-                               g_free (t);
-                       }
-                       continue;
-               }
 
-               g_strfreev (parts);
-               return FALSE;
-       }
-
-       g_strfreev (parts);
-       return TRUE;
+       return mono_assembly_get_object (domain, ass);
 }
 
 MonoReflectionAssembly *
 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
                                                                                        MonoArray *raw_assembly,
-                                                                                       MonoArray *raw_symbol_store, MonoObject *evidence)
+                                                                                       MonoArray *raw_symbol_store, MonoObject *evidence,
+                                                                                       MonoBoolean refonly)
 {
        MonoAssembly *ass;
        MonoReflectionAssembly *refass = NULL;
        MonoDomain *domain = ad->data;
        MonoImageOpenStatus status;
        guint32 raw_assembly_len = mono_array_length (raw_assembly);
-       MonoImage *image = mono_image_open_from_data (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL);
+       MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
 
        if (raw_symbol_store)
                mono_raise_exception (mono_get_exception_not_implemented ("LoadAssemblyRaw: Raw Symbol Store not Implemented"));
@@ -974,7 +1015,7 @@ ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
                return NULL;
        }
 
-       ass = mono_assembly_load_from (image, "", &status);
+       ass = mono_assembly_load_from_full (image, "", &status, refonly);
 
        if (!ass) {
                mono_image_close (image);
@@ -983,36 +1024,41 @@ ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
        }
 
        refass = mono_assembly_get_object (domain, ass);
-       refass->evidence = evidence;
+       MONO_OBJECT_SETREF (refass, evidence, evidence);
        return refass;
 }
 
 MonoReflectionAssembly *
-ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence)
+ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
 {
        MonoDomain *domain = ad->data; 
        MonoImageOpenStatus status = MONO_IMAGE_OK;
        MonoAssembly *ass;
        MonoAssemblyName aname;
        MonoReflectionAssembly *refass = NULL;
+       gchar *name;
+       gboolean parsed;
 
        MONO_ARCH_SAVE_REGS;
 
        g_assert (assRef != NULL);
 
-       if (!get_info_from_assembly_name (assRef, &aname)) {
+       name = mono_string_to_utf8 (assRef);
+       parsed = mono_assembly_name_parse (name, &aname);
+       g_free (name);
+
+       if (!parsed) {
                MonoException *exc;
 
-               free_assembly_name (&aname);
                /* This is a parse error... */
                exc = mono_get_exception_file_not_found (assRef);
                mono_raise_exception (exc);
        }
 
-       ass = mono_assembly_load (&aname, NULL, &status);
-       free_assembly_name (&aname);
+       ass = mono_assembly_load_full (&aname, NULL, &status, refOnly);
+       mono_assembly_name_free (&aname);
 
-       if (!ass && (refass = try_assembly_resolve (domain, assRef)) == NULL){
+       if (!ass && (refass = try_assembly_resolve (domain, assRef, refOnly)) == NULL){
                /* FIXME: it doesn't make much sense since we really don't have a filename ... */
                MonoException *exc = mono_get_exception_file_not_found (assRef);
                mono_raise_exception (exc);
@@ -1021,7 +1067,7 @@ ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef,
        if (refass == NULL)
                refass = mono_assembly_get_object (domain, ass);
 
-       refass->evidence = evidence;
+       MONO_OBJECT_SETREF (refass, evidence, evidence);
        return refass;
 }
 
@@ -1094,7 +1140,7 @@ ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file,
                args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
 
        refass = mono_assembly_get_object (ad->data, assembly);
-       refass->evidence = evidence;
+       MONO_OBJECT_SETREF (refass, evidence, evidence);
 
        res = mono_runtime_exec_main (method, (MonoArray *)args, NULL);
 
@@ -1226,11 +1272,11 @@ clear_cached_vtable (gpointer key, gpointer value, gpointer user_data)
 {
        MonoClass *klass = (MonoClass*)key;
        MonoDomain *domain = (MonoDomain*)user_data;
-       MonoVTable *vt;
+       MonoClassRuntimeInfo *runtime_info;
 
-       vt = klass->cached_vtable;
-       if (vt && vt->domain == domain)
-               klass->cached_vtable = NULL;
+       runtime_info = klass->runtime_info;
+       if (runtime_info && runtime_info->max_domain >= domain->domain_id)
+               runtime_info->domain_vtables [domain->domain_id] = NULL;
 }
 
 typedef struct unload_data {
@@ -1238,7 +1284,7 @@ typedef struct unload_data {
        char *failure_reason;
 } unload_data;
 
-static guint32
+static guint32 WINAPI
 unload_thread_main (void *arg)
 {
        unload_data *data = (unload_data*)arg;
@@ -1259,30 +1305,36 @@ unload_thread_main (void *arg)
                return 1;
        }
 
-       /* Clear references to our vtables in class->cached_vtable */
+       /* Clear references to our vtables in class->runtime_info.
+        * We also hold the loader lock because we're going to change
+        * class->runtime_info.
+        */
        mono_domain_lock (domain);
-       mono_g_hash_table_foreach (domain->class_vtable_hash, clear_cached_vtable,
-                                                          domain);
+       mono_loader_lock ();
+       g_hash_table_foreach (domain->class_vtable_hash, clear_cached_vtable, domain);
+       mono_loader_unlock ();
        mono_domain_unlock (domain);
 
+       mono_threads_clear_cached_culture (domain);
+
        domain->state = MONO_APPDOMAIN_UNLOADED;
 
        /* printf ("UNLOADED %s.\n", domain->friendly_name); */
 
        mono_domain_free (domain, FALSE);
 
-#ifdef HAVE_BOEHM_GC
-       GC_gcollect ();
-#endif
+       mono_gc_collect (mono_gc_max_generation ());
 
        return 0;
 }
 
 /*
  * mono_domain_unload:
+ * @domain: The domain to unload
  *
  *  Unloads an appdomain. Follows the process outlined in:
  *  http://blogs.gotdotnet.com/cbrumme
+ *
  *  If doing things the 'right' way is too hard or complex, we do it the 
  *  'simple' way, which means do everything needed to avoid crashes and
  *  memory leaks, but not much else.
@@ -1291,7 +1343,8 @@ static void
 mono_domain_unload (MonoDomain *domain)
 {
        HANDLE thread_handle;
-       guint32 tid, res;
+       gsize tid;
+       guint32 res;
        MonoAppDomainState prev_state;
        MonoMethod *method;
        MonoObject *exc;
@@ -1301,7 +1354,7 @@ mono_domain_unload (MonoDomain *domain)
        /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
 
        /* Atomically change our state to UNLOADING */
-       prev_state = InterlockedCompareExchange (&domain->state,
+       prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
                                                                                         MONO_APPDOMAIN_UNLOADING,
                                                                                         MONO_APPDOMAIN_CREATED);
        if (prev_state != MONO_APPDOMAIN_CREATED) {
@@ -1343,11 +1396,7 @@ mono_domain_unload (MonoDomain *domain)
 #if 0
        thread_handle = CreateThread (NULL, 0, unload_thread_main, &thread_data, 0, &tid);
 #else
-#if defined(PLATFORM_WIN32) && defined (HAVE_BOEHM_GC)
-       thread_handle = GC_CreateThread (NULL, 0, unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid);
-#else
-       thread_handle = CreateThread (NULL, 0, unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid);
-#endif
+       thread_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid);
        ResumeThread (thread_handle);
 #endif
 
@@ -1369,10 +1418,11 @@ mono_domain_unload (MonoDomain *domain)
 
                g_warning (thread_data.failure_reason);
 
-               g_free (thread_data.failure_reason);
-
                ex = mono_get_exception_cannot_unload_appdomain (thread_data.failure_reason);
 
+               g_free (thread_data.failure_reason);
+               thread_data.failure_reason = NULL;
+
                mono_raise_exception (ex);
        }
 }