2008-07-11 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / appdomain.c
index 20e4521e7b6df8e4fe084c594a4d8da85277af30..a57df66f8b6d1710c68312580d9f9af4746df655 100644 (file)
 #include <config.h>
 #include <glib.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#else
+#ifdef HAVE_SYS_UTIME_H
+#include <sys/utime.h>
+#endif
+#endif
 
-#include <mono/os/gc_wrapper.h>
-
+#include <mono/metadata/gc-internal.h>
 #include <mono/metadata/object.h>
 #include <mono/metadata/domain-internals.h>
 #include "mono/metadata/metadata-internals.h"
 #include <mono/utils/mono-logger.h>
 #include <mono/utils/mono-path.h>
 #include <mono/utils/mono-stdlib.h>
+#include <mono/utils/mono-io-portability.h>
+#ifdef PLATFORM_WIN32
+#include <direct.h>
+#endif
 
-#define MONO_CORLIB_VERSION 54
+/*
+ * This is the version number of the corlib-runtime interface. When
+ * making changes to this interface (by changing the layout
+ * of classes the runtime knows about, changing icall signature or
+ * semantics etc), increment this variable. Also increment the
+ * pair of this variable in mscorlib in:
+ *       mcs/class/mscorlib/System/Environment.cs
+ *
+ * Changes which are already detected at runtime, like the addition
+ * of icalls, do not require an increment.
+ */
+#define MONO_CORLIB_VERSION 68
+
+typedef struct
+{
+       int runtime_count;
+       int assemblybinding_count;
+       MonoDomain *domain;
+} RuntimeConfig;
 
 CRITICAL_SECTION mono_delegate_section;
 
@@ -66,6 +99,21 @@ add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *has
 static void
 mono_domain_unload (MonoDomain *domain);
 
+static MonoLoadFunc load_function = NULL;
+
+void
+mono_install_runtime_load (MonoLoadFunc func)
+{
+       load_function = func;
+}
+
+MonoDomain*
+mono_runtime_load (const char *filename, const char *runtime_version)
+{
+       g_assert (load_function);
+       return load_function (filename, runtime_version);
+}
+
 /**
  * mono_runtime_init:
  * @domain: domain returned by mono_init ()
@@ -86,8 +134,10 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
        MonoAppDomain *ad;
        MonoClass *class;
        MonoString *arg;
+
+       mono_portability_helpers_init ();
        
-       MONO_GC_PRE_INIT ();
+       mono_gc_base_init ();
        mono_monitor_init ();
        mono_thread_pool_init ();
        mono_marshal_init ();
@@ -143,7 +193,7 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
 
        /* mscorlib is loaded before we install the load hook */
        mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
-
+       
        return;
 }
 
@@ -214,6 +264,10 @@ mono_runtime_cleanup (MonoDomain *domain)
        mono_type_initialization_cleanup ();
 
        mono_monitor_cleanup ();
+
+#ifndef PLATFORM_WIN32
+       _wapi_cleanup ();
+#endif
 }
 
 static MonoDomainFunc quit_function = NULL;
@@ -472,6 +526,111 @@ ves_icall_System_AppDomain_getRootDomain ()
        return root->domain;
 }
 
