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