Merge pull request #1659 from alexanderkyte/stringbuilder-referencesource
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Authors:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  * Copyright 2012 Xamarin Inc
12  */
13 #undef ASSEMBLY_LOAD_DEBUG
14 #include <config.h>
15 #include <glib.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #ifdef HAVE_SYS_TIME_H
22 #include <sys/time.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_UTIME_H
28 #include <utime.h>
29 #else
30 #ifdef HAVE_SYS_UTIME_H
31 #include <sys/utime.h>
32 #endif
33 #endif
34
35 #include <mono/metadata/gc-internal.h>
36 #include <mono/metadata/object.h>
37 #include <mono/metadata/domain-internals.h>
38 #include "mono/metadata/metadata-internals.h"
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/exception.h>
41 #include <mono/metadata/threads.h>
42 #include <mono/metadata/socket-io.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/gc-internal.h>
45 #include <mono/metadata/mono-gc.h>
46 #include <mono/metadata/marshal.h>
47 #include <mono/metadata/monitor.h>
48 #include <mono/metadata/threadpool.h>
49 #include <mono/metadata/mono-debug.h>
50 #include <mono/metadata/mono-debug-debugger.h>
51 #include <mono/metadata/attach.h>
52 #include <mono/metadata/file-io.h>
53 #include <mono/metadata/lock-tracer.h>
54 #include <mono/metadata/console-io.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/tokentype.h>
57 #include <mono/utils/mono-uri.h>
58 #include <mono/utils/mono-logger-internal.h>
59 #include <mono/utils/mono-path.h>
60 #include <mono/utils/mono-stdlib.h>
61 #include <mono/utils/mono-io-portability.h>
62 #include <mono/utils/mono-error-internals.h>
63 #include <mono/utils/atomic.h>
64 #include <mono/utils/mono-memory-model.h>
65 #include <mono/utils/mono-threads.h>
66 #ifdef HOST_WIN32
67 #include <direct.h>
68 #endif
69
70 /*
71  * This is the version number of the corlib-runtime interface. When
72  * making changes to this interface (by changing the layout
73  * of classes the runtime knows about, changing icall signature or
74  * semantics etc), increment this variable. Also increment the
75  * pair of this variable in mscorlib in:
76  *       mcs/class/corlib/System/Environment.cs
77  *
78  * Changes which are already detected at runtime, like the addition
79  * of icalls, do not require an increment.
80  */
81 #define MONO_CORLIB_VERSION 124
82
83 typedef struct
84 {
85         int runtime_count;
86         int assemblybinding_count;
87         MonoDomain *domain;
88         gchar *filename;
89 } RuntimeConfig;
90
91 mono_mutex_t mono_delegate_section;
92
93 mono_mutex_t mono_strtod_mutex;
94
95 static gunichar2 process_guid [36];
96 static gboolean process_guid_set = FALSE;
97
98 static gboolean no_exec = FALSE;
99
100 static MonoAssembly *
101 mono_domain_assembly_preload (MonoAssemblyName *aname,
102                               gchar **assemblies_path,
103                               gpointer user_data);
104
105 static MonoAssembly *
106 mono_domain_assembly_search (MonoAssemblyName *aname,
107                                                          gpointer user_data);
108
109 static void
110 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
111
112 static void
113 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
114
115 static MonoAppDomain *
116 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
117
118 static char *
119 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120
121 static MonoLoadFunc load_function = NULL;
122
123 void
124 mono_install_runtime_load (MonoLoadFunc func)
125 {
126         load_function = func;
127 }
128
129 MonoDomain*
130 mono_runtime_load (const char *filename, const char *runtime_version)
131 {
132         g_assert (load_function);
133         return load_function (filename, runtime_version);
134 }
135
136 /**
137  * mono_runtime_set_no_exec:
138  *
139  * Instructs the runtime to operate in static mode, i.e. avoid/do not
140  * allow managed code execution. This is useful for running the AOT
141  * compiler on platforms which allow full-aot execution only.  This
142  * should be called before mono_runtime_init ().
143  */
144 void
145 mono_runtime_set_no_exec (gboolean val)
146 {
147         no_exec = val;
148 }
149
150 /**
151  * mono_runtime_get_no_exec:
152  *
153  * If true, then the runtime will not allow managed code execution.
154  */
155 gboolean
156 mono_runtime_get_no_exec (void)
157 {
158         return no_exec;
159 }
160
161 static void
162 create_domain_objects (MonoDomain *domain)
163 {
164         MonoDomain *old_domain = mono_domain_get ();
165         MonoString *arg;
166         MonoVTable *string_vt;
167         MonoClassField *string_empty_fld;
168
169         if (domain != old_domain) {
170                 mono_thread_push_appdomain_ref (domain);
171                 mono_domain_set_internal_with_options (domain, FALSE);
172         }
173
174         /*
175          * Initialize String.Empty. This enables the removal of
176          * the static cctor of the String class.
177          */
178         string_vt = mono_class_vtable (domain, mono_defaults.string_class);
179         string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
180         g_assert (string_empty_fld);
181         mono_field_static_set_value (string_vt, string_empty_fld, mono_string_new (domain, ""));
182
183         /*
184          * Create an instance early since we can't do it when there is no memory.
185          */
186         arg = mono_string_new (domain, "Out of memory");
187         domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
188
189         /* 
190          * These two are needed because the signal handlers might be executing on
191          * an alternate stack, and Boehm GC can't handle that.
192          */
193         arg = mono_string_new (domain, "A null value was found where an object instance was required");
194         domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
195         arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
196         domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
197
198         /*The ephemeron tombstone i*/
199         domain->ephemeron_tombstone = mono_object_new (domain, mono_defaults.object_class);
200
201         if (domain != old_domain) {
202                 mono_thread_pop_appdomain_ref ();
203                 mono_domain_set_internal_with_options (old_domain, FALSE);
204         }
205
206         /* 
207          * This class is used during exception handling, so initialize it here, to prevent
208          * stack overflows while handling stack overflows.
209          */
210         mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
211 }
212
213 /**
214  * mono_runtime_init:
215  * @domain: domain returned by mono_init ()
216  *
217  * Initialize the core AppDomain: this function will run also some
218  * IL initialization code, so it needs the execution engine to be fully 
219  * operational.
220  *
221  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
222  * we know the entry_assembly.
223  *
224  */
225 void
226 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
227                    MonoThreadAttachCB attach_cb)
228 {
229         MonoAppDomainSetup *setup;
230         MonoAppDomain *ad;
231         MonoClass *class;
232
233         mono_portability_helpers_init ();
234         
235         mono_gc_base_init ();
236         mono_monitor_init ();
237         mono_thread_pool_init ();
238         mono_marshal_init ();
239
240         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
241         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
242         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
243         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
244         mono_install_assembly_postload_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
245         mono_install_assembly_postload_refonly_search_hook ((void*)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
246         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
247         mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
248
249         mono_thread_init (start_cb, attach_cb);
250
251         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
252         setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, class);
253
254         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
255         ad = (MonoAppDomain *) mono_object_new_pinned (domain, class);
256         ad->data = domain;
257         domain->domain = ad;
258         domain->setup = setup;
259
260         mono_mutex_init_recursive (&mono_delegate_section);
261
262         mono_mutex_init_recursive (&mono_strtod_mutex);
263         
264         mono_thread_attach (domain);
265         mono_context_init (domain);
266         mono_context_set (domain->default_context);
267
268         mono_type_initialization_init ();
269
270         if (!mono_runtime_get_no_exec ())
271                 create_domain_objects (domain);
272
273         /* GC init has to happen after thread init */
274         mono_gc_init ();
275
276 #ifndef DISABLE_SOCKETS
277         mono_network_init ();
278 #endif
279         
280         mono_console_init ();
281         mono_attach_init ();
282
283         mono_locks_tracer_init ();
284
285         /* mscorlib is loaded before we install the load hook */
286         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
287         
288         return;
289 }
290
291 static int
292 mono_get_corlib_version (void)
293 {
294         MonoClass *klass;
295         MonoClassField *field;
296         MonoObject *value;
297
298         klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
299         mono_class_init (klass);
300         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
301         if (!field)
302                 return -1;
303         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
304                 return -1;
305         value = mono_field_get_value_object (mono_domain_get (), field, NULL);
306         return *(gint32*)((gchar*)value + sizeof (MonoObject));
307 }
308
309 /**
310  * mono_check_corlib_version
311  *
312  * Checks that the corlib that is loaded matches the version of this runtime.
313  *
314  * Returns: NULL if the runtime will work with the corlib, or a g_malloc
315  * allocated string with the error otherwise.
316  */
317 const char*
318 mono_check_corlib_version (void)
319 {
320         int version = mono_get_corlib_version ();
321         if (version != MONO_CORLIB_VERSION)
322                 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
323         else
324                 return NULL;
325 }
326
327 /**
328  * mono_context_init:
329  * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
330  *
331  * Initializes the @domain's default System.Runtime.Remoting's Context.
332  */
333 void
334 mono_context_init (MonoDomain *domain)
335 {
336         MonoClass *class;
337         MonoAppContext *context;
338
339         class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
340         context = (MonoAppContext *) mono_object_new_pinned (domain, class);
341         context->domain_id = domain->domain_id;
342         context->context_id = 0;
343         domain->default_context = context;
344 }
345
346 /**
347  * mono_runtime_cleanup:
348  * @domain: unused.
349  *
350  * Internal routine.
351  *
352  * This must not be called while there are still running threads executing
353  * managed code.
354  */
355 void
356 mono_runtime_cleanup (MonoDomain *domain)
357 {
358         mono_attach_cleanup ();
359
360         /* This ends up calling any pending pending (for at most 2 seconds) */
361         mono_gc_cleanup ();
362
363         mono_thread_cleanup ();
364
365 #ifndef DISABLE_SOCKETS
366         mono_network_cleanup ();
367 #endif
368         mono_marshal_cleanup ();
369
370         mono_type_initialization_cleanup ();
371
372         mono_monitor_cleanup ();
373 }
374
375 static MonoDomainFunc quit_function = NULL;
376
377 void
378 mono_install_runtime_cleanup (MonoDomainFunc func)
379 {
380         quit_function = func;
381 }
382
383 void
384 mono_runtime_quit ()
385 {
386         if (quit_function != NULL)
387                 quit_function (mono_get_root_domain (), NULL);
388 }
389
390 /**
391  * mono_domain_create_appdomain:
392  * @friendly_name: The friendly name of the appdomain to create
393  * @configuration_file: The configuration file to initialize the appdomain with
394  * 
395  * Returns a MonoDomain initialized with the appdomain
396  */
397 MonoDomain *
398 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
399 {
400         MonoAppDomain *ad;
401         MonoAppDomainSetup *setup;
402         MonoClass *class;
403
404         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
405         setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
406         setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
407
408         ad = mono_domain_create_appdomain_internal (friendly_name, setup);
409
410         return mono_domain_from_appdomain (ad);
411 }
412
413 /**
414  * mono_domain_set_config:
415  * @domain: MonoDomain initialized with the appdomain we want to change
416  * @base_dir: new base directory for the appdomain
417  * @config_file_name: path to the new configuration for the app domain
418  *
419  * Used to set the system configuration for an appdomain
420  *
421  * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException: 
422  * Error Initializing the configuration system. ---> System.ArgumentException: 
423  * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
424  */
425 void
426 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
427 {
428         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
429         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
430 }
431
432 static MonoAppDomainSetup*
433 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
434 {
435         MonoDomain *caller_domain = mono_domain_get ();
436         MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
437         MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
438
439         mono_domain_set_internal (domain);
440
441         MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
442         MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
443         MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
444         MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
445         MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
446         MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
447         MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
448         MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
449         MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
450         MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
451         copy->publisher_policy = setup->publisher_policy;
452         copy->path_changed = setup->path_changed;
453         copy->loader_optimization = setup->loader_optimization;
454         copy->disallow_binding_redirects = setup->disallow_binding_redirects;
455         copy->disallow_code_downloads = setup->disallow_code_downloads;
456         MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
457         copy->disallow_appbase_probe = setup->disallow_appbase_probe;
458         MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
459         MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
460         MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
461
462         mono_domain_set_internal (caller_domain);
463
464         return copy;
465 }
466
467 static MonoAppDomain *
468 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
469 {
470         MonoError error;
471         MonoClass *adclass;
472         MonoAppDomain *ad;
473         MonoDomain *data;
474         char *shadow_location;
475         
476         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
477
478         /* FIXME: pin all those objects */
479         data = mono_domain_create();
480
481         ad = (MonoAppDomain *) mono_object_new (data, adclass);
482         ad->data = data;
483         data->domain = ad;
484         data->friendly_name = g_strdup (friendly_name);
485
486         if (!setup->application_base) {
487                 /* Inherit from the root domain since MS.NET does this */
488                 MonoDomain *root = mono_get_root_domain ();
489                 if (root->setup->application_base)
490                         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)));
491         }
492
493         mono_context_init (data);
494
495         data->setup = copy_app_domain_setup (data, setup);
496         mono_set_private_bin_path_from_config (data);
497         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
498
499 #ifndef DISABLE_SHADOW_COPY
500         /*FIXME, guard this for when the debugger is not running */
501         shadow_location = get_shadow_assembly_location_base (data, &error);
502         if (!mono_error_ok (&error))
503                 mono_error_raise_exception (&error);
504         g_free (shadow_location);
505 #endif
506
507         create_domain_objects (data);
508
509         return ad;
510 }
511
512 /**
513  * mono_domain_has_type_resolve:
514  * @domain: application domains being looked up
515  *
516  * Returns true if the AppDomain.TypeResolve field has been
517  * set.
518  */
519 gboolean
520 mono_domain_has_type_resolve (MonoDomain *domain)
521 {
522         static MonoClassField *field = NULL;
523         MonoObject *o;
524
525         if (field == NULL) {
526                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
527                 g_assert (field);
528         }
529
530         /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
531         if (!domain->domain)
532                 return FALSE;
533
534         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
535         return o != NULL;
536 }
537
538 /**
539  * mono_domain_try_type_resolve:
540  * @domain: application domainwhere the name where the type is going to be resolved
541  * @name: the name of the type to resolve or NULL.
542  * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
543  *
544  * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
545  * the assembly that matches name.
546  *
547  * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
548  *
549  * Returns: A MonoReflectionAssembly or NULL if not found
550  */
551 MonoReflectionAssembly *
552 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
553 {
554         MonoClass *klass;
555         void *params [1];
556         static MonoMethod *method = NULL;
557
558         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
559
560         if (method == NULL) {
561                 klass = domain->domain->mbr.obj.vtable->klass;
562                 g_assert (klass);
563
564                 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
565                 if (method == NULL) {
566                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
567                         return NULL;
568                 }
569         }
570
571         if (name)
572                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
573         else
574                 *params = tb;
575         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
576 }
577
578 /**
579  * mono_domain_owns_vtable_slot:
580  *
581  *  Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
582  */
583 gboolean
584 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
585 {
586         gboolean res;
587
588         mono_domain_lock (domain);
589         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
590         mono_domain_unlock (domain);
591         return res;
592 }
593
594 /**
595  * mono_domain_set:
596  * @domain: domain
597  * @force: force setting.
598  *
599  * Set the current appdomain to @domain. If @force is set, set it even
600  * if it is being unloaded.
601  *
602  * Returns:
603  *   TRUE on success;
604  *   FALSE if the domain is unloaded
605  */
606 gboolean
607 mono_domain_set (MonoDomain *domain, gboolean force)
608 {
609         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
610                 return FALSE;
611
612         mono_domain_set_internal (domain);
613
614         return TRUE;
615 }
616
617 MonoObject *
618 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
619 {
620         MonoDomain *add;
621         MonoObject *o;
622         char *str;
623
624         MONO_CHECK_ARG_NULL (name, NULL);
625
626         g_assert (ad != NULL);
627         add = ad->data;
628         g_assert (add != NULL);
629
630         str = mono_string_to_utf8 (name);
631
632         mono_domain_lock (add);
633
634         if (!strcmp (str, "APPBASE"))
635                 o = (MonoObject *)add->setup->application_base;
636         else if (!strcmp (str, "APP_CONFIG_FILE"))
637                 o = (MonoObject *)add->setup->configuration_file;
638         else if (!strcmp (str, "DYNAMIC_BASE"))
639                 o = (MonoObject *)add->setup->dynamic_base;
640         else if (!strcmp (str, "APP_NAME"))
641                 o = (MonoObject *)add->setup->application_name;
642         else if (!strcmp (str, "CACHE_BASE"))
643                 o = (MonoObject *)add->setup->cache_path;
644         else if (!strcmp (str, "PRIVATE_BINPATH"))
645                 o = (MonoObject *)add->setup->private_bin_path;
646         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
647                 o = (MonoObject *)add->setup->private_bin_path_probe;
648         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
649                 o = (MonoObject *)add->setup->shadow_copy_directories;
650         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
651                 o = (MonoObject *)add->setup->shadow_copy_files;
652         else 
653                 o = mono_g_hash_table_lookup (add->env, name);
654
655         mono_domain_unlock (add);
656         g_free (str);
657
658         if (!o)
659                 return NULL;
660
661         return o;
662 }
663
664 void
665 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
666 {
667         MonoDomain *add;
668
669         MONO_CHECK_ARG_NULL (name,);
670
671         g_assert (ad != NULL);
672         add = ad->data;
673         g_assert (add != NULL);
674
675         mono_domain_lock (add);
676
677         mono_g_hash_table_insert (add->env, name, data);
678
679         mono_domain_unlock (add);
680 }
681
682 MonoAppDomainSetup *
683 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
684 {
685         g_assert (ad != NULL);
686         g_assert (ad->data != NULL);
687
688         return ad->data->setup;
689 }
690
691 MonoString *
692 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
693 {
694         g_assert (ad != NULL);
695         g_assert (ad->data != NULL);
696
697         return mono_string_new (ad->data, ad->data->friendly_name);
698 }
699
700 MonoAppDomain *
701 ves_icall_System_AppDomain_getCurDomain ()
702 {
703         MonoDomain *add = mono_domain_get ();
704
705         return add->domain;
706 }
707
708 MonoAppDomain *
709 ves_icall_System_AppDomain_getRootDomain ()
710 {
711         MonoDomain *root = mono_get_root_domain ();
712
713         return root->domain;
714 }
715
716 static char*
717 get_attribute_value (const gchar **attribute_names, 
718                      const gchar **attribute_values, 
719                      const char *att_name)
720 {
721         int n;
722         for (n = 0; attribute_names [n] != NULL; n++) {
723                 if (strcmp (attribute_names [n], att_name) == 0)
724                         return g_strdup (attribute_values [n]);
725         }
726         return NULL;
727 }
728
729 static void
730 start_element (GMarkupParseContext *context, 
731                const gchar         *element_name,
732                const gchar        **attribute_names,
733                const gchar        **attribute_values,
734                gpointer             user_data,
735                GError             **error)
736 {
737         RuntimeConfig *runtime_config = user_data;
738         
739         if (strcmp (element_name, "runtime") == 0) {
740                 runtime_config->runtime_count++;
741                 return;
742         }
743
744         if (strcmp (element_name, "assemblyBinding") == 0) {
745                 runtime_config->assemblybinding_count++;
746                 return;
747         }
748         
749         if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
750                 return;
751
752         if (strcmp (element_name, "probing") != 0)
753                 return;
754
755         g_free (runtime_config->domain->private_bin_path);
756         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
757         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
758                 g_free (runtime_config->domain->private_bin_path);
759                 runtime_config->domain->private_bin_path = NULL;
760                 return;
761         }
762 }
763
764 static void
765 end_element (GMarkupParseContext *context,
766              const gchar         *element_name,
767              gpointer             user_data,
768              GError             **error)
769 {
770         RuntimeConfig *runtime_config = user_data;
771         if (strcmp (element_name, "runtime") == 0)
772                 runtime_config->runtime_count--;
773         else if (strcmp (element_name, "assemblyBinding") == 0)
774                 runtime_config->assemblybinding_count--;
775 }
776
777 static void
778 parse_error   (GMarkupParseContext *context, GError *error, gpointer user_data)
779 {
780         RuntimeConfig *state = user_data;
781         const gchar *msg;
782         const gchar *filename;
783
784         filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
785         msg = error && error->message ? error->message : "";
786         g_warning ("Error parsing %s: %s", filename, msg);
787 }
788
789 static const GMarkupParser
790 mono_parser = {
791         start_element,
792         end_element,
793         NULL,
794         NULL,
795         parse_error
796 };
797
798 void
799 mono_set_private_bin_path_from_config (MonoDomain *domain)
800 {
801         MonoError error;
802         gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
803         gsize len;
804         GMarkupParseContext *context;
805         RuntimeConfig runtime_config;
806         gint offset;
807         
808         if (!domain || !domain->setup || !domain->setup->configuration_file)
809                 return;
810
811         config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
812         if (!mono_error_ok (&error)) {
813                 mono_error_cleanup (&error);
814                 goto free_and_out;
815         }
816
817         config_file_path = mono_portability_find_file (config_file_name, TRUE);
818         if (!config_file_path)
819                 config_file_path = config_file_name;
820
821         if (!g_file_get_contents (config_file_path, &text, &len, NULL))
822                 goto free_and_out;
823
824         runtime_config.runtime_count = 0;
825         runtime_config.assemblybinding_count = 0;
826         runtime_config.domain = domain;
827         runtime_config.filename = config_file_path;
828         
829         offset = 0;
830         if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
831                 offset = 3; /* Skip UTF-8 BOM */
832
833         context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
834         if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
835                 g_markup_parse_context_end_parse (context, NULL);
836         g_markup_parse_context_free (context);
837
838   free_and_out:
839         g_free (text);
840         if (config_file_name != config_file_path)
841                 g_free (config_file_name);
842         g_free (config_file_path);
843 }
844
845 MonoAppDomain *
846 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
847 {
848 #ifdef DISABLE_APPDOMAINS
849         mono_set_pending_exception (mono_get_exception_not_supported ("AppDomain creation is not supported on this runtime."));
850         return NULL;
851 #else
852         char *fname = mono_string_to_utf8 (friendly_name);
853         MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
854         
855         g_free (fname);
856
857         return ad;
858 #endif
859 }
860
861 MonoArray *
862 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
863 {
864         MonoDomain *domain = ad->data; 
865         MonoAssembly* ass;
866         static MonoClass *System_Reflection_Assembly;
867         MonoArray *res;
868         GSList *tmp;
869         int i;
870         GPtrArray *assemblies;
871
872         if (!System_Reflection_Assembly)
873                 System_Reflection_Assembly = mono_class_from_name (
874                         mono_defaults.corlib, "System.Reflection", "Assembly");
875
876         /* 
877          * Make a copy of the list of assemblies because we can't hold the assemblies
878          * lock while creating objects etc.
879          */
880         assemblies = g_ptr_array_new ();
881         /* Need to skip internal assembly builders created by remoting */
882         mono_domain_assemblies_lock (domain);
883         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
884                 ass = tmp->data;
885                 if (refonly != ass->ref_only)
886                         continue;
887                 if (ass->corlib_internal)
888                         continue;
889                 g_ptr_array_add (assemblies, ass);
890         }
891         mono_domain_assemblies_unlock (domain);
892
893         res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
894         for (i = 0; i < assemblies->len; ++i) {
895                 ass = g_ptr_array_index (assemblies, i);
896                 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
897         }
898
899         g_ptr_array_free (assemblies, TRUE);
900
901         return res;
902 }
903
904 MonoReflectionAssembly *
905 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly)
906 {
907         MonoClass *klass;
908         MonoMethod *method;
909         MonoBoolean isrefonly;
910         gpointer params [3];
911
912         if (mono_runtime_get_no_exec ())
913                 return NULL;
914
915         g_assert (domain != NULL && fname != NULL);
916
917         klass = domain->domain->mbr.obj.vtable->klass;
918         g_assert (klass);
919         
920         method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
921         if (method == NULL) {
922                 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
923                 return NULL;
924         }
925
926         isrefonly = refonly ? 1 : 0;
927         params [0] = fname;
928         params [1] = (requesting) ? mono_assembly_get_object (domain, requesting) : NULL;
929         params [2] = &isrefonly;
930         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
931 }
932
933 MonoAssembly *
934 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
935                                                                           gboolean refonly)
936 {
937         MonoReflectionAssembly *assembly;
938         MonoDomain *domain = mono_domain_get ();
939         char *aname_str;
940         MonoString *str;
941
942         aname_str = mono_stringify_assembly_name (aname);
943
944         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
945         str = mono_string_new (domain, aname_str);
946         if (!str) {
947                 g_free (aname_str);
948                 return NULL;
949         }
950         assembly = mono_try_assembly_resolve (domain, str, requesting, refonly);
951         g_free (aname_str);
952
953         if (assembly)
954                 return assembly->assembly;
955         else
956                 return NULL;
957 }
958         
959 /*
960  * LOCKING: assumes assemblies_lock in the domain is already locked.
961  */
962 static void
963 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
964 {
965         gint i;
966         GSList *tmp;
967         gboolean destroy_ht = FALSE;
968
969         if (!ass->aname.name)
970                 return;
971
972         if (!ht) {
973                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
974                 destroy_ht = TRUE;
975         }
976
977         /* FIXME: handle lazy loaded assemblies */
978         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
979                 g_hash_table_insert (ht, tmp->data, tmp->data);
980         }
981         if (!g_hash_table_lookup (ht, ass)) {
982                 mono_assembly_addref (ass);
983                 g_hash_table_insert (ht, ass, ass);
984                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
985                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
986         }
987
988         if (ass->image->references) {
989                 for (i = 0; ass->image->references [i] != NULL; i++) {
990                         if (ass->image->references [i] != REFERENCE_MISSING)
991                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
992                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
993                                 }
994                 }
995         }
996         if (destroy_ht)
997                 g_hash_table_destroy (ht);
998 }
999
1000 static void
1001 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1002 {
1003         static MonoClassField *assembly_load_field;
1004         static MonoMethod *assembly_load_method;
1005         MonoDomain *domain = mono_domain_get ();
1006         MonoReflectionAssembly *ref_assembly;
1007         MonoClass *klass;
1008         gpointer load_value;
1009         void *params [1];
1010
1011         if (!domain->domain)
1012                 /* This can happen during startup */
1013                 return;
1014 #ifdef ASSEMBLY_LOAD_DEBUG
1015         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1016 #endif
1017         klass = domain->domain->mbr.obj.vtable->klass;
1018
1019         mono_domain_assemblies_lock (domain);
1020         add_assemblies_to_domain (domain, assembly, NULL);
1021         mono_domain_assemblies_unlock (domain);
1022
1023         if (assembly_load_field == NULL) {
1024                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1025                 g_assert (assembly_load_field);
1026         }
1027
1028         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1029         if (load_value == NULL) {
1030                 /* No events waiting to be triggered */
1031                 return;
1032         }
1033
1034         ref_assembly = mono_assembly_get_object (domain, assembly);
1035         g_assert (ref_assembly);
1036
1037         if (assembly_load_method == NULL) {
1038                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1039                 g_assert (assembly_load_method);
1040         }
1041
1042         *params = ref_assembly;
1043         mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1044 }
1045
1046 /*
1047  * LOCKING: Acquires the domain assemblies lock.
1048  */
1049 static void
1050 set_domain_search_path (MonoDomain *domain)
1051 {
1052         MonoError error;
1053         MonoAppDomainSetup *setup;
1054         gchar **tmp;
1055         gchar *search_path = NULL;
1056         gint i;
1057         gint npaths = 0;
1058         gchar **pvt_split = NULL;
1059         GError *gerror = NULL;
1060         gint appbaselen = -1;
1061
1062         /* 
1063          * We use the low-level domain assemblies lock, since this is called from
1064          * assembly loads hooks, which means this thread might hold the loader lock.
1065          */
1066         mono_domain_assemblies_lock (domain);
1067
1068         if (!domain->setup) {
1069                 mono_domain_assemblies_unlock (domain);
1070                 return;
1071         }
1072
1073         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1074                 mono_domain_assemblies_unlock (domain);
1075                 return;
1076         }
1077         setup = domain->setup;
1078         if (!setup->application_base) {
1079                 mono_domain_assemblies_unlock (domain);
1080                 return; /* Must set application base to get private path working */
1081         }
1082
1083         npaths++;
1084         
1085         if (setup->private_bin_path) {
1086                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1087                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1088                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1089                         mono_error_cleanup (&error);
1090                         mono_domain_assemblies_unlock (domain);
1091                         return;
1092                 }
1093         }
1094         
1095         if (domain->private_bin_path) {
1096                 if (search_path == NULL)
1097                         search_path = domain->private_bin_path;
1098                 else {
1099                         gchar *tmp2 = search_path;
1100                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1101                         g_free (tmp2);
1102                 }
1103         }
1104         
1105         if (search_path) {
1106                 /*
1107                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1108                  * directories relative to ApplicationBase separated by semicolons (see
1109                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1110                  * The loop below copes with the fact that some Unix applications may use ':' (or
1111                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1112                  * ';' for the subsequent split.
1113                  *
1114                  * The issue was reported in bug #81446
1115                  */
1116
1117 #ifndef TARGET_WIN32
1118                 gint slen;
1119
1120                 slen = strlen (search_path);
1121                 for (i = 0; i < slen; i++)
1122                         if (search_path [i] == ':')
1123                                 search_path [i] = ';';
1124 #endif
1125                 
1126                 pvt_split = g_strsplit (search_path, ";", 1000);
1127                 g_free (search_path);
1128                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1129         }
1130
1131         if (!npaths) {
1132                 if (pvt_split)
1133                         g_strfreev (pvt_split);
1134                 /*
1135                  * Don't do this because the first time is called, the domain
1136                  * setup is not finished.
1137                  *
1138                  * domain->search_path = g_malloc (sizeof (char *));
1139                  * domain->search_path [0] = NULL;
1140                 */
1141                 mono_domain_assemblies_unlock (domain);
1142                 return;
1143         }
1144
1145         if (domain->search_path)
1146                 g_strfreev (domain->search_path);
1147
1148         tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1149         tmp [npaths] = NULL;
1150
1151         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1152         if (!mono_error_ok (&error)) {
1153                 mono_error_cleanup (&error);
1154                 g_strfreev (pvt_split);
1155                 g_free (tmp);
1156
1157                 mono_domain_assemblies_unlock (domain);
1158                 return;
1159         }
1160
1161         domain->search_path = tmp;
1162
1163         /* FIXME: is this needed? */
1164         if (strncmp (*tmp, "file://", 7) == 0) {
1165                 gchar *file = *tmp;
1166                 gchar *uri = *tmp;
1167                 gchar *tmpuri;
1168
1169                 if (uri [7] != '/')
1170                         uri = g_strdup_printf ("file:///%s", uri + 7);
1171
1172                 tmpuri = uri;
1173                 uri = mono_escape_uri_string (tmpuri);
1174                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1175                 g_free (uri);
1176
1177                 if (tmpuri != file)
1178                         g_free (tmpuri);
1179
1180                 if (gerror != NULL) {
1181                         g_warning ("%s\n", gerror->message);
1182                         g_error_free (gerror);
1183                         *tmp = file;
1184                 } else {
1185                         g_free (file);
1186                 }
1187         }
1188
1189         for (i = 1; pvt_split && i < npaths; i++) {
1190                 if (g_path_is_absolute (pvt_split [i - 1])) {
1191                         tmp [i] = g_strdup (pvt_split [i - 1]);
1192                 } else {
1193                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1194                 }
1195
1196                 if (strchr (tmp [i], '.')) {
1197                         gchar *reduced;
1198                         gchar *freeme;
1199
1200                         reduced = mono_path_canonicalize (tmp [i]);
1201                         if (appbaselen == -1)
1202                                 appbaselen = strlen (tmp [0]);
1203
1204                         if (strncmp (tmp [0], reduced, appbaselen)) {
1205                                 g_free (reduced);
1206                                 g_free (tmp [i]);
1207                                 tmp [i] = g_strdup ("");
1208                                 continue;
1209                         }
1210
1211                         freeme = tmp [i];
1212                         tmp [i] = reduced;
1213                         g_free (freeme);
1214                 }
1215         }
1216         
1217         if (setup->private_bin_path_probe != NULL) {
1218                 g_free (tmp [0]);
1219                 tmp [0] = g_strdup ("");
1220         }
1221                 
1222         domain->setup->path_changed = FALSE;
1223
1224         g_strfreev (pvt_split);
1225
1226         mono_domain_assemblies_unlock (domain);
1227 }
1228
1229 #ifdef DISABLE_SHADOW_COPY
1230 gboolean
1231 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1232 {
1233         return FALSE;
1234 }
1235
1236 char *
1237 mono_make_shadow_copy (const char *filename)
1238 {
1239         return (char *) filename;
1240 }
1241 #else
1242 static gboolean
1243 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1244 {
1245         guint16 *orig, *dest;
1246         gboolean copy_result;
1247         
1248         strcpy (src + srclen - tail_len, extension);
1249
1250         if (IS_PORTABILITY_CASE) {
1251                 gchar *file = mono_portability_find_file (src, TRUE);
1252
1253                 if (file == NULL)
1254                         return TRUE;
1255
1256                 g_free (file);
1257         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1258                 return TRUE;
1259         }
1260
1261         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1262
1263         strcpy (target + targetlen - tail_len, extension);
1264         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1265         
1266         DeleteFile (dest);
1267         copy_result = CopyFile (orig, dest, FALSE);
1268
1269         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1270          * overwritten when updated in their original locations. */
1271         if (copy_result)
1272                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1273
1274         g_free (orig);
1275         g_free (dest);
1276         
1277         return copy_result;
1278 }
1279
1280 static gint32 
1281 get_cstring_hash (const char *str)
1282 {
1283         int len, i;
1284         const char *p;
1285         gint32 h = 0;
1286         
1287         if (!str || !str [0])
1288                 return 0;
1289                 
1290         len = strlen (str);
1291         p = str;
1292         for (i = 0; i < len; i++) {
1293                 h = (h << 5) - h + *p;
1294                 p++;
1295         }
1296         
1297         return h;
1298 }
1299
1300 /*
1301  * Returned memory is malloc'd. Called must free it 
1302  */
1303 static char *
1304 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1305 {
1306         MonoAppDomainSetup *setup;
1307         char *cache_path, *appname;
1308         char *userdir;
1309         char *location;
1310
1311         mono_error_init (error);
1312         
1313         setup = domain->setup;
1314         if (setup->cache_path != NULL && setup->application_name != NULL) {
1315                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1316                 if (!mono_error_ok (error))
1317                         return NULL;
1318 #ifndef TARGET_WIN32
1319                 {
1320                         gint i;
1321                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1322                                 if (cache_path [i] == '\\')
1323                                         cache_path [i] = '/';
1324                 }
1325 #endif
1326
1327                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1328                 if (!mono_error_ok (error)) {
1329                         g_free (cache_path);
1330                         return NULL;
1331                 }
1332
1333                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1334                 g_free (appname);
1335                 g_free (cache_path);
1336         } else {
1337                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1338                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1339                 g_free (userdir);
1340         }
1341         return location;
1342 }
1343
1344 static char *
1345 get_shadow_assembly_location (const char *filename, MonoError *error)
1346 {
1347         gint32 hash = 0, hash2 = 0;
1348         char name_hash [9];
1349         char path_hash [30];
1350         char *bname = g_path_get_basename (filename);
1351         char *dirname = g_path_get_dirname (filename);
1352         char *location, *tmploc;
1353         MonoDomain *domain = mono_domain_get ();
1354
1355         mono_error_init (error);
1356         
1357         hash = get_cstring_hash (bname);
1358         hash2 = get_cstring_hash (dirname);
1359         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1360         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1361         tmploc = get_shadow_assembly_location_base (domain, error);
1362         if (!mono_error_ok (error)) {
1363                 g_free (bname);
1364                 g_free (dirname);
1365                 return NULL;
1366         }
1367
1368         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1369         g_free (tmploc);
1370         g_free (bname);
1371         g_free (dirname);
1372         return location;
1373 }
1374
1375 static gboolean
1376 ensure_directory_exists (const char *filename)
1377 {
1378 #ifdef HOST_WIN32
1379         gchar *dir_utf8 = g_path_get_dirname (filename);
1380         gunichar2 *p;
1381         gunichar2 *dir_utf16 = NULL;
1382         int retval;
1383         
1384         if (!dir_utf8 || !dir_utf8 [0])
1385                 return FALSE;
1386
1387         dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1388         g_free (dir_utf8);
1389
1390         if (!dir_utf16)
1391                 return FALSE;
1392
1393         p = dir_utf16;
1394
1395         /* make life easy and only use one directory seperator */
1396         while (*p != '\0')
1397         {
1398                 if (*p == '/')
1399                         *p = '\\';
1400                 p++;
1401         }
1402
1403         p = dir_utf16;
1404
1405         /* get past C:\ )*/
1406         while (*p++ != '\\')    
1407         {
1408         }
1409
1410         while (1) {
1411                 BOOL bRet = FALSE;
1412                 p = wcschr (p, '\\');
1413                 if (p)
1414                         *p = '\0';
1415                 retval = _wmkdir (dir_utf16);
1416                 if (retval != 0 && errno != EEXIST) {
1417                         g_free (dir_utf16);
1418                         return FALSE;
1419                 }
1420                 if (!p)
1421                         break;
1422                 *p++ = '\\';
1423         }
1424         
1425         g_free (dir_utf16);
1426         return TRUE;
1427 #else
1428         char *p;
1429         gchar *dir = g_path_get_dirname (filename);
1430         int retval;
1431         struct stat sbuf;
1432         
1433         if (!dir || !dir [0]) {
1434                 g_free (dir);
1435                 return FALSE;
1436         }
1437         
1438         if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1439                 g_free (dir);
1440                 return TRUE;
1441         }
1442         
1443         p = dir;
1444         while (*p == '/')
1445                 p++;
1446
1447         while (1) {
1448                 p = strchr (p, '/');
1449                 if (p)
1450                         *p = '\0';
1451                 retval = mkdir (dir, 0777);
1452                 if (retval != 0 && errno != EEXIST) {
1453                         g_free (dir);
1454                         return FALSE;
1455                 }
1456                 if (!p)
1457                         break;
1458                 *p++ = '/';
1459         }
1460         
1461         g_free (dir);
1462         return TRUE;
1463 #endif
1464 }
1465
1466 static gboolean
1467 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1468 {
1469         struct stat sbuf_dest;
1470         gchar *stat_src;
1471         gchar *real_src = mono_portability_find_file (src, TRUE);
1472
1473         if (!real_src)
1474                 stat_src = (gchar*)src;
1475         else
1476                 stat_src = real_src;
1477
1478         if (stat (stat_src, sbuf_src) == -1) {
1479                 time_t tnow = time (NULL);
1480
1481                 if (real_src)
1482                         g_free (real_src);
1483
1484                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1485                 sbuf_src->st_mtime = tnow;
1486                 sbuf_src->st_atime = tnow;
1487                 return TRUE;
1488         }
1489
1490         if (real_src)
1491                 g_free (real_src);
1492
1493         if (stat (dest, &sbuf_dest) == -1)
1494                 return TRUE;
1495         
1496         if (sbuf_src->st_size == sbuf_dest.st_size &&
1497             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1498                 return FALSE;
1499
1500         return TRUE;
1501 }
1502
1503 static gboolean
1504 shadow_copy_create_ini (const char *shadow, const char *filename)
1505 {
1506         char *dir_name;
1507         char *ini_file;
1508         guint16 *u16_ini;
1509         gboolean result;
1510         guint32 n;
1511         HANDLE *handle;
1512         gchar *full_path;
1513
1514         dir_name = g_path_get_dirname (shadow);
1515         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1516         g_free (dir_name);
1517         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1518                 g_free (ini_file);
1519                 return TRUE;
1520         }
1521
1522         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1523         g_free (ini_file);
1524         if (!u16_ini) {
1525                 return FALSE;
1526         }
1527         handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1528                                 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1529         g_free (u16_ini);
1530         if (handle == INVALID_HANDLE_VALUE) {
1531                 return FALSE;
1532         }
1533
1534         full_path = mono_path_resolve_symlinks (filename);
1535         result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1536         g_free (full_path);
1537         CloseHandle (handle);
1538         return result;
1539 }
1540
1541 gboolean
1542 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1543 {
1544         MonoError error;
1545         MonoAppDomainSetup *setup;
1546         gchar *all_dirs;
1547         gchar **dir_ptr;
1548         gchar **directories;
1549         gchar *shadow_status_string;
1550         gchar *base_dir;
1551         gboolean shadow_enabled;
1552         gboolean found = FALSE;
1553
1554         if (domain == NULL)
1555                 return FALSE;
1556
1557         setup = domain->setup;
1558         if (setup == NULL || setup->shadow_copy_files == NULL)
1559                 return FALSE;
1560
1561         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1562         if (!mono_error_ok (&error)) {
1563                 mono_error_cleanup (&error);
1564                 return FALSE;
1565         }
1566         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1567         g_free (shadow_status_string);
1568
1569         if (!shadow_enabled)
1570                 return FALSE;
1571
1572         if (setup->shadow_copy_directories == NULL)
1573                 return TRUE;
1574
1575         /* Is dir_name a shadow_copy destination already? */
1576         base_dir = get_shadow_assembly_location_base (domain, &error);
1577         if (!mono_error_ok (&error)) {
1578                 mono_error_cleanup (&error);
1579                 return FALSE;
1580         }
1581
1582         if (strstr (dir_name, base_dir)) {
1583                 g_free (base_dir);
1584                 return TRUE;
1585         }
1586         g_free (base_dir);
1587
1588         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1589         if (!mono_error_ok (&error)) {
1590                 mono_error_cleanup (&error);
1591                 return FALSE;
1592         }
1593
1594         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1595         dir_ptr = directories;
1596         while (*dir_ptr) {
1597                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1598                         found = TRUE;
1599                         break;
1600                 }
1601                 dir_ptr++;
1602         }
1603         g_strfreev (directories);
1604         g_free (all_dirs);
1605         return found;
1606 }
1607
1608 /*
1609 This function raises exceptions so it can cause as sorts of nasty stuff if called
1610 while holding a lock.
1611 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1612 or NULL if source file not found.
1613 FIXME bubble up the error instead of raising it here
1614 */
1615 char *
1616 mono_make_shadow_copy (const char *filename)
1617 {
1618         MonoError error;
1619         gchar *sibling_source, *sibling_target;
1620         gint sibling_source_len, sibling_target_len;
1621         guint16 *orig, *dest;
1622         guint32 attrs;
1623         char *shadow;
1624         gboolean copy_result;
1625         MonoException *exc;
1626         struct stat src_sbuf;
1627         struct utimbuf utbuf;
1628         char *dir_name = g_path_get_dirname (filename);
1629         MonoDomain *domain = mono_domain_get ();
1630         char *shadow_dir;
1631
1632         set_domain_search_path (domain);
1633
1634         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1635                 g_free (dir_name);
1636                 return (char *) filename;
1637         }
1638
1639         /* Is dir_name a shadow_copy destination already? */
1640         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1641         if (!mono_error_ok (&error)) {
1642                 mono_error_cleanup (&error);
1643                 g_free (dir_name);
1644                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1645                 mono_raise_exception (exc);
1646         }
1647
1648         if (strstr (dir_name, shadow_dir)) {
1649                 g_free (shadow_dir);
1650                 g_free (dir_name);
1651                 return (char *) filename;
1652         }
1653         g_free (shadow_dir);
1654         g_free (dir_name);
1655
1656         shadow = get_shadow_assembly_location (filename, &error);
1657         if (!mono_error_ok (&error)) {
1658                 mono_error_cleanup (&error);
1659                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1660                 mono_raise_exception (exc);
1661         }
1662
1663         if (ensure_directory_exists (shadow) == FALSE) {
1664                 g_free (shadow);
1665                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1666                 mono_raise_exception (exc);
1667         }       
1668
1669         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1670                 return (char*) shadow;
1671
1672         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1673         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1674         DeleteFile (dest);
1675
1676         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1677          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1678          * and not have it runtime error" */
1679         attrs = GetFileAttributes (orig);
1680         if (attrs == INVALID_FILE_ATTRIBUTES) {
1681                 g_free (shadow);
1682                 return (char *)filename;
1683         }
1684
1685         copy_result = CopyFile (orig, dest, FALSE);
1686
1687         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1688          * overwritten when updated in their original locations. */
1689         if (copy_result)
1690                 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1691
1692         g_free (dest);
1693         g_free (orig);
1694
1695         if (copy_result == FALSE) {
1696                 g_free (shadow);
1697
1698                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1699                 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1700                         return NULL; /* file not found, shadow copy failed */
1701
1702                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1703                 mono_raise_exception (exc);
1704         }
1705
1706         /* attempt to copy .mdb, .config if they exist */
1707         sibling_source = g_strconcat (filename, ".config", NULL);
1708         sibling_source_len = strlen (sibling_source);
1709         sibling_target = g_strconcat (shadow, ".config", NULL);
1710         sibling_target_len = strlen (sibling_target);
1711         
1712         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1713         if (copy_result == TRUE)
1714                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1715         
1716         g_free (sibling_source);
1717         g_free (sibling_target);
1718         
1719         if (copy_result == FALSE)  {
1720                 g_free (shadow);
1721                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1722                 mono_raise_exception (exc);
1723         }
1724
1725         /* Create a .ini file containing the original assembly location */
1726         if (!shadow_copy_create_ini (shadow, filename)) {
1727                 g_free (shadow);
1728                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1729                 mono_raise_exception (exc);
1730         }
1731
1732         utbuf.actime = src_sbuf.st_atime;
1733         utbuf.modtime = src_sbuf.st_mtime;
1734         utime (shadow, &utbuf);
1735         
1736         return shadow;
1737 }
1738 #endif /* DISABLE_SHADOW_COPY */
1739
1740 MonoDomain *
1741 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1742 {
1743         if (appdomain == NULL)
1744                 return NULL;
1745         
1746         return appdomain->data;
1747 }
1748
1749 static gboolean
1750 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1751                                         const gchar *path3, const gchar *path4,
1752                                         gboolean refonly, gboolean is_private)
1753 {
1754         gchar *fullpath;
1755         gboolean found = FALSE;
1756         
1757         *assembly = NULL;
1758         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1759
1760         if (IS_PORTABILITY_SET) {
1761                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1762                 if (new_fullpath) {
1763                         g_free (fullpath);
1764                         fullpath = new_fullpath;
1765                         found = TRUE;
1766                 }
1767         } else
1768                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1769         
1770         if (found)
1771                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1772
1773         g_free (fullpath);
1774         return (*assembly != NULL);
1775 }
1776
1777 static MonoAssembly *
1778 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1779 {
1780         MonoAssembly *result = NULL;
1781         gchar **path;
1782         gchar *filename;
1783         const gchar *local_culture;
1784         gint len;
1785         gboolean is_private = FALSE;
1786
1787         if (!culture || *culture == '\0') {
1788                 local_culture = "";
1789         } else {
1790                 local_culture = culture;
1791         }
1792
1793         filename =  g_strconcat (name, ".dll", NULL);
1794         len = strlen (filename);
1795
1796         for (path = search_path; *path; path++) {
1797                 if (**path == '\0') {
1798                         is_private = TRUE;
1799                         continue; /* Ignore empty ApplicationBase */
1800                 }
1801
1802                 /* See test cases in bug #58992 and bug #57710 */
1803                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1804                 strcpy (filename + len - 4, ".dll");
1805                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1806                         break;
1807
1808                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1809                 strcpy (filename + len - 4, ".exe");
1810                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1811                         break;
1812
1813                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1814                 strcpy (filename + len - 4, ".dll");
1815                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1816                         break;
1817
1818                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1819                 strcpy (filename + len - 4, ".exe");
1820                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1821                         break;
1822         }
1823
1824         g_free (filename);
1825         return result;
1826 }
1827
1828 /*
1829  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1830  * and then from assemblies_path if any.
1831  * LOCKING: This is called from the assembly loading code, which means the caller
1832  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1833  */
1834 static MonoAssembly *
1835 mono_domain_assembly_preload (MonoAssemblyName *aname,
1836                               gchar **assemblies_path,
1837                               gpointer user_data)
1838 {
1839         MonoDomain *domain = mono_domain_get ();
1840         MonoAssembly *result = NULL;
1841         gboolean refonly = GPOINTER_TO_UINT (user_data);
1842
1843         set_domain_search_path (domain);
1844
1845         if (domain->search_path && domain->search_path [0] != NULL) {
1846                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1847         }
1848
1849         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1850                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1851         }
1852
1853         return result;
1854 }
1855
1856 /*
1857  * Check whenever a given assembly was already loaded in the current appdomain.
1858  */
1859 static MonoAssembly *
1860 mono_domain_assembly_search (MonoAssemblyName *aname,
1861                                                          gpointer user_data)
1862 {
1863         MonoDomain *domain = mono_domain_get ();
1864         GSList *tmp;
1865         MonoAssembly *ass;
1866         gboolean refonly = GPOINTER_TO_UINT (user_data);
1867
1868         mono_domain_assemblies_lock (domain);
1869         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1870                 ass = tmp->data;
1871                 /* Dynamic assemblies can't match here in MS.NET */
1872                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1873                         continue;
1874
1875                 mono_domain_assemblies_unlock (domain);
1876                 return ass;
1877         }
1878         mono_domain_assemblies_unlock (domain);
1879
1880         return NULL;
1881 }
1882
1883 MonoReflectionAssembly *
1884 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1885 {
1886         MonoDomain *domain = mono_domain_get ();
1887         char *name, *filename;
1888         MonoImageOpenStatus status = MONO_IMAGE_OK;
1889         MonoAssembly *ass;
1890
1891         if (fname == NULL) {
1892                 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1893                 mono_set_pending_exception (exc);
1894                 return NULL;
1895         }
1896                 
1897         name = filename = mono_string_to_utf8 (fname);
1898         
1899         ass = mono_assembly_open_full (filename, &status, refOnly);
1900         
1901         if (!ass) {
1902                 MonoException *exc;
1903
1904                 if (status == MONO_IMAGE_IMAGE_INVALID)
1905                         exc = mono_get_exception_bad_image_format2 (NULL, fname);
1906                 else
1907                         exc = mono_get_exception_file_not_found2 (NULL, fname);
1908                 g_free (name);
1909                 mono_set_pending_exception (exc);
1910                 return NULL;
1911         }
1912
1913         g_free (name);
1914
1915         return mono_assembly_get_object (domain, ass);
1916 }
1917
1918 MonoReflectionAssembly *
1919 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
1920                                             MonoArray *raw_assembly,
1921                                             MonoArray *raw_symbol_store, MonoObject *evidence,
1922                                             MonoBoolean refonly)
1923 {
1924         MonoAssembly *ass;
1925         MonoReflectionAssembly *refass = NULL;
1926         MonoDomain *domain = ad->data;
1927         MonoImageOpenStatus status;
1928         guint32 raw_assembly_len = mono_array_length (raw_assembly);
1929         MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1930
1931         if (!image) {
1932                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1933                 return NULL;
1934         }
1935
1936         if (raw_symbol_store != NULL)
1937                 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1938
1939         ass = mono_assembly_load_from_full (image, "", &status, refonly);
1940
1941
1942         if (!ass) {
1943                 mono_image_close (image);
1944                 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
1945                 return NULL; 
1946         }
1947
1948         refass = mono_assembly_get_object (domain, ass);
1949         MONO_OBJECT_SETREF (refass, evidence, evidence);
1950         return refass;
1951 }
1952
1953 MonoReflectionAssembly *
1954 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1955 {
1956         MonoDomain *domain = ad->data; 
1957         MonoImageOpenStatus status = MONO_IMAGE_OK;
1958         MonoAssembly *ass;
1959         MonoAssemblyName aname;
1960         MonoReflectionAssembly *refass = NULL;
1961         gchar *name;
1962         gboolean parsed;
1963
1964         g_assert (assRef != NULL);
1965
1966         name = mono_string_to_utf8 (assRef);
1967         parsed = mono_assembly_name_parse (name, &aname);
1968         g_free (name);
1969
1970         if (!parsed) {
1971                 /* This is a parse error... */
1972                 if (!refOnly)
1973                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1974                 return refass;
1975         }
1976
1977         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1978         mono_assembly_name_free (&aname);
1979
1980         if (!ass) {
1981                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1982                 if (!refOnly)
1983                         refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly);
1984                 else
1985                         refass = NULL;
1986                 if (!refass) {
1987                         return NULL;
1988                 }
1989         }
1990
1991         if (refass == NULL)
1992                 refass = mono_assembly_get_object (domain, ass);
1993
1994         MONO_OBJECT_SETREF (refass, evidence, evidence);
1995         return refass;
1996 }
1997
1998 void
1999 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2000 {
2001         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2002
2003         if (NULL == domain) {
2004                 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2005                 mono_set_pending_exception (exc);
2006                 return;
2007         }
2008         
2009         if (domain == mono_get_root_domain ()) {
2010                 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2011                 return;
2012         }
2013
2014         /* 
2015          * Unloading seems to cause problems when running NUnit/NAnt, hence
2016          * this workaround.
2017          */
2018         if (g_getenv ("MONO_NO_UNLOAD"))
2019                 return;
2020 #ifdef __native_client__
2021         return;
2022 #endif
2023
2024         mono_domain_unload (domain);
2025 }
2026
2027 gboolean
2028 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2029 {
2030         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2031
2032         if (!domain)
2033                 return TRUE;
2034
2035         return mono_domain_is_unloading (domain);
2036 }
2037
2038 gint32
2039 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
2040                                                                                         MonoReflectionAssembly *refass, MonoArray *args)
2041 {
2042         MonoError error;
2043         MonoImage *image;
2044         MonoMethod *method;
2045
2046         g_assert (refass);
2047         image = refass->assembly->image;
2048         g_assert (image);
2049
2050         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2051
2052         if (!method)
2053                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2054
2055         if (!args)
2056                 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2057
2058         return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2059 }
2060
2061 gint32 
2062 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2063 {
2064         return ad->data->domain_id;
2065 }
2066
2067 MonoAppDomain * 
2068 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2069 {
2070         MonoDomain *old_domain = mono_domain_get();
2071
2072         if (!mono_domain_set (ad->data, FALSE)) {
2073                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2074                 return NULL;
2075         }
2076
2077         return old_domain->domain;
2078 }
2079
2080 MonoAppDomain * 
2081 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2082 {
2083         MonoDomain *current_domain = mono_domain_get ();
2084         MonoDomain *domain = mono_domain_get_by_id (domainid);
2085
2086         if (!domain || !mono_domain_set (domain, FALSE)) {
2087                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2088                 return NULL;
2089         }
2090
2091         return current_domain->domain;
2092 }
2093
2094 void
2095 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2096 {
2097         mono_thread_push_appdomain_ref (ad->data);
2098 }
2099
2100 void
2101 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2102 {
2103         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2104
2105         if (!domain) {
2106                 /* 
2107                  * Raise an exception to prevent the managed code from executing a pop
2108                  * later.
2109                  */
2110                 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2111                 return;
2112         }
2113
2114         mono_thread_push_appdomain_ref (domain);
2115 }
2116
2117 void
2118 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2119 {
2120         mono_thread_pop_appdomain_ref ();
2121 }
2122
2123 MonoAppContext * 
2124 ves_icall_System_AppDomain_InternalGetContext ()
2125 {
2126         return mono_context_get ();
2127 }
2128
2129 MonoAppContext * 
2130 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2131 {
2132         return mono_domain_get ()->default_context;
2133 }
2134
2135 MonoAppContext * 
2136 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2137 {
2138         MonoAppContext *old_context = mono_context_get ();
2139
2140         mono_context_set (mc);
2141
2142         return old_context;
2143 }
2144
2145 MonoString *
2146 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2147 {
2148         MonoDomain* mono_root_domain = mono_get_root_domain ();
2149         mono_domain_lock (mono_root_domain);
2150         if (process_guid_set) {
2151                 mono_domain_unlock (mono_root_domain);
2152                 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2153         }
2154         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2155         process_guid_set = TRUE;
2156         mono_domain_unlock (mono_root_domain);
2157         return newguid;
2158 }
2159
2160 gboolean
2161 mono_domain_is_unloading (MonoDomain *domain)
2162 {
2163         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2164                 return TRUE;
2165         else
2166                 return FALSE;
2167 }
2168
2169 static void
2170 clear_cached_vtable (MonoVTable *vtable)
2171 {
2172         MonoClass *klass = vtable->klass;
2173         MonoDomain *domain = vtable->domain;
2174         MonoClassRuntimeInfo *runtime_info;
2175         void *data;
2176
2177         runtime_info = klass->runtime_info;
2178         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2179                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2180         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2181                 mono_gc_free_fixed (data);
2182 }
2183
2184 static G_GNUC_UNUSED void
2185 zero_static_data (MonoVTable *vtable)
2186 {
2187         MonoClass *klass = vtable->klass;
2188         void *data;
2189
2190         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2191                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2192 }
2193
2194 typedef struct unload_data {
2195         gboolean done;
2196         MonoDomain *domain;
2197         char *failure_reason;
2198         gint32 refcount;
2199 } unload_data;
2200
2201 static void
2202 unload_data_unref (unload_data *data)
2203 {
2204         gint32 count;
2205         do {
2206                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2207                 g_assert (count >= 1 && count <= 2);
2208                 if (count == 1) {
2209                         g_free (data);
2210                         return;
2211                 }
2212         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2213 }
2214
2215 static void
2216 deregister_reflection_info_roots_from_list (MonoImage *image)
2217 {
2218         GSList *list = image->reflection_info_unregister_classes;
2219
2220         while (list) {
2221                 MonoClass *class = list->data;
2222
2223                 mono_class_free_ref_info (class);
2224
2225                 list = list->next;
2226         }
2227
2228         image->reflection_info_unregister_classes = NULL;
2229 }
2230
2231 static void
2232 deregister_reflection_info_roots (MonoDomain *domain)
2233 {
2234         GSList *list;
2235
2236         mono_domain_assemblies_lock (domain);
2237         for (list = domain->domain_assemblies; list; list = list->next) {
2238                 MonoAssembly *assembly = list->data;
2239                 MonoImage *image = assembly->image;
2240                 int i;
2241
2242                 /*
2243                  * No need to take the image lock here since dynamic images are appdomain bound and
2244                  * at this point the mutator is gone.  Taking the image lock here would mean
2245                  * promoting it from a simple lock to a complex lock, which we better avoid if
2246                  * possible.
2247                  */
2248                 if (image_is_dynamic (image))
2249                         deregister_reflection_info_roots_from_list (image);
2250
2251                 for (i = 0; i < image->module_count; ++i) {
2252                         MonoImage *module = image->modules [i];
2253                         if (module && image_is_dynamic (module))
2254                                 deregister_reflection_info_roots_from_list (module);
2255                 }
2256         }
2257         mono_domain_assemblies_unlock (domain);
2258 }
2259
2260 static guint32 WINAPI
2261 unload_thread_main (void *arg)
2262 {
2263         unload_data *data = (unload_data*)arg;
2264         MonoDomain *domain = data->domain;
2265         MonoThread *thread;
2266         int i;
2267
2268         /* Have to attach to the runtime so shutdown can wait for this thread */
2269         /* Force it to be attached to avoid racing during shutdown. */
2270         thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2271
2272         /* 
2273          * FIXME: Abort our parent thread last, so we can return a failure 
2274          * indication if aborting times out.
2275          */
2276         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2277                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2278                 goto failure;
2279         }
2280
2281         if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2282                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2283                 goto failure;
2284         }
2285
2286         /* Finalize all finalizable objects in the doomed appdomain */
2287         if (!mono_domain_finalize (domain, -1)) {
2288                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2289                 goto failure;
2290         }
2291
2292         /* Clear references to our vtables in class->runtime_info.
2293          * We also hold the loader lock because we're going to change
2294          * class->runtime_info.
2295          */
2296
2297         mono_loader_lock (); //FIXME why do we need the loader lock here?
2298         mono_domain_lock (domain);
2299 #ifdef HAVE_SGEN_GC
2300         /*
2301          * We need to make sure that we don't have any remsets
2302          * pointing into static data of the to-be-freed domain because
2303          * at the next collections they would be invalid.  So what we
2304          * do is we first zero all static data and then do a minor
2305          * collection.  Because all references in the static data will
2306          * now be null we won't do any unnecessary copies and after
2307          * the collection there won't be any more remsets.
2308          */
2309         for (i = 0; i < domain->class_vtable_array->len; ++i)
2310                 zero_static_data (g_ptr_array_index (domain->class_vtable_array, i));
2311         mono_gc_collect (0);
2312 #endif
2313         for (i = 0; i < domain->class_vtable_array->len; ++i)
2314                 clear_cached_vtable (g_ptr_array_index (domain->class_vtable_array, i));
2315         deregister_reflection_info_roots (domain);
2316
2317         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2318
2319         mono_domain_unlock (domain);
2320         mono_loader_unlock ();
2321
2322         mono_threads_clear_cached_culture (domain);
2323
2324         domain->state = MONO_APPDOMAIN_UNLOADED;
2325
2326         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2327
2328         /* remove from the handle table the items related to this domain */
2329         mono_gchandle_free_domain (domain);
2330
2331         mono_domain_free (domain, FALSE);
2332
2333         mono_gc_collect (mono_gc_max_generation ());
2334
2335         mono_atomic_store_release (&data->done, TRUE);
2336         unload_data_unref (data);
2337         mono_thread_detach (thread);
2338         return 0;
2339
2340 failure:
2341         mono_atomic_store_release (&data->done, TRUE);
2342         unload_data_unref (data);
2343         mono_thread_detach (thread);
2344         return 1;
2345 }
2346
2347 /*
2348  * mono_domain_unload:
2349  * @domain: The domain to unload
2350  *
2351  *  Unloads an appdomain. Follows the process outlined in the comment
2352  *  for mono_domain_try_unload.
2353  */
2354 void
2355 mono_domain_unload (MonoDomain *domain)
2356 {
2357         MonoObject *exc = NULL;
2358         mono_domain_try_unload (domain, &exc);
2359         if (exc)
2360                 mono_raise_exception ((MonoException*)exc);
2361 }
2362
2363 /*
2364  * mono_domain_unload:
2365  * @domain: The domain to unload
2366  * @exc: Exception information
2367  *
2368  *  Unloads an appdomain. Follows the process outlined in:
2369  *  http://blogs.gotdotnet.com/cbrumme
2370  *
2371  *  If doing things the 'right' way is too hard or complex, we do it the 
2372  *  'simple' way, which means do everything needed to avoid crashes and
2373  *  memory leaks, but not much else.
2374  *
2375  *  It is required to pass a valid reference to the exc argument, upon return
2376  *  from this function *exc will be set to the exception thrown, if any.
2377  *
2378  *  If this method is not called from an icall (embedded scenario for instance),
2379  *  it must not be called with any managed frames on the stack, since the unload
2380  *  process could end up trying to abort the current thread.
2381  */
2382 void
2383 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2384 {
2385         HANDLE thread_handle;
2386         MonoAppDomainState prev_state;
2387         MonoMethod *method;
2388         unload_data *thread_data;
2389         MonoNativeThreadId tid;
2390         MonoDomain *caller_domain = mono_domain_get ();
2391         char *name;
2392
2393         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2394
2395         /* Atomically change our state to UNLOADING */
2396         prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2397                                                                                          MONO_APPDOMAIN_UNLOADING_START,
2398                                                                                          MONO_APPDOMAIN_CREATED);
2399         if (prev_state != MONO_APPDOMAIN_CREATED) {
2400                 switch (prev_state) {
2401                 case MONO_APPDOMAIN_UNLOADING_START:
2402                 case MONO_APPDOMAIN_UNLOADING:
2403                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2404                         return;
2405                 case MONO_APPDOMAIN_UNLOADED:
2406                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2407                         return;
2408                 default:
2409                         g_warning ("Invalid appdomain state %d", prev_state);
2410                         g_assert_not_reached ();
2411                 }
2412         }
2413
2414         mono_domain_set (domain, FALSE);
2415         /* Notify OnDomainUnload listeners */
2416         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2417         g_assert (method);
2418
2419         mono_runtime_invoke (method, domain->domain, NULL, exc);
2420         if (*exc) {
2421                 /* Roll back the state change */
2422                 domain->state = MONO_APPDOMAIN_CREATED;
2423                 mono_domain_set (caller_domain, FALSE);
2424                 return;
2425         }
2426         mono_domain_set (caller_domain, FALSE);
2427
2428         thread_data = g_new0 (unload_data, 1);
2429         thread_data->domain = domain;
2430         thread_data->failure_reason = NULL;
2431         thread_data->done = FALSE;
2432         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2433
2434         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2435         domain->state = MONO_APPDOMAIN_UNLOADING;
2436         /* 
2437          * First we create a separate thread for unloading, since
2438          * we might have to abort some threads, including the current one.
2439          */
2440         thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2441         if (thread_handle == NULL)
2442                 return;
2443         name = g_strdup_printf ("Unload thread for domain %x", domain);
2444         mono_thread_info_set_name (tid, name);
2445         mono_thread_info_resume (tid);
2446         g_free (name);
2447
2448         /* Wait for the thread */       
2449         while (!thread_data->done && WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2450                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2451                         /* The unload thread tries to abort us */
2452                         /* The icall wrapper will execute the abort */
2453                         CloseHandle (thread_handle);
2454                         unload_data_unref (thread_data);
2455                         return;
2456                 }
2457         }
2458         CloseHandle (thread_handle);
2459
2460         if (thread_data->failure_reason) {
2461                 /* Roll back the state change */
2462                 domain->state = MONO_APPDOMAIN_CREATED;
2463
2464                 g_warning ("%s", thread_data->failure_reason);
2465
2466                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2467
2468                 g_free (thread_data->failure_reason);
2469                 thread_data->failure_reason = NULL;
2470         }
2471
2472         unload_data_unref (thread_data);
2473 }