+static char*
+get_attribute_value (const gchar **attribute_names, 
+                    const gchar **attribute_values, 
+                    const char *att_name)
+{
+       int n;
+       for (n = 0; attribute_names [n] != NULL; n++) {
+               if (strcmp (attribute_names [n], att_name) == 0)
+                       return g_strdup (attribute_values [n]);
+       }
+       return NULL;
+}
+
+static void
+start_element (GMarkupParseContext *context, 
+              const gchar         *element_name,
+              const gchar        **attribute_names,
+              const gchar        **attribute_values,
+              gpointer             user_data,
+              GError             **error)
+{
+       RuntimeConfig *runtime_config = user_data;
+       
+       if (strcmp (element_name, "runtime") == 0) {
+               runtime_config->runtime_count++;
+               return;
+       }
+
+       if (strcmp (element_name, "assemblyBinding") == 0) {
+               runtime_config->assemblybinding_count++;
+               return;
+       }
+       
+       if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
+               return;
+
+       if (strcmp (element_name, "probing") != 0)
+               return;
+
+       g_free (runtime_config->domain->private_bin_path);
+       runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
+       if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
+               g_free (runtime_config->domain->private_bin_path);
+               runtime_config->domain->private_bin_path = NULL;
+               return;
+       }
+}
+
+static void
+end_element (GMarkupParseContext *context,
+            const gchar         *element_name,
+            gpointer             user_data,
+            GError             **error)
+{
+       RuntimeConfig *runtime_config = user_data;
+       if (strcmp (element_name, "runtime") == 0)
+               runtime_config->runtime_count--;
+       else if (strcmp (element_name, "assemblyBinding") == 0)
+               runtime_config->assemblybinding_count--;
+}
+
+static const GMarkupParser
+mono_parser = {
+       start_element,
+       end_element,
+       NULL,
+       NULL,
+       NULL
+};
+
+static void
+mono_set_private_bin_path_from_config (MonoDomain *domain)
+{
+       gchar *config_file, *text;
+       gsize len;
+       struct stat sbuf;
+       GMarkupParseContext *context;
+       RuntimeConfig runtime_config;
+       
+       if (!domain || !domain->setup || !domain->setup->configuration_file)
+               return;
+
+       config_file = mono_string_to_utf8 (domain->setup->configuration_file);
+       if (stat (config_file, &sbuf) != 0) {
+               g_free (config_file);
+               return;
+       }
+
+       if (!g_file_get_contents (config_file, &text, &len, NULL)) {
+               g_free (config_file);
+               return;
+       }
+       g_free (config_file);
+
+       runtime_config.runtime_count = 0;
+       runtime_config.assemblybinding_count = 0;
+       runtime_config.domain = domain;
+       
+       context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
+       if (g_markup_parse_context_parse (context, text, len, NULL))
+               g_markup_parse_context_end_parse (context, NULL);
+       g_markup_parse_context_free (context);
+       g_free (text);
+}
+
 MonoAppDomain *
 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
 {
@@ -491,6 +650,8 @@ ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomai
        data->domain = ad;
        data->setup = setup;
        data->friendly_name = mono_string_to_utf8 (friendly_name);
+       // FIXME: The ctor runs in the current domain
+       // FIXME: Initialize null_reference_ex and stack_overflow_ex
        data->out_of_memory_ex = mono_exception_from_name_domain (data, mono_defaults.corlib, "System", "OutOfMemoryException");
 
        if (!setup->application_base) {
@@ -500,6 +661,8 @@ ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomai
                        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_set_private_bin_path_from_config (data);
+       
        mono_context_init (data);
 
        add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
@@ -515,42 +678,45 @@ ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly
        static MonoClass *System_Reflection_Assembly;
        MonoArray *res;
        GSList *tmp;
-       int i, count;
-       
+       int i;
+       GPtrArray *assemblies;
+
        MONO_ARCH_SAVE_REGS;
 
        if (!System_Reflection_Assembly)
                System_Reflection_Assembly = mono_class_from_name (
                        mono_defaults.corlib, "System.Reflection", "Assembly");
 
-       count = 0;
+       /* 
+        * Make a copy of the list of assemblies because we can't hold the assemblies
+        * lock while creating objects etc.
+        */
+       assemblies = g_ptr_array_new ();
        /* Need to skip internal assembly builders created by remoting */
        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;
+               g_ptr_array_add (assemblies, ass);
        }
        mono_domain_assemblies_unlock (domain);
 
+       res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
+       for (i = 0; i < assemblies->len; ++i) {
+               ass = g_ptr_array_index (assemblies, i);
+               mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
+       }
+
+       g_ptr_array_free (assemblies, TRUE);
+
        return res;
 }
 
-static MonoReflectionAssembly *
-try_assembly_resolve (MonoDomain *domain, MonoString *fname, gboolean refonly)
+MonoReflectionAssembly *
+mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, gboolean refonly)
 {
        MonoClass *klass;
        MonoMethod *method;
@@ -586,7 +752,7 @@ mono_domain_assembly_postload_search (MonoAssemblyName *aname,
        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);
+       assembly = mono_try_assembly_resolve (domain, mono_string_new (domain, aname_str), refonly);
 
        g_free (aname_str);
 
@@ -627,9 +793,10 @@ add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
 
        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 (ass->image->references [i] != REFERENCE_MISSING)
+                               if (!g_hash_table_lookup (ht, ass->image->references [i])) {
+                                       add_assemblies_to_domain (domain, ass->image->references [i], ht);
+                               }
                }
        }
        if (destroy_ht)
