[runtime] Remove all NACL support. It was unmaintained for a long time. (#4955)
[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_appdomain_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         MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1178         ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1179 leave:
1180         HANDLE_FUNCTION_RETURN_VAL (ret);
1181 }
1182
1183 MonoAssembly *
1184 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1185                                                                           gboolean refonly)
1186 {
1187         MonoError error;
1188         MonoAssembly *assembly;
1189         MonoDomain *domain = mono_domain_get ();
1190         char *aname_str;
1191
1192         aname_str = mono_stringify_assembly_name (aname);
1193
1194         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1195
1196         assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1197         g_free (aname_str);
1198         mono_error_cleanup (&error);
1199
1200         return assembly;
1201 }
1202         
1203 /*
1204  * LOCKING: assumes assemblies_lock in the domain is already locked.
1205  */
1206 static void
1207 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1208 {
1209         gint i;
1210         GSList *tmp;
1211         gboolean destroy_ht = FALSE;
1212
1213         if (!ass->aname.name)
1214                 return;
1215
1216         if (!ht) {
1217                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1218                 destroy_ht = TRUE;
1219                 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1220                         g_hash_table_insert (ht, tmp->data, tmp->data);
1221                 }
1222         }
1223
1224         /* FIXME: handle lazy loaded assemblies */
1225
1226         if (!g_hash_table_lookup (ht, ass)) {
1227                 mono_assembly_addref (ass);
1228                 g_hash_table_insert (ht, ass, ass);
1229                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1230                 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);
1231         }
1232
1233         if (ass->image->references) {
1234                 for (i = 0; i < ass->image->nreferences; i++) {
1235                         if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1236                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1237                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1238                                 }
1239                         }
1240                 }
1241         }
1242         if (destroy_ht)
1243                 g_hash_table_destroy (ht);
1244 }
1245
1246 static void
1247 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1248 {
1249         HANDLE_FUNCTION_ENTER ();
1250         static MonoClassField *assembly_load_field;
1251         static MonoMethod *assembly_load_method;
1252         MonoError error;
1253         MonoDomain *domain = mono_domain_get ();
1254         MonoClass *klass;
1255         gpointer load_value;
1256         void *params [1];
1257
1258         if (!domain->domain)
1259                 /* This can happen during startup */
1260                 goto leave;
1261 #ifdef ASSEMBLY_LOAD_DEBUG
1262         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1263 #endif
1264         klass = domain->domain->mbr.obj.vtable->klass;
1265
1266         mono_domain_assemblies_lock (domain);
1267         add_assemblies_to_domain (domain, assembly, NULL);
1268         mono_domain_assemblies_unlock (domain);
1269
1270         if (assembly_load_field == NULL) {
1271                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1272                 g_assert (assembly_load_field);
1273         }
1274
1275         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1276         if (load_value == NULL) {
1277                 /* No events waiting to be triggered */
1278                 goto leave;
1279         }
1280
1281         MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1282         mono_error_assert_ok (&error);
1283
1284         if (assembly_load_method == NULL) {
1285                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1286                 g_assert (assembly_load_method);
1287         }
1288
1289         *params = MONO_HANDLE_RAW(ref_assembly);
1290
1291         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1292         mono_error_cleanup (&error);
1293 leave:
1294         HANDLE_FUNCTION_RETURN ();
1295 }
1296
1297 /*
1298  * LOCKING: Acquires the domain assemblies lock.
1299  */
1300 static void
1301 set_domain_search_path (MonoDomain *domain)
1302 {
1303         MonoError error;
1304         MonoAppDomainSetup *setup;
1305         gchar **tmp;
1306         gchar *search_path = NULL;
1307         gint i;
1308         gint npaths = 0;
1309         gchar **pvt_split = NULL;
1310         GError *gerror = NULL;
1311         gint appbaselen = -1;
1312
1313         /* 
1314          * We use the low-level domain assemblies lock, since this is called from
1315          * assembly loads hooks, which means this thread might hold the loader lock.
1316          */
1317         mono_domain_assemblies_lock (domain);
1318
1319         if (!domain->setup) {
1320                 mono_domain_assemblies_unlock (domain);
1321                 return;
1322         }
1323
1324         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1325                 mono_domain_assemblies_unlock (domain);
1326                 return;
1327         }
1328         setup = domain->setup;
1329         if (!setup->application_base) {
1330                 mono_domain_assemblies_unlock (domain);
1331                 return; /* Must set application base to get private path working */
1332         }
1333
1334         npaths++;
1335         
1336         if (setup->private_bin_path) {
1337                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1338                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1339                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1340                         mono_error_cleanup (&error);
1341                         mono_domain_assemblies_unlock (domain);
1342                         return;
1343                 }
1344         }
1345         
1346         if (domain->private_bin_path) {
1347                 if (search_path == NULL)
1348                         search_path = domain->private_bin_path;
1349                 else {
1350                         gchar *tmp2 = search_path;
1351                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1352                         g_free (tmp2);
1353                 }
1354         }
1355         
1356         if (search_path) {
1357                 /*
1358                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1359                  * directories relative to ApplicationBase separated by semicolons (see
1360                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1361                  * The loop below copes with the fact that some Unix applications may use ':' (or
1362                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1363                  * ';' for the subsequent split.
1364                  *
1365                  * The issue was reported in bug #81446
1366                  */
1367
1368 #ifndef TARGET_WIN32
1369                 gint slen;
1370
1371                 slen = strlen (search_path);
1372                 for (i = 0; i < slen; i++)
1373                         if (search_path [i] == ':')
1374                                 search_path [i] = ';';
1375 #endif
1376                 
1377                 pvt_split = g_strsplit (search_path, ";", 1000);
1378                 g_free (search_path);
1379                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1380         }
1381
1382         if (!npaths) {
1383                 if (pvt_split)
1384                         g_strfreev (pvt_split);
1385                 /*
1386                  * Don't do this because the first time is called, the domain
1387                  * setup is not finished.
1388                  *
1389                  * domain->search_path = g_malloc (sizeof (char *));
1390                  * domain->search_path [0] = NULL;
1391                 */
1392                 mono_domain_assemblies_unlock (domain);
1393                 return;
1394         }
1395
1396         if (domain->search_path)
1397                 g_strfreev (domain->search_path);
1398
1399         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1400         tmp [npaths] = NULL;
1401
1402         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1403         if (!mono_error_ok (&error)) {
1404                 mono_error_cleanup (&error);
1405                 g_strfreev (pvt_split);
1406                 g_free (tmp);
1407
1408                 mono_domain_assemblies_unlock (domain);
1409                 return;
1410         }
1411
1412         domain->search_path = tmp;
1413
1414         /* FIXME: is this needed? */
1415         if (strncmp (*tmp, "file://", 7) == 0) {
1416                 gchar *file = *tmp;
1417                 gchar *uri = *tmp;
1418                 gchar *tmpuri;
1419
1420                 if (uri [7] != '/')
1421                         uri = g_strdup_printf ("file:///%s", uri + 7);
1422
1423                 tmpuri = uri;
1424                 uri = mono_escape_uri_string (tmpuri);
1425                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1426                 g_free (uri);
1427
1428                 if (tmpuri != file)
1429                         g_free (tmpuri);
1430
1431                 if (gerror != NULL) {
1432                         g_warning ("%s\n", gerror->message);
1433                         g_error_free (gerror);
1434                         *tmp = file;
1435                 } else {
1436                         g_free (file);
1437                 }
1438         }
1439
1440         for (i = 1; pvt_split && i < npaths; i++) {
1441                 if (g_path_is_absolute (pvt_split [i - 1])) {
1442                         tmp [i] = g_strdup (pvt_split [i - 1]);
1443                 } else {
1444                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1445                 }
1446
1447                 if (strchr (tmp [i], '.')) {
1448                         gchar *reduced;
1449                         gchar *freeme;
1450
1451                         reduced = mono_path_canonicalize (tmp [i]);
1452                         if (appbaselen == -1)
1453                                 appbaselen = strlen (tmp [0]);
1454
1455                         if (strncmp (tmp [0], reduced, appbaselen)) {
1456                                 g_free (reduced);
1457                                 g_free (tmp [i]);
1458                                 tmp [i] = g_strdup ("");
1459                                 continue;
1460                         }
1461
1462                         freeme = tmp [i];
1463                         tmp [i] = reduced;
1464                         g_free (freeme);
1465                 }
1466         }
1467         
1468         if (setup->private_bin_path_probe != NULL) {
1469                 g_free (tmp [0]);
1470                 tmp [0] = g_strdup ("");
1471         }
1472                 
1473         domain->setup->path_changed = FALSE;
1474
1475         g_strfreev (pvt_split);
1476
1477         mono_domain_assemblies_unlock (domain);
1478 }
1479
1480 #ifdef DISABLE_SHADOW_COPY
1481 gboolean
1482 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1483 {
1484         return FALSE;
1485 }
1486
1487 char *
1488 mono_make_shadow_copy (const char *filename, MonoError *error)
1489 {
1490         error_init (error);
1491         return (char *) filename;
1492 }
1493 #else
1494 static gboolean
1495 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1496 {
1497         guint16 *orig, *dest;
1498         gboolean copy_result;
1499         gint32 copy_error;
1500         
1501         strcpy (src + srclen - tail_len, extension);
1502
1503         if (IS_PORTABILITY_CASE) {
1504                 gchar *file = mono_portability_find_file (src, TRUE);
1505
1506                 if (file == NULL)
1507                         return TRUE;
1508
1509                 g_free (file);
1510         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1511                 return TRUE;
1512         }
1513
1514         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1515
1516         strcpy (target + targetlen - tail_len, extension);
1517         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1518         
1519         mono_w32file_delete (dest);
1520
1521         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1522
1523         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1524          * overwritten when updated in their original locations. */
1525         if (copy_result)
1526                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1527
1528         g_free (orig);
1529         g_free (dest);
1530         
1531         return copy_result;
1532 }
1533
1534 static gint32 
1535 get_cstring_hash (const char *str)
1536 {
1537         int len, i;
1538         const char *p;
1539         gint32 h = 0;
1540         
1541         if (!str || !str [0])
1542                 return 0;
1543                 
1544         len = strlen (str);
1545         p = str;
1546         for (i = 0; i < len; i++) {
1547                 h = (h << 5) - h + *p;
1548                 p++;
1549         }
1550         
1551         return h;
1552 }
1553
1554 /*
1555  * Returned memory is malloc'd. Called must free it 
1556  */
1557 static char *
1558 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1559 {
1560         MonoAppDomainSetup *setup;
1561         char *cache_path, *appname;
1562         char *userdir;
1563         char *location;
1564
1565         error_init (error);
1566         
1567         setup = domain->setup;
1568         if (setup->cache_path != NULL && setup->application_name != NULL) {
1569                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1570                 return_val_if_nok (error, NULL);
1571
1572 #ifndef TARGET_WIN32
1573                 {
1574                         gint i;
1575                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1576                                 if (cache_path [i] == '\\')
1577                                         cache_path [i] = '/';
1578                 }
1579 #endif
1580
1581                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1582                 if (!mono_error_ok (error)) {
1583                         g_free (cache_path);
1584                         return NULL;
1585                 }
1586
1587                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1588                 g_free (appname);
1589                 g_free (cache_path);
1590         } else {
1591                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1592                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1593                 g_free (userdir);
1594         }
1595         return location;
1596 }
1597
1598 static char *
1599 get_shadow_assembly_location (const char *filename, MonoError *error)
1600 {
1601         gint32 hash = 0, hash2 = 0;
1602         char name_hash [9];
1603         char path_hash [30];
1604         char *bname = g_path_get_basename (filename);
1605         char *dirname = g_path_get_dirname (filename);
1606         char *location, *tmploc;
1607         MonoDomain *domain = mono_domain_get ();
1608
1609         error_init (error);
1610         
1611         hash = get_cstring_hash (bname);
1612         hash2 = get_cstring_hash (dirname);
1613         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1614         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1615         tmploc = get_shadow_assembly_location_base (domain, error);
1616         if (!mono_error_ok (error)) {
1617                 g_free (bname);
1618                 g_free (dirname);
1619                 return NULL;
1620         }
1621
1622         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1623         g_free (tmploc);
1624         g_free (bname);
1625         g_free (dirname);
1626         return location;
1627 }
1628
1629 static gboolean
1630 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1631 {
1632         struct stat sbuf_dest;
1633         gchar *stat_src;
1634         gchar *real_src = mono_portability_find_file (src, TRUE);
1635
1636         if (!real_src)
1637                 stat_src = (gchar*)src;
1638         else
1639                 stat_src = real_src;
1640
1641         if (stat (stat_src, sbuf_src) == -1) {
1642                 time_t tnow = time (NULL);
1643
1644                 if (real_src)
1645                         g_free (real_src);
1646
1647                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1648                 sbuf_src->st_mtime = tnow;
1649                 sbuf_src->st_atime = tnow;
1650                 return TRUE;
1651         }
1652
1653         if (real_src)
1654                 g_free (real_src);
1655
1656         if (stat (dest, &sbuf_dest) == -1)
1657                 return TRUE;
1658         
1659         if (sbuf_src->st_size == sbuf_dest.st_size &&
1660             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1661                 return FALSE;
1662
1663         return TRUE;
1664 }
1665
1666 static gboolean
1667 shadow_copy_create_ini (const char *shadow, const char *filename)
1668 {
1669         char *dir_name;
1670         char *ini_file;
1671         guint16 *u16_ini;
1672         gboolean result;
1673         guint32 n;
1674         HANDLE *handle;
1675         gchar *full_path;
1676
1677         dir_name = g_path_get_dirname (shadow);
1678         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1679         g_free (dir_name);
1680         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1681                 g_free (ini_file);
1682                 return TRUE;
1683         }
1684
1685         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1686         g_free (ini_file);
1687         if (!u16_ini) {
1688                 return FALSE;
1689         }
1690         handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1691         g_free (u16_ini);
1692         if (handle == INVALID_HANDLE_VALUE) {
1693                 return FALSE;
1694         }
1695
1696         full_path = mono_path_resolve_symlinks (filename);
1697         result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1698         g_free (full_path);
1699         mono_w32file_close (handle);
1700         return result;
1701 }
1702
1703 gboolean
1704 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1705 {
1706         MonoError error;
1707         MonoAppDomainSetup *setup;
1708         gchar *all_dirs;
1709         gchar **dir_ptr;
1710         gchar **directories;
1711         gchar *shadow_status_string;
1712         gchar *base_dir;
1713         gboolean shadow_enabled;
1714         gboolean found = FALSE;
1715
1716         if (domain == NULL)
1717                 return FALSE;
1718
1719         setup = domain->setup;
1720         if (setup == NULL || setup->shadow_copy_files == NULL)
1721                 return FALSE;
1722
1723         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1724         if (!mono_error_ok (&error)) {
1725                 mono_error_cleanup (&error);
1726                 return FALSE;
1727         }
1728         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1729         g_free (shadow_status_string);
1730
1731         if (!shadow_enabled)
1732                 return FALSE;
1733
1734         if (setup->shadow_copy_directories == NULL)
1735                 return TRUE;
1736
1737         /* Is dir_name a shadow_copy destination already? */
1738         base_dir = get_shadow_assembly_location_base (domain, &error);
1739         if (!mono_error_ok (&error)) {
1740                 mono_error_cleanup (&error);
1741                 return FALSE;
1742         }
1743
1744         if (strstr (dir_name, base_dir)) {
1745                 g_free (base_dir);
1746                 return TRUE;
1747         }
1748         g_free (base_dir);
1749
1750         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1751         if (!mono_error_ok (&error)) {
1752                 mono_error_cleanup (&error);
1753                 return FALSE;
1754         }
1755
1756         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1757         dir_ptr = directories;
1758         while (*dir_ptr) {
1759                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1760                         found = TRUE;
1761                         break;
1762                 }
1763                 dir_ptr++;
1764         }
1765         g_strfreev (directories);
1766         g_free (all_dirs);
1767         return found;
1768 }
1769
1770 /*
1771 This function raises exceptions so it can cause as sorts of nasty stuff if called
1772 while holding a lock.
1773 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1774 or NULL if source file not found.
1775 FIXME bubble up the error instead of raising it here
1776 */
1777 char *
1778 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1779 {
1780         MonoError error;
1781         gchar *sibling_source, *sibling_target;
1782         gint sibling_source_len, sibling_target_len;
1783         guint16 *orig, *dest;
1784         guint32 attrs;
1785         char *shadow;
1786         gboolean copy_result;
1787         struct stat src_sbuf;
1788         struct utimbuf utbuf;
1789         char *dir_name = g_path_get_dirname (filename);
1790         MonoDomain *domain = mono_domain_get ();
1791         char *shadow_dir;
1792         gint32 copy_error;
1793
1794         error_init (oerror);
1795
1796         set_domain_search_path (domain);
1797
1798         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1799                 g_free (dir_name);
1800                 return (char *) filename;
1801         }
1802
1803         /* Is dir_name a shadow_copy destination already? */
1804         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1805         if (!mono_error_ok (&error)) {
1806                 mono_error_cleanup (&error);
1807                 g_free (dir_name);
1808                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1809                 return NULL;
1810         }
1811
1812         if (strstr (dir_name, shadow_dir)) {
1813                 g_free (shadow_dir);
1814                 g_free (dir_name);
1815                 return (char *) filename;
1816         }
1817         g_free (shadow_dir);
1818         g_free (dir_name);
1819
1820         shadow = get_shadow_assembly_location (filename, &error);
1821         if (!mono_error_ok (&error)) {
1822                 mono_error_cleanup (&error);
1823                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1824                 return NULL;
1825         }
1826
1827         if (g_ensure_directory_exists (shadow) == FALSE) {
1828                 g_free (shadow);
1829                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1830                 return NULL;
1831         }       
1832
1833         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1834                 return (char*) shadow;
1835
1836         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1837         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1838         mono_w32file_delete (dest);
1839
1840         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1841          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1842          * and not have it runtime error" */
1843         attrs = mono_w32file_get_attributes (orig);
1844         if (attrs == INVALID_FILE_ATTRIBUTES) {
1845                 g_free (shadow);
1846                 return (char *)filename;
1847         }
1848
1849         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1850
1851         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1852          * overwritten when updated in their original locations. */
1853         if (copy_result)
1854                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1855
1856         g_free (dest);
1857         g_free (orig);
1858
1859         if (copy_result == FALSE) {
1860                 g_free (shadow);
1861
1862                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1863                 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1864                         return NULL; /* file not found, shadow copy failed */
1865
1866                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1867                 return NULL;
1868         }
1869
1870         /* attempt to copy .mdb, .config if they exist */
1871         sibling_source = g_strconcat (filename, ".config", NULL);
1872         sibling_source_len = strlen (sibling_source);
1873         sibling_target = g_strconcat (shadow, ".config", NULL);
1874         sibling_target_len = strlen (sibling_target);
1875
1876         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1877         if (copy_result)
1878                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".pdb", sibling_target, sibling_target_len, 11);
1879         if (copy_result)
1880                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1881         
1882         g_free (sibling_source);
1883         g_free (sibling_target);
1884         
1885         if (!copy_result)  {
1886                 g_free (shadow);
1887                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1888                 return NULL;
1889         }
1890
1891         /* Create a .ini file containing the original assembly location */
1892         if (!shadow_copy_create_ini (shadow, filename)) {
1893                 g_free (shadow);
1894                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1895                 return NULL;
1896         }
1897
1898         utbuf.actime = src_sbuf.st_atime;
1899         utbuf.modtime = src_sbuf.st_mtime;
1900         utime (shadow, &utbuf);
1901         
1902         return shadow;
1903 }
1904 #endif /* DISABLE_SHADOW_COPY */
1905
1906 /**
1907  * mono_domain_from_appdomain:
1908  */
1909 MonoDomain *
1910 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1911 {
1912         HANDLE_FUNCTION_ENTER ();
1913         MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1914         MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1915         HANDLE_FUNCTION_RETURN_VAL (result);
1916 }
1917
1918 MonoDomain *
1919 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1920 {
1921         HANDLE_FUNCTION_ENTER ();
1922         MonoDomain *dom = NULL;
1923         if (MONO_HANDLE_IS_NULL (appdomain))
1924                 goto leave;
1925
1926         if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1927                 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1928                 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1929                 
1930                 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1931         } else
1932                 dom = MONO_HANDLE_GETVAL (appdomain, data);
1933
1934 leave:
1935         HANDLE_FUNCTION_RETURN_VAL (dom);
1936 }
1937
1938
1939 static gboolean
1940 try_load_from (MonoAssembly **assembly,
1941                const gchar *path1, const gchar *path2,
1942                const gchar *path3, const gchar *path4,
1943                gboolean refonly, gboolean is_private,
1944                MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1945 {
1946         gchar *fullpath;
1947         gboolean found = FALSE;
1948         
1949         *assembly = NULL;
1950         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1951
1952         if (IS_PORTABILITY_SET) {
1953                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1954                 if (new_fullpath) {
1955                         g_free (fullpath);
1956                         fullpath = new_fullpath;
1957                         found = TRUE;
1958                 }
1959         } else
1960                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1961         
1962         if (found)
1963                 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1964
1965         g_free (fullpath);
1966         return (*assembly != NULL);
1967 }
1968
1969 static MonoAssembly *
1970 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1971 {
1972         MonoAssembly *result = NULL;
1973         gchar **path;
1974         gchar *filename;
1975         const gchar *local_culture;
1976         gint len;
1977         gboolean is_private = FALSE;
1978
1979         if (!culture || *culture == '\0') {
1980                 local_culture = "";
1981         } else {
1982                 local_culture = culture;
1983         }
1984
1985         filename =  g_strconcat (name, ".dll", NULL);
1986         len = strlen (filename);
1987
1988         for (path = search_path; *path; path++) {
1989                 if (**path == '\0') {
1990                         is_private = TRUE;
1991                         continue; /* Ignore empty ApplicationBase */
1992                 }
1993
1994                 /* See test cases in bug #58992 and bug #57710 */
1995                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1996                 strcpy (filename + len - 4, ".dll");
1997                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1998                         break;
1999
2000                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2001                 strcpy (filename + len - 4, ".exe");
2002                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2003                         break;
2004
2005                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2006                 strcpy (filename + len - 4, ".dll");
2007                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2008                         break;
2009
2010                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2011                 strcpy (filename + len - 4, ".exe");
2012                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2013                         break;
2014         }
2015
2016         g_free (filename);
2017         return result;
2018 }
2019
2020 /*
2021  * Try loading the assembly from ApplicationBase and PrivateBinPath 
2022  * and then from assemblies_path if any.
2023  * LOCKING: This is called from the assembly loading code, which means the caller
2024  * might hold the loader lock. Thus, this function must not acquire the domain lock.
2025  */
2026 static MonoAssembly *
2027 mono_domain_assembly_preload (MonoAssemblyName *aname,
2028                               gchar **assemblies_path,
2029                               gpointer user_data)
2030 {
2031         MonoDomain *domain = mono_domain_get ();
2032         MonoAssembly *result = NULL;
2033         gboolean refonly = GPOINTER_TO_UINT (user_data);
2034
2035         set_domain_search_path (domain);
2036
2037         MonoAssemblyCandidatePredicate predicate = NULL;
2038         void* predicate_ud = NULL;
2039 #if !defined(DISABLE_DESKTOP_LOADER)
2040         if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2041                 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2042                 predicate_ud = aname;
2043         }
2044 #endif
2045         if (domain->search_path && domain->search_path [0] != NULL) {
2046                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2047                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2048                         for (int i = 0; domain->search_path [i]; i++) {
2049                                 const char *p = domain->search_path[i];
2050                                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2051                         }
2052                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);                    
2053                 }
2054                 result = real_load (domain->search_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2055         }
2056
2057         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2058                 result = real_load (assemblies_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2059         }
2060
2061         return result;
2062 }
2063
2064 /*
2065  * Check whenever a given assembly was already loaded in the current appdomain.
2066  */
2067 static MonoAssembly *
2068 mono_domain_assembly_search (MonoAssemblyName *aname,
2069                                                          gpointer user_data)
2070 {
2071         MonoDomain *domain = mono_domain_get ();
2072         GSList *tmp;
2073         MonoAssembly *ass;
2074         gboolean refonly = GPOINTER_TO_UINT (user_data);
2075
2076         mono_domain_assemblies_lock (domain);
2077         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2078                 ass = (MonoAssembly *)tmp->data;
2079                 /* Dynamic assemblies can't match here in MS.NET */
2080                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2081                         continue;
2082
2083                 mono_domain_assemblies_unlock (domain);
2084                 return ass;
2085         }
2086         mono_domain_assemblies_unlock (domain);
2087
2088         return NULL;
2089 }
2090
2091 MonoReflectionAssemblyHandle
2092 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2093 {
2094         error_init (error);
2095         MonoDomain *domain = mono_domain_get ();
2096         char *name, *filename;
2097         MonoImageOpenStatus status = MONO_IMAGE_OK;
2098         MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2099
2100         name = NULL;
2101         result = NULL;
2102
2103         if (fname == NULL) {
2104                 mono_error_set_argument_null (error, "assemblyFile", "");
2105                 goto leave;
2106         }
2107                 
2108         name = filename = mono_string_handle_to_utf8 (fname, error);
2109         if (!is_ok (error))
2110                 goto leave;
2111         
2112         MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2113         
2114         if (!ass) {
2115                 if (status == MONO_IMAGE_IMAGE_INVALID)
2116                         mono_error_set_bad_image_name (error, g_strdup (name), "");
2117                 else
2118                         mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2119                 goto leave;
2120         }
2121
2122         result = mono_assembly_get_object_handle (domain, ass, error);
2123
2124 leave:
2125         g_free (name);
2126         return result;
2127 }
2128
2129 MonoReflectionAssemblyHandle
2130 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, 
2131                                             MonoArrayHandle raw_assembly,
2132                                             MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2133                                             MonoBoolean refonly,
2134                                             MonoError *error)
2135 {
2136         error_init (error);
2137         MonoAssembly *ass;
2138         MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2139         MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2140         MonoImageOpenStatus status;
2141         guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2142
2143         /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2144         char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2145         if (!assembly_data) {
2146                 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2147                 return refass;
2148         }
2149         uint32_t gchandle;
2150         mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2151         memcpy (assembly_data, raw_data, raw_assembly_len);
2152         mono_gchandle_free (gchandle); /* unpin */
2153         MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2154         
2155         MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2156
2157         if (!image) {
2158                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2159                 return refass;
2160         }
2161
2162         if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2163                 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2164                 uint32_t symbol_gchandle;
2165                 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2166                 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2167                 mono_gchandle_free (symbol_gchandle);
2168         }
2169
2170         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2171
2172
2173         if (!ass) {
2174                 mono_image_close (image);
2175                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2176                 return refass; 
2177         }
2178
2179         refass = mono_assembly_get_object_handle (domain, ass, error);
2180         if (!MONO_HANDLE_IS_NULL(refass))
2181                 MONO_HANDLE_SET (refass, evidence, evidence);
2182         return refass;
2183 }
2184
2185 MonoReflectionAssemblyHandle
2186 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2187 {
2188         error_init (error);
2189         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2190         MonoImageOpenStatus status = MONO_IMAGE_OK;
2191         MonoAssembly *ass;
2192         MonoAssemblyName aname;
2193         gchar *name = NULL;
2194         gboolean parsed;
2195
2196         g_assert (assRef);
2197
2198         name = mono_string_handle_to_utf8 (assRef, error);
2199         if (!is_ok (error))
2200                 goto fail;
2201         parsed = mono_assembly_name_parse (name, &aname);
2202         g_free (name);
2203
2204         if (!parsed) {
2205                 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2206                 /* This is a parse error... */
2207                 if (!refOnly) {
2208                         MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2209                         if (!is_ok (error))
2210                                 goto fail;
2211                         if (assm) {
2212                                 refass = mono_assembly_get_object_handle (domain, assm, error);
2213                                 if (!is_ok (error))
2214                                         goto fail;
2215                         }
2216                 }
2217                 return refass;
2218         }
2219
2220         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2221         mono_assembly_name_free (&aname);
2222
2223         if (!ass) {
2224                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2225                 if (!refOnly) {
2226                         ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2227                         if (!is_ok (error))
2228                                 goto fail;
2229                 }
2230                 if (!ass)
2231                         goto fail;
2232         }
2233
2234         g_assert (ass);
2235         MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2236         if (!is_ok (error))
2237                 goto fail;
2238
2239         MONO_HANDLE_SET (refass, evidence, evidence);
2240
2241         return refass;
2242 fail:
2243         return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2244 }
2245
2246 void
2247 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2248 {
2249         error_init (error);
2250         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2251
2252         if (NULL == domain) {
2253                 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2254                 return;
2255         }
2256         
2257         if (domain == mono_get_root_domain ()) {
2258                 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2259                 return;
2260         }
2261
2262         /* 
2263          * Unloading seems to cause problems when running NUnit/NAnt, hence
2264          * this workaround.
2265          */
2266         if (g_hasenv ("MONO_NO_UNLOAD"))
2267                 return;
2268
2269         MonoException *exc = NULL;
2270         mono_domain_try_unload (domain, (MonoObject**)&exc);
2271         if (exc)
2272                 mono_error_set_exception_instance (error, exc);
2273 }
2274
2275 gboolean
2276 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2277 {
2278         error_init (error);
2279         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2280
2281         if (!domain)
2282                 return TRUE;
2283
2284         return mono_domain_is_unloading (domain);
2285 }
2286
2287 void
2288 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2289 {
2290         error_init (error);
2291         mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2292         mono_error_assert_ok (error);
2293 }
2294
2295 gint32
2296 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2297                                             MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2298                                             MonoError *error)
2299 {
2300         error_init (error);
2301         MonoImage *image;
2302         MonoMethod *method;
2303
2304         g_assert (!MONO_HANDLE_IS_NULL (refass));
2305         MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2306         image = assembly->image;
2307         g_assert (image);
2308
2309         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2310
2311         if (!method)
2312                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2313
2314         if (MONO_HANDLE_IS_NULL (args)) {
2315                 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2316                 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2317                 mono_error_assert_ok (error);
2318         }
2319
2320         int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2321         return res;
2322 }
2323
2324 gint32 
2325 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2326 {
2327         return ad->data->domain_id;
2328 }
2329
2330 MonoAppDomainHandle
2331 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2332 {
2333         error_init (error);
2334         MonoDomain *old_domain = mono_domain_get ();
2335
2336         if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2337                 mono_error_set_appdomain_unloaded (error);
2338                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2339         }
2340
2341         return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2342 }
2343
2344 MonoAppDomainHandle
2345 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2346 {
2347         MonoDomain *current_domain = mono_domain_get ();
2348         MonoDomain *domain = mono_domain_get_by_id (domainid);
2349
2350         if (!domain || !mono_domain_set (domain, FALSE)) {
2351                 mono_error_set_appdomain_unloaded (error);
2352                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2353         }
2354
2355         return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2356 }
2357
2358 void
2359 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2360 {
2361         error_init (error);
2362         mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2363 }
2364
2365 void
2366 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2367 {
2368         error_init (error);
2369         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2370
2371         if (!domain) {
2372                 /* 
2373                  * Raise an exception to prevent the managed code from executing a pop
2374                  * later.
2375                  */
2376                 mono_error_set_appdomain_unloaded (error);
2377                 return;
2378         }
2379
2380         mono_thread_push_appdomain_ref (domain);
2381 }
2382
2383 void
2384 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2385 {
2386         error_init (error);
2387         mono_thread_pop_appdomain_ref ();
2388 }
2389
2390 MonoAppContextHandle
2391 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2392 {
2393         error_init (error);
2394         return mono_context_get_handle ();
2395 }
2396
2397 MonoAppContextHandle
2398 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2399 {
2400         error_init (error);
2401         return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2402 }
2403
2404 MonoAppContextHandle
2405 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2406 {
2407         error_init (error);
2408         MonoAppContextHandle old_context = mono_context_get_handle ();
2409
2410         mono_context_set_handle (mc);
2411
2412         return old_context;
2413 }
2414
2415 MonoStringHandle
2416 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2417 {
2418         error_init (error);
2419         MonoDomain* mono_root_domain = mono_get_root_domain ();
2420         mono_domain_lock (mono_root_domain);
2421         if (process_guid_set) {
2422                 mono_domain_unlock (mono_root_domain);
2423                 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2424         }
2425         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2426         memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2427         mono_gchandle_free (gchandle);
2428         process_guid_set = TRUE;
2429         mono_domain_unlock (mono_root_domain);
2430         return newguid;
2431 }
2432
2433 /**
2434  * mono_domain_is_unloading:
2435  */
2436 gboolean
2437 mono_domain_is_unloading (MonoDomain *domain)
2438 {
2439         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2440                 return TRUE;
2441         else
2442                 return FALSE;
2443 }
2444
2445 static void
2446 clear_cached_vtable (MonoVTable *vtable)
2447 {
2448         MonoClass *klass = vtable->klass;
2449         MonoDomain *domain = vtable->domain;
2450         MonoClassRuntimeInfo *runtime_info;
2451         void *data;
2452
2453         runtime_info = klass->runtime_info;
2454         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2455                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2456         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2457                 mono_gc_free_fixed (data);
2458 }
2459
2460 static G_GNUC_UNUSED void
2461 zero_static_data (MonoVTable *vtable)
2462 {
2463         MonoClass *klass = vtable->klass;
2464         void *data;
2465
2466         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2467                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2468 }
2469
2470 typedef struct unload_data {
2471         gboolean done;
2472         MonoDomain *domain;
2473         char *failure_reason;
2474         gint32 refcount;
2475 } unload_data;
2476
2477 static void
2478 unload_data_unref (unload_data *data)
2479 {
2480         gint32 count;
2481         do {
2482                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2483                 g_assert (count >= 1 && count <= 2);
2484                 if (count == 1) {
2485                         g_free (data);
2486                         return;
2487                 }
2488         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2489 }
2490
2491 static void
2492 deregister_reflection_info_roots_from_list (MonoImage *image)
2493 {
2494         GSList *list = image->reflection_info_unregister_classes;
2495
2496         while (list) {
2497                 MonoClass *klass = (MonoClass *)list->data;
2498
2499                 mono_class_free_ref_info (klass);
2500
2501                 list = list->next;
2502         }
2503
2504         image->reflection_info_unregister_classes = NULL;
2505 }
2506
2507 static void
2508 deregister_reflection_info_roots (MonoDomain *domain)
2509 {
2510         GSList *list;
2511
2512         mono_domain_assemblies_lock (domain);
2513         for (list = domain->domain_assemblies; list; list = list->next) {
2514                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2515                 MonoImage *image = assembly->image;
2516                 int i;
2517
2518                 /*
2519                  * No need to take the image lock here since dynamic images are appdomain bound and
2520                  * at this point the mutator is gone.  Taking the image lock here would mean
2521                  * promoting it from a simple lock to a complex lock, which we better avoid if
2522                  * possible.
2523                  */
2524                 if (image_is_dynamic (image))
2525                         deregister_reflection_info_roots_from_list (image);
2526
2527                 for (i = 0; i < image->module_count; ++i) {
2528                         MonoImage *module = image->modules [i];
2529                         if (module && image_is_dynamic (module))
2530                                 deregister_reflection_info_roots_from_list (module);
2531                 }
2532         }
2533         mono_domain_assemblies_unlock (domain);
2534 }
2535
2536 static gsize WINAPI
2537 unload_thread_main (void *arg)
2538 {
2539         MonoError error;
2540         unload_data *data = (unload_data*)arg;
2541         MonoDomain *domain = data->domain;
2542         MonoInternalThread *internal;
2543         int i;
2544
2545         internal = mono_thread_internal_current ();
2546
2547         MonoString *thread_name_str = mono_string_new_checked (mono_domain_get (), "Domain unloader", &error);
2548         if (is_ok (&error))
2549                 mono_thread_set_name_internal (internal, thread_name_str, TRUE, FALSE, &error);
2550         if (!is_ok (&error)) {
2551                 data->failure_reason = g_strdup (mono_error_get_message (&error));
2552                 mono_error_cleanup (&error);
2553                 goto failure;
2554         }
2555
2556         /* 
2557          * FIXME: Abort our parent thread last, so we can return a failure 
2558          * indication if aborting times out.
2559          */
2560         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2561                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2562                 goto failure;
2563         }
2564
2565         if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2566                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2567                 goto failure;
2568         }
2569
2570         /* Finalize all finalizable objects in the doomed appdomain */
2571         if (!mono_domain_finalize (domain, -1)) {
2572                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2573                 goto failure;
2574         }
2575
2576         /* Clear references to our vtables in class->runtime_info.
2577          * We also hold the loader lock because we're going to change
2578          * class->runtime_info.
2579          */
2580
2581         mono_loader_lock (); //FIXME why do we need the loader lock here?
2582         mono_domain_lock (domain);
2583 #ifdef HAVE_SGEN_GC
2584         /*
2585          * We need to make sure that we don't have any remsets
2586          * pointing into static data of the to-be-freed domain because
2587          * at the next collections they would be invalid.  So what we
2588          * do is we first zero all static data and then do a minor
2589          * collection.  Because all references in the static data will
2590          * now be null we won't do any unnecessary copies and after
2591          * the collection there won't be any more remsets.
2592          */
2593         for (i = 0; i < domain->class_vtable_array->len; ++i)
2594                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2595         mono_gc_collect (0);
2596 #endif
2597         for (i = 0; i < domain->class_vtable_array->len; ++i)
2598                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2599         deregister_reflection_info_roots (domain);
2600
2601         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2602
2603         mono_domain_unlock (domain);
2604         mono_loader_unlock ();
2605
2606         domain->state = MONO_APPDOMAIN_UNLOADED;
2607
2608         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2609
2610         /* remove from the handle table the items related to this domain */
2611         mono_gchandle_free_domain (domain);
2612
2613         mono_domain_free (domain, FALSE);
2614
2615         mono_gc_collect (mono_gc_max_generation ());
2616
2617         mono_atomic_store_release (&data->done, TRUE);
2618         unload_data_unref (data);
2619         return 0;
2620
2621 failure:
2622         mono_atomic_store_release (&data->done, TRUE);
2623         unload_data_unref (data);
2624         return 1;
2625 }
2626
2627 /**
2628  * mono_domain_unload:
2629  * \param domain The domain to unload
2630  *
2631  * Unloads an appdomain. Follows the process outlined in the comment
2632  * for \c mono_domain_try_unload.
2633  */
2634 void
2635 mono_domain_unload (MonoDomain *domain)
2636 {
2637         MonoObject *exc = NULL;
2638         mono_domain_try_unload (domain, &exc);
2639 }
2640
2641 static MonoThreadInfoWaitRet
2642 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2643 {
2644         MonoThreadInfoWaitRet result;
2645
2646         MONO_ENTER_GC_SAFE;
2647         result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2648         MONO_EXIT_GC_SAFE;
2649
2650         return result;
2651 }
2652
2653 /**
2654  * mono_domain_unload:
2655  * \param domain The domain to unload
2656  * \param exc Exception information
2657  *
2658  *  Unloads an appdomain. Follows the process outlined in:
2659  *  http://blogs.gotdotnet.com/cbrumme
2660  *
2661  *  If doing things the 'right' way is too hard or complex, we do it the 
2662  *  'simple' way, which means do everything needed to avoid crashes and
2663  *  memory leaks, but not much else.
2664  *
2665  *  It is required to pass a valid reference to the exc argument, upon return
2666  *  from this function *exc will be set to the exception thrown, if any.
2667  *
2668  *  If this method is not called from an icall (embedded scenario for instance),
2669  *  it must not be called with any managed frames on the stack, since the unload
2670  *  process could end up trying to abort the current thread.
2671  */
2672 void
2673 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2674 {
2675         MonoError error;
2676         MonoThreadHandle *thread_handle;
2677         MonoAppDomainState prev_state;
2678         MonoMethod *method;
2679         unload_data *thread_data;
2680         MonoInternalThread *internal;
2681         MonoDomain *caller_domain = mono_domain_get ();
2682
2683         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2684
2685         /* Atomically change our state to UNLOADING */
2686         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2687                 MONO_APPDOMAIN_UNLOADING_START,
2688                 MONO_APPDOMAIN_CREATED);
2689         if (prev_state != MONO_APPDOMAIN_CREATED) {
2690                 switch (prev_state) {
2691                 case MONO_APPDOMAIN_UNLOADING_START:
2692                 case MONO_APPDOMAIN_UNLOADING:
2693                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2694                         return;
2695                 case MONO_APPDOMAIN_UNLOADED:
2696                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2697                         return;
2698                 default:
2699                         g_warning ("Invalid appdomain state %d", prev_state);
2700                         g_assert_not_reached ();
2701                 }
2702         }
2703
2704         mono_domain_set (domain, FALSE);
2705         /* Notify OnDomainUnload listeners */
2706         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2707         g_assert (method);
2708
2709         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2710
2711         if (!mono_error_ok (&error)) {
2712                 if (*exc)
2713                         mono_error_cleanup (&error);
2714                 else
2715                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2716         }
2717
2718         if (*exc) {
2719                 /* Roll back the state change */
2720                 domain->state = MONO_APPDOMAIN_CREATED;
2721                 mono_domain_set (caller_domain, FALSE);
2722                 return;
2723         }
2724         mono_domain_set (caller_domain, FALSE);
2725
2726         thread_data = g_new0 (unload_data, 1);
2727         thread_data->domain = domain;
2728         thread_data->failure_reason = NULL;
2729         thread_data->done = FALSE;
2730         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2731
2732         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2733         domain->state = MONO_APPDOMAIN_UNLOADING;
2734         /* 
2735          * First we create a separate thread for unloading, since
2736          * we might have to abort some threads, including the current one.
2737          *
2738          * Have to attach to the runtime so shutdown can wait for this thread.
2739          *
2740          * Force it to be attached to avoid racing during shutdown.
2741          */
2742         internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2743         mono_error_assert_ok (&error);
2744
2745         thread_handle = mono_threads_open_thread_handle (internal->handle);
2746
2747         /* Wait for the thread */       
2748         while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2749                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2750                         /* The unload thread tries to abort us */
2751                         /* The icall wrapper will execute the abort */
2752                         mono_threads_close_thread_handle (thread_handle);
2753                         unload_data_unref (thread_data);
2754                         return;
2755                 }
2756         }
2757
2758         mono_threads_close_thread_handle (thread_handle);
2759
2760         if (thread_data->failure_reason) {
2761                 /* Roll back the state change */
2762                 domain->state = MONO_APPDOMAIN_CREATED;
2763
2764                 g_warning ("%s", thread_data->failure_reason);
2765
2766                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2767
2768                 g_free (thread_data->failure_reason);
2769                 thread_data->failure_reason = NULL;
2770         }
2771
2772         unload_data_unref (thread_data);
2773 }