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