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