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