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