@@ -682,32 +849,80 @@ mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
        mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
 }
 
+/*
+ * LOCKING: Acquires the domain assemblies lock.
+ */
 static void
 set_domain_search_path (MonoDomain *domain)
 {
        MonoAppDomainSetup *setup;
        gchar **tmp;
-       gchar *utf8;
+       gchar *search_path = NULL;
        gint i;
        gint npaths = 0;
        gchar **pvt_split = NULL;
        GError *error = NULL;
        gint appbaselen = -1;
 
-       if ((domain->search_path != NULL) && !domain->setup->path_changed)
+       /* 
+        * We use the low-level domain assemblies lock, since this is called from
+        * assembly loads hooks, which means this thread might hold the loader lock.
+        */
+       mono_domain_assemblies_lock (domain);
+
+       if ((domain->search_path != NULL) && !domain->setup->path_changed) {
+               mono_domain_assemblies_unlock (domain);
                return;
-       if (!domain->setup)
+       }
+       if (!domain->setup) {
+               mono_domain_assemblies_unlock (domain);
                return;
+       }
 
        setup = domain->setup;
-       if (!setup->application_base)
+       if (!setup->application_base) {
+               mono_domain_assemblies_unlock (domain);
                return; /* Must set application base to get private path working */
+       }
 
        npaths++;
-       if (setup->private_bin_path) {
-               utf8 = mono_string_to_utf8 (setup->private_bin_path);
-               pvt_split = g_strsplit (utf8, G_SEARCHPATH_SEPARATOR_S, 1000);
-               g_free (utf8);
+       
+       if (setup->private_bin_path)
+               search_path = mono_string_to_utf8 (setup->private_bin_path);
+       
+       if (domain->private_bin_path) {
+               if (search_path == NULL)
+                       search_path = domain->private_bin_path;
+               else {
+                       gchar *tmp2 = search_path;
+                       search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
+                       g_free (tmp2);
+               }
+       }
+       
+       if (search_path) {
+               /*
+                * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
+                * directories relative to ApplicationBase separated by semicolons (see
+                * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
+                * The loop below copes with the fact that some Unix applications may use ':' (or
+                * System.IO.Path.PathSeparator) as the path search separator. We replace it with
+                * ';' for the subsequent split.
+                *
+                * The issue was reported in bug #81446
+                */
+
+#ifndef PLATFORM_WIN32
+               gint slen;
+
+               slen = strlen (search_path);
+               for (i = 0; i < slen; i++)
+                       if (search_path [i] == ':')
+                               search_path [i] = ';';
+#endif
+               
+               pvt_split = g_strsplit (search_path, ";", 1000);
+               g_free (search_path);
                for (tmp = pvt_split; *tmp; tmp++, npaths++);
        }
 
@@ -721,6 +936,7 @@ set_domain_search_path (MonoDomain *domain)
                 * domain->search_path = g_malloc (sizeof (char *));
                 * domain->search_path [0] = NULL;
                */
+               mono_domain_assemblies_unlock (domain);
                return;
        }
 
@@ -794,43 +1010,280 @@ set_domain_search_path (MonoDomain *domain)
        domain->setup->path_changed = FALSE;
 
        g_strfreev (pvt_split);
+
+       mono_domain_assemblies_unlock (domain);
 }
 
