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