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