-static char *
-make_shadow_copy (const char *filename)
+static gboolean
+shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
 {
-       gchar *tmp;
        guint16 *orig, *dest;
+       gboolean copy_result;
+       
+       strcpy (src + srclen - tail_len, extension);
+       if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
+               return TRUE;
+       orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
+
+       strcpy (target + targetlen - tail_len, extension);
+       dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
+       
+       DeleteFile (dest);
+       copy_result = CopyFile (orig, dest, FALSE);
+       g_free (orig);
+       g_free (dest);
+       
+       return copy_result;
+}
+
+static gint32 
+get_cstring_hash (const char *str)
+{
+       int len, i;
+       const char *p;
+       gint32 h = 0;
+       
+       if (!str || !str [0])
+               return 0;
+               
+       len = strlen (str);
+       p = str;
+       for (i = 0; i < len; i++) {
+               h = (h << 5) - h + *p;
+               p++;
+       }
+       
+       return h;
+}
+
+static char *
+get_shadow_assembly_location (const char *filename)
+{
+       gint32 hash = 0, hash2 = 0;
+       char name_hash [9];
+       char path_hash [30];
+       char *bname = g_path_get_basename (filename);
+       char *dirname = g_path_get_dirname (filename);
+       char *location, *dyn_base;
        MonoDomain *domain = mono_domain_get ();
-       char *db;
-       int fd;
+       
+       hash = get_cstring_hash (bname);
+       hash2 = get_cstring_hash (dirname);
+       g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
+       g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
+       dyn_base = mono_string_to_utf8 (domain->setup->dynamic_base);
+       location = g_build_filename (dyn_base, "assembly", "shadow", name_hash, path_hash, bname, NULL);
+       g_free (dyn_base);
+       g_free (bname);
+       g_free (dirname);
+       return location;
+}
+
+static gboolean
+ensure_directory_exists (const char *filename)
+{
+#ifdef PLATFORM_WIN32
+       gchar *dir_utf8 = g_path_get_dirname (filename);
+       gunichar2 *p;
+       gunichar2 *dir_utf16 = NULL;
+       int retval;
+       
+       if (!dir_utf8 || !dir_utf8 [0])
+               return FALSE;
+
+       dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
+       g_free (dir_utf8);
+
+       if (!dir_utf16)
+               return FALSE;
+
+       p = dir_utf16;
+
+       /* make life easy and only use one directory seperator */
+       while (*p != '\0')
+       {
+               if (*p == '/')
+                       *p = '\\';
+               p++;
+       }
+
+       p = dir_utf16;
+
+       /* get past C:\ )*/
+       while (*p++ != '\\')    
+       {
+       }
+
+       while (1) {
+               BOOL bRet = FALSE;
+               p = wcschr (p, '\\');
+               if (p)
+                       *p = '\0';
+               retval = _wmkdir (dir_utf16);
+               if (retval != 0 && errno != EEXIST) {
+                       g_free (dir_utf16);
+                       return FALSE;
+               }
+               if (!p)
+                       break;
+               *p++ = '\\';
+       }
+       
+       g_free (dir_utf16);
+       return TRUE;
+#else
+       char *p;
+       gchar *dir = g_path_get_dirname (filename);
+       int retval;
+       struct stat sbuf;
+       
+       if (!dir || !dir [0]) {
+               g_free (dir);
+               return FALSE;
+       }
+       
+       if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
+               g_free (dir);
+               return TRUE;
+       }
+       
+       p = dir;
+       while (*p == '/')
+               p++;
+
+       while (1) {
+               p = strchr (p, '/');
+               if (p)
+                       *p = '\0';
+               retval = mkdir (dir, 0777);
+               if (retval != 0 && errno != EEXIST) {
+                       g_free (dir);
+                       return FALSE;
+               }
+               if (!p)
+                       break;
+               *p++ = '/';
+       }
+       
+       g_free (dir);
+       return TRUE;
+#endif
+}
+
+static gboolean
+private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
+{
+       struct stat sbuf_dest;
+       
+       if (stat (src, sbuf_src) == -1 || stat (dest, &sbuf_dest) == -1)
+               return TRUE;
+
+       if (sbuf_src->st_mode == sbuf_dest.st_mode &&
+           sbuf_src->st_size == sbuf_dest.st_size &&
+           sbuf_src->st_mtime == sbuf_dest.st_mtime)
+               return FALSE;
+
+       return TRUE;
+}
+
+char *
+mono_make_shadow_copy (const char *filename)
+{
+       gchar *sibling_source, *sibling_target;
+       gint sibling_source_len, sibling_target_len;
+       guint16 *orig, *dest;
+       char *shadow;
        gboolean copy_result;
+       gboolean is_private = FALSE;
+       gboolean do_copy = FALSE;
        MonoException *exc;
+       gchar **path;
+       struct stat src_sbuf;
+       struct utimbuf utbuf;
+       char *dir_name = g_path_get_dirname (filename);
+       MonoDomain *domain = mono_domain_get ();
+       set_domain_search_path (domain);
 
-       db = mono_string_to_utf8 (domain->setup->dynamic_base);
-       tmp = g_build_filename (db, "shadow-XXXXXX", NULL);
-       fd = mono_mkstemp (tmp);
-       if (fd == -1) {
-               exc = mono_get_exception_execution_engine ("Failed to create shadow copy (mkstemp).");
-               g_free (tmp);
-               g_free (db);
-               mono_raise_exception (exc);
+       if (!domain->search_path) {
+               g_free (dir_name);
+               return (char*) filename;
+       }
+       
+       for (path = domain->search_path; *path; path++) {
+               if (**path == '\0') {
+                       is_private = TRUE;
+                       continue;
+               }
+               
+               if (!is_private)
+                       continue;
+
+               if (strstr (dir_name, *path) == dir_name) {
+                       do_copy = TRUE;
+                       break;
+               }
        }
-       close (fd);
-       remove (tmp);
+       g_free (dir_name);
+
+       if (!do_copy)
+               return (char*) filename;
+       
+       shadow = get_shadow_assembly_location (filename);
+       if (ensure_directory_exists (shadow) == FALSE) {
+               exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
+               mono_raise_exception (exc);
+       }       
+
+       if (!private_file_needs_copying (filename, &src_sbuf, shadow))
+               return (char*) shadow;
+
        orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
-       dest = g_utf8_to_utf16 (tmp, strlen (tmp), NULL, NULL, NULL);
-       copy_result = CopyFile (orig, dest, TRUE);
+       dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
+       DeleteFile (dest);
+       copy_result = CopyFile (orig, dest, FALSE);
        g_free (dest);
        g_free (orig);
-       g_free (db);
 
        if (copy_result == FALSE) {
-               g_free (tmp);
+               g_free (shadow);
                exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
                mono_raise_exception (exc);
        }
-       return tmp;
+
+       /* attempt to copy .mdb, .config if they exist */
+       sibling_source = g_strconcat (filename, ".config", NULL);
+       sibling_source_len = strlen (sibling_source);
+       sibling_target = g_strconcat (shadow, ".config", NULL);
+       sibling_target_len = strlen (sibling_target);
+       
+       copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
+       if (copy_result == TRUE)
+               copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
+       
+       g_free (sibling_source);
+       g_free (sibling_target);
+       
+       if (copy_result == FALSE)  {
+               g_free (shadow);
+               exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
+               mono_raise_exception (exc);
+       }
+
+       utbuf.actime = src_sbuf.st_atime;
+       utbuf.modtime = src_sbuf.st_mtime;
+       utime (shadow, &utbuf);
+       
+       return shadow;
+}
+
+
+MonoDomain *
+mono_domain_from_appdomain (MonoAppDomain *appdomain)
+{
+       if (appdomain == NULL)
+               return NULL;
+       
+       return appdomain->data;
 }
 
 static gboolean
@@ -838,20 +1291,24 @@ try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
                                        const gchar *path3, const gchar *path4,
                                        gboolean refonly, gboolean is_private)
 {
-       
        gchar *fullpath;
-
+       gboolean found = FALSE;
+       
        *assembly = NULL;
        fullpath = g_build_filename (path1, path2, path3, path4, NULL);
-       if (g_file_test (fullpath, G_FILE_TEST_IS_REGULAR)) {
-               if (is_private) {
-                       char *new_path = make_shadow_copy (fullpath);
+
+       if (IS_PORTABILITY_SET) {
+               gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
+               if (new_fullpath) {
                        g_free (fullpath);
-                       fullpath = new_path;
+                       fullpath = new_fullpath;
+                       found = TRUE;
                }
-
+       } else
+               found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
+       
+       if (found)
                *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
-       }
 
        g_free (fullpath);
        return (*assembly != NULL);
@@ -911,6 +1368,8 @@ real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolea
 /*
  * Try loading the assembly from ApplicationBase and PrivateBinPath 
  * and then from assemblies_path if any.
+ * LOCKING: This is called from the assembly loading code, which means the caller
+ * might hold the loader lock. Thus, this function must not acquire the domain lock.
  */
 static MonoAssembly *
 mono_domain_assembly_preload (MonoAssemblyName *aname,
@@ -977,14 +1436,14 @@ ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean re
        }
                
        name = filename = mono_string_to_utf8 (fname);
-
+       
        ass = mono_assembly_open_full (filename, &status, refOnly);
        
        if (!ass){
                MonoException *exc;
 
                if (status == MONO_IMAGE_IMAGE_INVALID)
-                       exc = mono_get_exception_bad_image_format (name);
+                       exc = mono_get_exception_bad_image_format2 (NULL, fname);
                else
                        exc = mono_get_exception_file_not_found2 (NULL, fname);
                g_free (name);
@@ -998,9 +1457,9 @@ ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean re
 
 MonoReflectionAssembly *
 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
-                                                                                       MonoArray *raw_assembly,
-                                                                                       MonoArray *raw_symbol_store, MonoObject *evidence,
-                                                                                       MonoBoolean refonly)
+                                           MonoArray *raw_assembly,
+                                           MonoArray *raw_symbol_store, MonoObject *evidence,
+                                           MonoBoolean refonly)
 {
        MonoAssembly *ass;
        MonoReflectionAssembly *refass = NULL;
@@ -1015,7 +1474,7 @@ ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
        }
 
        if (raw_symbol_store != NULL)
-               mono_debug_init_2_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
+               mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
 
        ass = mono_assembly_load_from_full (image, "", &status, refonly);
 
@@ -1058,13 +1517,20 @@ ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef,
                mono_raise_exception (exc);
        }
 
