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