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