-       ass = mono_assembly_load_full (&aname, NULL, &status, refOnly);
+       ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
        mono_assembly_name_free (&aname);
 
-       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_found2 (NULL, assRef);
-               mono_raise_exception (exc);
+       if (!ass) {
+               /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
+               if (!refOnly)
+                       refass = mono_try_assembly_resolve (domain, assRef, refOnly);
+               else
+                       refass = NULL;
+               if (!refass) {
+                       /* FIXME: it doesn't make much sense since we really don't have a filename ... */
+                       MonoException *exc = mono_get_exception_file_not_found2 (NULL, assRef);
+                       mono_raise_exception (exc);
+               }
        }
 
        if (refass == NULL)
@@ -1113,26 +1579,17 @@ ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
 }
 
 gint32
-ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, 
-                                           MonoObject *evidence, MonoArray *args)
+ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
+                                                                                       MonoReflectionAssembly *refass, MonoArray *args)
 {
-       MonoAssembly *assembly;
        MonoImage *image;
        MonoMethod *method;
-       char *filename;
-       gint32 res;
-       MonoReflectionAssembly *refass;
 
        MONO_ARCH_SAVE_REGS;
 
-       filename = mono_string_to_utf8 (file);
-       assembly = mono_assembly_open (filename, NULL);
-       g_free (filename);
-
-       if (!assembly)
-               mono_raise_exception (mono_get_exception_file_not_found2 (NULL, file));
-
-       image = assembly->image;
+       g_assert (refass);
+       image = refass->assembly->image;
+       g_assert (image);
 
        method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
 
@@ -1142,12 +1599,7 @@ ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file,
        if (!args)
                args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
 
-       refass = mono_assembly_get_object (ad->data, assembly);
-       MONO_OBJECT_SETREF (refass, evidence, evidence);
-
-       res = mono_runtime_exec_main (method, (MonoArray *)args, NULL);
-
-       return res;
+       return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
 }
 
 gint32 
@@ -1297,13 +1749,13 @@ unload_thread_main (void *arg)
         * FIXME: Abort our parent thread last, so we can return a failure 
         * indication if aborting times out.
         */
-       if (!mono_threads_abort_appdomain_threads (domain, 10000)) {
+       if (!mono_threads_abort_appdomain_threads (domain, -1)) {
                data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
                return 1;
        }
 
        /* Finalize all finalizable objects in the doomed appdomain */
-       if (!mono_domain_finalize (domain, 10000)) {
+       if (!mono_domain_finalize (domain, -1)) {
                data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
                return 1;
        }
@@ -1403,6 +1855,9 @@ mono_domain_unload (MonoDomain *domain)
        thread_handle = CreateThread (NULL, 0, unload_thread_main, &thread_data, 0, &tid);
 #else
        thread_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid);
+       if (thread_handle == NULL) {
+               return;
+       }
        ResumeThread (thread_handle);
 #endif