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