[runtime] New profiler 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_RAISE (domain_name, (data, data->friendly_name));
640
641         MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
642         if (MONO_HANDLE_IS_NULL (app_base)) {
643                 /* Inherit from the root domain since MS.NET does this */
644                 MonoDomain *root = mono_get_root_domain ();
645                 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
646                 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
647                 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
648                         /* N.B. new string is in the new domain */
649                         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
650                         MonoStringHandle s = mono_string_new_utf16_handle (data, mono_string_chars (MONO_HANDLE_RAW (root_app_base)), mono_string_handle_length (root_app_base), error);
651                         mono_gchandle_free (gchandle);
652                         if (!is_ok (error)) {
653                                 g_free (data->friendly_name);
654                                 goto leave;
655                         }
656                         MONO_HANDLE_SET (setup, application_base, s);
657                 }
658         }
659
660         mono_context_init_checked (data, error);
661         if (!is_ok (error))
662                 goto leave;
663
664         data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
665         if (!mono_error_ok (error)) {
666                 g_free (data->friendly_name);
667                 goto leave;
668         }
669
670         mono_domain_set_options_from_config (data);
671         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
672
673 #ifndef DISABLE_SHADOW_COPY
674         /*FIXME, guard this for when the debugger is not running */
675         char *shadow_location = get_shadow_assembly_location_base (data, error);
676         if (!mono_error_ok (error)) {
677                 g_free (data->friendly_name);
678                 goto leave;
679         }
680
681         g_free (shadow_location);
682 #endif
683
684         create_domain_objects (data);
685
686         MONO_HANDLE_ASSIGN (result, ad);
687 leave:
688         HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
689 }
690
691 /**
692  * mono_domain_has_type_resolve:
693  * \param domain application domain being looked up
694  *
695  * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
696  */
697 gboolean
698 mono_domain_has_type_resolve (MonoDomain *domain)
699 {
700         static MonoClassField *field = NULL;
701         MonoObject *o;
702
703         if (field == NULL) {
704                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
705                 g_assert (field);
706         }
707
708         /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
709         if (!domain->domain)
710                 return FALSE;
711
712         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
713         return o != NULL;
714 }
715
716 /**
717  * mono_domain_try_type_resolve:
718  * \param domain application domainwhere the name where the type is going to be resolved
719  * \param name the name of the type to resolve or NULL.
720  * \param tb A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
721  *
722  * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
723  * the assembly that matches name.
724  *
725  * If \p name is null, the value of \c ((TypeBuilder)tb).FullName is used instead
726  *
727  * \returns A \c MonoReflectionAssembly or NULL if not found
728  */
729 MonoReflectionAssembly *
730 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
731 {
732         MonoError error;
733         MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
734         mono_error_cleanup (&error);
735
736         return ret;
737 }
738
739 MonoReflectionAssembly *
740 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
741 {
742         static MonoMethod *method = NULL;
743         MonoReflectionAssembly *ret;
744         void *params [1];
745
746         error_init (error);
747
748         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
749
750         if (method == NULL) {
751                 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
752                 if (method == NULL) {
753                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
754                         return NULL;
755                 }
756         }
757
758         if (name) {
759                 *params = (MonoObject*)mono_string_new_checked (mono_domain_get (), name, error);
760                 return_val_if_nok (error, NULL);
761         } else
762                 *params = tb;
763
764         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
765         return_val_if_nok (error, NULL);
766
767         return ret;
768 }
769
770 /**
771  * mono_domain_owns_vtable_slot:
772  * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
773  */
774 gboolean
775 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
776 {
777         gboolean res;
778
779         mono_domain_lock (domain);
780         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
781         mono_domain_unlock (domain);
782         return res;
783 }
784
785 /**
786  * mono_domain_set:
787  * \param domain domain
788  * \param force force setting.
789  *
790  * Set the current appdomain to \p domain. If \p force is set, set it even
791  * if it is being unloaded.
792  *
793  * \returns TRUE on success; FALSE if the domain is unloaded
794  */
795 gboolean
796 mono_domain_set (MonoDomain *domain, gboolean force)
797 {
798         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
799                 return FALSE;
800
801         mono_domain_set_internal (domain);
802
803         return TRUE;
804 }
805
806 MonoObjectHandle
807 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
808 {
809         error_init (error);
810
811         if (MONO_HANDLE_IS_NULL (name)) {
812                 mono_error_set_argument_null (error, "name", "");
813                 return NULL_HANDLE;
814         }
815
816         g_assert (!MONO_HANDLE_IS_NULL (ad));
817         MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
818         g_assert (add);
819
820         char *str = mono_string_handle_to_utf8 (name, error);
821         return_val_if_nok (error, NULL_HANDLE);
822
823         mono_domain_lock (add);
824
825         MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
826         MonoStringHandle o;
827         if (!strcmp (str, "APPBASE"))
828                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
829         else if (!strcmp (str, "APP_CONFIG_FILE"))
830                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
831         else if (!strcmp (str, "DYNAMIC_BASE"))
832                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
833         else if (!strcmp (str, "APP_NAME"))
834                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
835         else if (!strcmp (str, "CACHE_BASE"))
836                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
837         else if (!strcmp (str, "PRIVATE_BINPATH"))
838                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
839         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
840                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
841         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
842                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
843         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
844                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
845         else 
846                 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
847
848         mono_domain_unlock (add);
849         g_free (str);
850
851         return MONO_HANDLE_CAST (MonoObject, o);
852 }
853
854 void
855 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
856 {
857         error_init (error);
858
859         if (MONO_HANDLE_IS_NULL (name)) {
860                 mono_error_set_argument_null (error, "name", "");
861                 return;
862         }
863
864         g_assert (!MONO_HANDLE_IS_NULL (ad));
865         MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
866         g_assert (add);
867
868         mono_domain_lock (add);
869
870         mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
871
872         mono_domain_unlock (add);
873 }
874
875 MonoAppDomainSetupHandle
876 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
877 {
878         error_init (error);
879         g_assert (!MONO_HANDLE_IS_NULL (ad));
880         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
881         g_assert (domain);
882
883         return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
884 }
885
886 MonoStringHandle
887 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
888 {
889         error_init (error);
890         g_assert (!MONO_HANDLE_IS_NULL (ad));
891         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
892         g_assert (domain);
893
894         return mono_string_new_handle (domain, domain->friendly_name, error);
895 }
896
897 MonoAppDomainHandle
898 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
899 {
900         error_init (error);
901         MonoDomain *add = mono_domain_get ();
902
903         return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
904 }
905
906 MonoAppDomainHandle
907 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
908 {
909         error_init (error);
910         MonoDomain *root = mono_get_root_domain ();
911
912         return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
913 }
914
915 MonoBoolean
916 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
917 {
918         MonoDomain *domain = mono_domain_get ();
919
920         return domain->throw_unobserved_task_exceptions;
921 }
922
923 static char*
924 get_attribute_value (const gchar **attribute_names, 
925                      const gchar **attribute_values, 
926                      const char *att_name)
927 {
928         int n;
929         for (n = 0; attribute_names [n] != NULL; n++) {
930                 if (strcmp (attribute_names [n], att_name) == 0)
931                         return g_strdup (attribute_values [n]);
932         }
933         return NULL;
934 }
935
936 static void
937 start_element (GMarkupParseContext *context, 
938                const gchar         *element_name,
939                const gchar        **attribute_names,
940                const gchar        **attribute_values,
941                gpointer             user_data,
942                GError             **error)
943 {
944         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
945         
946         if (strcmp (element_name, "runtime") == 0) {
947                 runtime_config->runtime_count++;
948                 return;
949         }
950
951         if (strcmp (element_name, "assemblyBinding") == 0) {
952                 runtime_config->assemblybinding_count++;
953                 return;
954         }
955
956         if (runtime_config->runtime_count != 1)
957                 return;
958
959         if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
960                 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
961
962                 if (value && g_ascii_strcasecmp (value, "true") == 0)
963                         runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
964         }
965
966         if (runtime_config->assemblybinding_count != 1)
967                 return;
968
969         if (strcmp (element_name, "probing") != 0)
970                 return;
971
972         g_free (runtime_config->domain->private_bin_path);
973         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
974         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
975                 g_free (runtime_config->domain->private_bin_path);
976                 runtime_config->domain->private_bin_path = NULL;
977                 return;
978         }
979 }
980
981 static void
982 end_element (GMarkupParseContext *context,
983              const gchar         *element_name,
984              gpointer             user_data,
985              GError             **error)
986 {
987         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
988         if (strcmp (element_name, "runtime") == 0)
989                 runtime_config->runtime_count--;
990         else if (strcmp (element_name, "assemblyBinding") == 0)
991                 runtime_config->assemblybinding_count--;
992 }
993
994 static void
995 parse_error   (GMarkupParseContext *context, GError *error, gpointer user_data)
996 {
997         RuntimeConfig *state = (RuntimeConfig *)user_data;
998         const gchar *msg;
999         const gchar *filename;
1000
1001         filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
1002         msg = error && error->message ? error->message : "";
1003         g_warning ("Error parsing %s: %s", filename, msg);
1004 }
1005
1006 static const GMarkupParser
1007 mono_parser = {
1008         start_element,
1009         end_element,
1010         NULL,
1011         NULL,
1012         parse_error
1013 };
1014
1015 void
1016 mono_domain_set_options_from_config (MonoDomain *domain)
1017 {
1018         MonoError error;
1019         gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
1020         gsize len;
1021         GMarkupParseContext *context;
1022         RuntimeConfig runtime_config;
1023         gint offset;
1024         
1025         if (!domain || !domain->setup || !domain->setup->configuration_file)
1026                 return;
1027
1028         config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1029         if (!mono_error_ok (&error)) {
1030                 mono_error_cleanup (&error);
1031                 goto free_and_out;
1032         }
1033
1034         config_file_path = mono_portability_find_file (config_file_name, TRUE);
1035         if (!config_file_path)
1036                 config_file_path = config_file_name;
1037
1038         if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1039                 goto free_and_out;
1040
1041         runtime_config.runtime_count = 0;
1042         runtime_config.assemblybinding_count = 0;
1043         runtime_config.domain = domain;
1044         runtime_config.filename = config_file_path;
1045         
1046         offset = 0;
1047         if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1048                 offset = 3; /* Skip UTF-8 BOM */
1049
1050         context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1051         if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1052                 g_markup_parse_context_end_parse (context, NULL);
1053         g_markup_parse_context_free (context);
1054
1055   free_and_out:
1056         g_free (text);
1057         if (config_file_name != config_file_path)
1058                 g_free (config_file_name);
1059         g_free (config_file_path);
1060 }
1061
1062 MonoAppDomainHandle
1063 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1064 {
1065         error_init (error);
1066         MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1067
1068 #ifdef DISABLE_APPDOMAINS
1069         mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1070 #else
1071         char *fname;
1072
1073         fname = mono_string_handle_to_utf8 (friendly_name, error);
1074         return_val_if_nok (error, ad);
1075         ad = mono_domain_create_appdomain_internal (fname, setup, error);
1076         g_free (fname);
1077 #endif
1078         return ad;
1079 }
1080
1081 static gboolean
1082 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1083 {
1084         HANDLE_FUNCTION_ENTER ();
1085         error_init (error);
1086         MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1087         if (!is_ok (error))
1088                 goto leave;
1089         MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1090 leave:
1091         HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1092 }
1093
1094 MonoArrayHandle
1095 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1096 {
1097         error_init (error);
1098         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1099         MonoAssembly* ass;
1100         GSList *tmp;
1101         int i;
1102         GPtrArray *assemblies;
1103
1104         /* 
1105          * Make a copy of the list of assemblies because we can't hold the assemblies
1106          * lock while creating objects etc.
1107          */
1108         assemblies = g_ptr_array_new ();
1109         /* Need to skip internal assembly builders created by remoting */
1110         mono_domain_assemblies_lock (domain);
1111         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1112                 ass = (MonoAssembly *)tmp->data;
1113                 if (refonly != ass->ref_only)
1114                         continue;
1115                 if (ass->corlib_internal)
1116                         continue;
1117                 g_ptr_array_add (assemblies, ass);
1118         }
1119         mono_domain_assemblies_unlock (domain);
1120
1121         MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1122         if (!is_ok (error))
1123                 goto leave;
1124         for (i = 0; i < assemblies->len; ++i) {
1125                 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1126                         goto leave;
1127         }
1128
1129 leave:
1130         g_ptr_array_free (assemblies, TRUE);
1131         return res;
1132 }
1133
1134 MonoAssembly*
1135 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1136 {
1137         HANDLE_FUNCTION_ENTER ();
1138         error_init (error);
1139         MonoAssembly *result = NULL;
1140         MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1141         if (!is_ok (error))
1142                 goto leave;
1143         result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1144 leave:
1145         HANDLE_FUNCTION_RETURN_VAL (result);
1146 }
1147
1148 MonoAssembly*
1149 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1150 {
1151         HANDLE_FUNCTION_ENTER ();
1152         MonoAssembly *ret = NULL;
1153         MonoMethod *method;
1154         MonoBoolean isrefonly;
1155         gpointer params [3];
1156
1157         error_init (error);
1158
1159         if (mono_runtime_get_no_exec ())
1160                 goto leave;
1161
1162         g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1163
1164         method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1165         g_assert (method != NULL);
1166
1167         isrefonly = refonly ? 1 : 0;
1168         MonoReflectionAssemblyHandle requesting_handle;
1169         if (requesting) {
1170                 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1171                 if (!is_ok (error))
1172                         goto leave;
1173         }
1174         params [0] = MONO_HANDLE_RAW (fname);
1175         params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1176         params [2] = &isrefonly;
1177         MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1178         ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1179
1180         if (ret && !refonly && ret->ref_only) {
1181                 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1182                 mono_error_set_file_not_found (error, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1183                 ret = NULL;
1184                 goto leave;
1185         }
1186 leave:
1187         HANDLE_FUNCTION_RETURN_VAL (ret);
1188 }
1189
1190 MonoAssembly *
1191 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1192                                                                           gboolean refonly)
1193 {
1194         MonoError error;
1195         MonoAssembly *assembly;
1196         MonoDomain *domain = mono_domain_get ();
1197         char *aname_str;
1198
1199         aname_str = mono_stringify_assembly_name (aname);
1200
1201         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1202
1203         assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1204         g_free (aname_str);
1205         mono_error_cleanup (&error);
1206
1207         return assembly;
1208 }
1209         
1210 /*
1211  * LOCKING: assumes assemblies_lock in the domain is already locked.
1212  */
1213 static void
1214 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1215 {
1216         gint i;
1217         GSList *tmp;
1218         gboolean destroy_ht = FALSE;
1219
1220         if (!ass->aname.name)
1221                 return;
1222
1223         if (!ht) {
1224                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1225                 destroy_ht = TRUE;
1226                 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1227                         g_hash_table_insert (ht, tmp->data, tmp->data);
1228                 }
1229         }
1230
1231         /* FIXME: handle lazy loaded assemblies */
1232
1233         if (!g_hash_table_lookup (ht, ass)) {
1234                 mono_assembly_addref (ass);
1235                 g_hash_table_insert (ht, ass, ass);
1236                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1237                 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);
1238         }
1239
1240         if (ass->image->references) {
1241                 for (i = 0; i < ass->image->nreferences; i++) {
1242                         if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1243                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1244                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1245                                 }
1246                         }
1247                 }
1248         }
1249         if (destroy_ht)
1250                 g_hash_table_destroy (ht);
1251 }
1252
1253 static void
1254 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1255 {
1256         HANDLE_FUNCTION_ENTER ();
1257         static MonoClassField *assembly_load_field;
1258         static MonoMethod *assembly_load_method;
1259         MonoError error;
1260         MonoDomain *domain = mono_domain_get ();
1261         MonoClass *klass;
1262         gpointer load_value;
1263         void *params [1];
1264
1265         if (!domain->domain)
1266                 /* This can happen during startup */
1267                 goto leave;
1268 #ifdef ASSEMBLY_LOAD_DEBUG
1269         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1270 #endif
1271         klass = domain->domain->mbr.obj.vtable->klass;
1272
1273         mono_domain_assemblies_lock (domain);
1274         add_assemblies_to_domain (domain, assembly, NULL);
1275         mono_domain_assemblies_unlock (domain);
1276
1277         if (assembly_load_field == NULL) {
1278                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1279                 g_assert (assembly_load_field);
1280         }
1281
1282         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1283         if (load_value == NULL) {
1284                 /* No events waiting to be triggered */
1285                 goto leave;
1286         }
1287
1288         MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1289         mono_error_assert_ok (&error);
1290
1291         if (assembly_load_method == NULL) {
1292                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1293                 g_assert (assembly_load_method);
1294         }
1295
1296         *params = MONO_HANDLE_RAW(ref_assembly);
1297
1298         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1299         mono_error_cleanup (&error);
1300 leave:
1301         HANDLE_FUNCTION_RETURN ();
1302 }
1303
1304 /*
1305  * LOCKING: Acquires the domain assemblies lock.
1306  */
1307 static void
1308 set_domain_search_path (MonoDomain *domain)
1309 {
1310         MonoError error;
1311         MonoAppDomainSetup *setup;
1312         gchar **tmp;
1313         gchar *search_path = NULL;
1314         gint i;
1315         gint npaths = 0;
1316         gchar **pvt_split = NULL;
1317         GError *gerror = NULL;
1318         gint appbaselen = -1;
1319
1320         /* 
1321          * We use the low-level domain assemblies lock, since this is called from
1322          * assembly loads hooks, which means this thread might hold the loader lock.
1323          */
1324         mono_domain_assemblies_lock (domain);
1325
1326         if (!domain->setup) {
1327                 mono_domain_assemblies_unlock (domain);
1328                 return;
1329         }
1330
1331         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1332                 mono_domain_assemblies_unlock (domain);
1333                 return;
1334         }
1335         setup = domain->setup;
1336         if (!setup->application_base) {
1337                 mono_domain_assemblies_unlock (domain);
1338                 return; /* Must set application base to get private path working */
1339         }
1340
1341         npaths++;
1342         
1343         if (setup->private_bin_path) {
1344                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1345                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1346                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1347                         mono_error_cleanup (&error);
1348                         mono_domain_assemblies_unlock (domain);
1349                         return;
1350                 }
1351         }
1352         
1353         if (domain->private_bin_path) {
1354                 if (search_path == NULL)
1355                         search_path = domain->private_bin_path;
1356                 else {
1357                         gchar *tmp2 = search_path;
1358                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1359                         g_free (tmp2);
1360                 }
1361         }
1362         
1363         if (search_path) {
1364                 /*
1365                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1366                  * directories relative to ApplicationBase separated by semicolons (see
1367                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1368                  * The loop below copes with the fact that some Unix applications may use ':' (or
1369                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1370                  * ';' for the subsequent split.
1371                  *
1372                  * The issue was reported in bug #81446
1373                  */
1374
1375 #ifndef TARGET_WIN32
1376                 gint slen;
1377
1378                 slen = strlen (search_path);
1379                 for (i = 0; i < slen; i++)
1380                         if (search_path [i] == ':')
1381                                 search_path [i] = ';';
1382 #endif
1383                 
1384                 pvt_split = g_strsplit (search_path, ";", 1000);
1385                 g_free (search_path);
1386                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1387         }
1388
1389         if (!npaths) {
1390                 if (pvt_split)
1391                         g_strfreev (pvt_split);
1392                 /*
1393                  * Don't do this because the first time is called, the domain
1394                  * setup is not finished.
1395                  *
1396                  * domain->search_path = g_malloc (sizeof (char *));
1397                  * domain->search_path [0] = NULL;
1398                 */
1399                 mono_domain_assemblies_unlock (domain);
1400                 return;
1401         }
1402
1403         if (domain->search_path)
1404                 g_strfreev (domain->search_path);
1405
1406         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1407         tmp [npaths] = NULL;
1408
1409         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1410         if (!mono_error_ok (&error)) {
1411                 mono_error_cleanup (&error);
1412                 g_strfreev (pvt_split);
1413                 g_free (tmp);
1414
1415                 mono_domain_assemblies_unlock (domain);
1416                 return;
1417         }
1418
1419         domain->search_path = tmp;
1420
1421         /* FIXME: is this needed? */
1422         if (strncmp (*tmp, "file://", 7) == 0) {
1423                 gchar *file = *tmp;
1424                 gchar *uri = *tmp;
1425                 gchar *tmpuri;
1426
1427                 if (uri [7] != '/')
1428                         uri = g_strdup_printf ("file:///%s", uri + 7);
1429
1430                 tmpuri = uri;
1431                 uri = mono_escape_uri_string (tmpuri);
1432                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1433                 g_free (uri);
1434
1435                 if (tmpuri != file)
1436                         g_free (tmpuri);
1437
1438                 if (gerror != NULL) {
1439                         g_warning ("%s\n", gerror->message);
1440                         g_error_free (gerror);
1441                         *tmp = file;
1442                 } else {
1443                         g_free (file);
1444                 }
1445         }
1446
1447         for (i = 1; pvt_split && i < npaths; i++) {
1448                 if (g_path_is_absolute (pvt_split [i - 1])) {
1449                         tmp [i] = g_strdup (pvt_split [i - 1]);
1450                 } else {
1451                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1452                 }
1453
1454                 if (strchr (tmp [i], '.')) {
1455                         gchar *reduced;
1456                         gchar *freeme;
1457
1458                         reduced = mono_path_canonicalize (tmp [i]);
1459                         if (appbaselen == -1)
1460                                 appbaselen = strlen (tmp [0]);
1461
1462                         if (strncmp (tmp [0], reduced, appbaselen)) {
1463                                 g_free (reduced);
1464                                 g_free (tmp [i]);
1465                                 tmp [i] = g_strdup ("");
1466                                 continue;
1467                         }
1468
1469                         freeme = tmp [i];
1470                         tmp [i] = reduced;
1471                         g_free (freeme);
1472                 }
1473         }
1474         
1475         if (setup->private_bin_path_probe != NULL) {
1476                 g_free (tmp [0]);
1477                 tmp [0] = g_strdup ("");
1478         }
1479                 
1480         domain->setup->path_changed = FALSE;
1481
1482         g_strfreev (pvt_split);
1483
1484         mono_domain_assemblies_unlock (domain);
1485 }
1486
1487 #ifdef DISABLE_SHADOW_COPY
1488 gboolean
1489 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1490 {
1491         return FALSE;
1492 }
1493
1494 char *
1495 mono_make_shadow_copy (const char *filename, MonoError *error)
1496 {
1497         error_init (error);
1498         return (char *) filename;
1499 }
1500 #else
1501 static gboolean
1502 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1503 {
1504         guint16 *orig, *dest;
1505         gboolean copy_result;
1506         gint32 copy_error;
1507         
1508         strcpy (src + srclen - tail_len, extension);
1509
1510         if (IS_PORTABILITY_CASE) {
1511                 gchar *file = mono_portability_find_file (src, TRUE);
1512
1513                 if (file == NULL)
1514                         return TRUE;
1515
1516                 g_free (file);
1517         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1518                 return TRUE;
1519         }
1520
1521         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1522
1523         strcpy (target + targetlen - tail_len, extension);
1524         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1525         
1526         mono_w32file_delete (dest);
1527
1528         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1529
1530         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1531          * overwritten when updated in their original locations. */
1532         if (copy_result)
1533                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1534
1535         g_free (orig);
1536         g_free (dest);
1537         
1538         return copy_result;
1539 }
1540
1541 static gint32 
1542 get_cstring_hash (const char *str)
1543 {
1544         int len, i;
1545         const char *p;
1546         gint32 h = 0;
1547         
1548         if (!str || !str [0])
1549                 return 0;
1550                 
1551         len = strlen (str);
1552         p = str;
1553         for (i = 0; i < len; i++) {
1554                 h = (h << 5) - h + *p;
1555                 p++;
1556         }
1557         
1558         return h;
1559 }
1560
1561 /*
1562  * Returned memory is malloc'd. Called must free it 
1563  */
1564 static char *
1565 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1566 {
1567         MonoAppDomainSetup *setup;
1568         char *cache_path, *appname;
1569         char *userdir;
1570         char *location;
1571
1572         error_init (error);
1573         
1574         setup = domain->setup;
1575         if (setup->cache_path != NULL && setup->application_name != NULL) {
1576                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1577                 return_val_if_nok (error, NULL);
1578
1579 #ifndef TARGET_WIN32
1580                 {
1581                         gint i;
1582                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1583                                 if (cache_path [i] == '\\')
1584                                         cache_path [i] = '/';
1585                 }
1586 #endif
1587
1588                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1589                 if (!mono_error_ok (error)) {
1590                         g_free (cache_path);
1591                         return NULL;
1592                 }
1593
1594                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1595                 g_free (appname);
1596                 g_free (cache_path);
1597         } else {
1598                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1599                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1600                 g_free (userdir);
1601         }
1602         return location;
1603 }
1604
1605 static char *
1606 get_shadow_assembly_location (const char *filename, MonoError *error)
1607 {
1608         gint32 hash = 0, hash2 = 0;
1609         char name_hash [9];
1610         char path_hash [30];
1611         char *bname = g_path_get_basename (filename);
1612         char *dirname = g_path_get_dirname (filename);
1613         char *location, *tmploc;
1614         MonoDomain *domain = mono_domain_get ();
1615
1616         error_init (error);
1617         
1618         hash = get_cstring_hash (bname);
1619         hash2 = get_cstring_hash (dirname);
1620         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1621         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1622         tmploc = get_shadow_assembly_location_base (domain, error);
1623         if (!mono_error_ok (error)) {
1624                 g_free (bname);
1625                 g_free (dirname);
1626                 return NULL;
1627         }
1628
1629         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1630         g_free (tmploc);
1631         g_free (bname);
1632         g_free (dirname);
1633         return location;
1634 }
1635
1636 static gboolean
1637 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1638 {
1639         struct stat sbuf_dest;
1640         gchar *stat_src;
1641         gchar *real_src = mono_portability_find_file (src, TRUE);
1642
1643         if (!real_src)
1644                 stat_src = (gchar*)src;
1645         else
1646                 stat_src = real_src;
1647
1648         if (stat (stat_src, sbuf_src) == -1) {
1649                 time_t tnow = time (NULL);
1650
1651                 if (real_src)
1652                         g_free (real_src);
1653
1654                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1655                 sbuf_src->st_mtime = tnow;
1656                 sbuf_src->st_atime = tnow;
1657                 return TRUE;
1658         }
1659
1660         if (real_src)
1661                 g_free (real_src);
1662
1663         if (stat (dest, &sbuf_dest) == -1)
1664                 return TRUE;
1665         
1666         if (sbuf_src->st_size == sbuf_dest.st_size &&
1667             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1668                 return FALSE;
1669
1670         return TRUE;
1671 }
1672
1673 static gboolean
1674 shadow_copy_create_ini (const char *shadow, const char *filename)
1675 {
1676         char *dir_name;
1677         char *ini_file;
1678         guint16 *u16_ini;
1679         gboolean result;
1680         guint32 n;
1681         HANDLE *handle;
1682         gchar *full_path;
1683
1684         dir_name = g_path_get_dirname (shadow);
1685         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1686         g_free (dir_name);
1687         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1688                 g_free (ini_file);
1689                 return TRUE;
1690         }
1691
1692         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1693         g_free (ini_file);
1694         if (!u16_ini) {
1695                 return FALSE;
1696         }
1697         handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1698         g_free (u16_ini);
1699         if (handle == INVALID_HANDLE_VALUE) {
1700                 return FALSE;
1701         }
1702
1703         full_path = mono_path_resolve_symlinks (filename);
1704         result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1705         g_free (full_path);
1706         mono_w32file_close (handle);
1707         return result;
1708 }
1709
1710 gboolean
1711 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1712 {
1713         MonoError error;
1714         MonoAppDomainSetup *setup;
1715         gchar *all_dirs;
1716         gchar **dir_ptr;
1717         gchar **directories;
1718         gchar *shadow_status_string;
1719         gchar *base_dir;
1720         gboolean shadow_enabled;
1721         gboolean found = FALSE;
1722
1723         if (domain == NULL)
1724                 return FALSE;
1725
1726         setup = domain->setup;
1727         if (setup == NULL || setup->shadow_copy_files == NULL)
1728                 return FALSE;
1729
1730         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1731         if (!mono_error_ok (&error)) {
1732                 mono_error_cleanup (&error);
1733                 return FALSE;
1734         }
1735         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1736         g_free (shadow_status_string);
1737
1738         if (!shadow_enabled)
1739                 return FALSE;
1740
1741         if (setup->shadow_copy_directories == NULL)
1742                 return TRUE;
1743
1744         /* Is dir_name a shadow_copy destination already? */
1745         base_dir = get_shadow_assembly_location_base (domain, &error);
1746         if (!mono_error_ok (&error)) {
1747                 mono_error_cleanup (&error);
1748                 return FALSE;
1749         }
1750
1751         if (strstr (dir_name, base_dir)) {
1752                 g_free (base_dir);
1753                 return TRUE;
1754         }
1755         g_free (base_dir);
1756
1757         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1758         if (!mono_error_ok (&error)) {
1759                 mono_error_cleanup (&error);
1760                 return FALSE;
1761         }
1762
1763         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1764         dir_ptr = directories;
1765         while (*dir_ptr) {
1766                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1767                         found = TRUE;
1768                         break;
1769                 }
1770                 dir_ptr++;
1771         }
1772         g_strfreev (directories);
1773         g_free (all_dirs);
1774         return found;
1775 }
1776
1777 /*
1778 This function raises exceptions so it can cause as sorts of nasty stuff if called
1779 while holding a lock.
1780 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1781 or NULL if source file not found.
1782 FIXME bubble up the error instead of raising it here
1783 */
1784 char *
1785 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1786 {
1787         MonoError error;
1788         gchar *sibling_source, *sibling_target;
1789         gint sibling_source_len, sibling_target_len;
1790         guint16 *orig, *dest;
1791         guint32 attrs;
1792         char *shadow;
1793         gboolean copy_result;
1794         struct stat src_sbuf;
1795         struct utimbuf utbuf;
1796         char *dir_name = g_path_get_dirname (filename);
1797         MonoDomain *domain = mono_domain_get ();
1798         char *shadow_dir;
1799         gint32 copy_error;
1800
1801         error_init (oerror);
1802
1803         set_domain_search_path (domain);
1804
1805         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1806                 g_free (dir_name);
1807                 return (char *) filename;
1808         }
1809
1810         /* Is dir_name a shadow_copy destination already? */
1811         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1812         if (!mono_error_ok (&error)) {
1813                 mono_error_cleanup (&error);
1814                 g_free (dir_name);
1815                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1816                 return NULL;
1817         }
1818
1819         if (strstr (dir_name, shadow_dir)) {
1820                 g_free (shadow_dir);
1821                 g_free (dir_name);
1822                 return (char *) filename;
1823         }
1824         g_free (shadow_dir);
1825         g_free (dir_name);
1826
1827         shadow = get_shadow_assembly_location (filename, &error);
1828         if (!mono_error_ok (&error)) {
1829                 mono_error_cleanup (&error);
1830                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1831                 return NULL;
1832         }
1833
1834         if (g_ensure_directory_exists (shadow) == FALSE) {
1835                 g_free (shadow);
1836                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1837                 return NULL;
1838         }       
1839
1840         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1841                 return (char*) shadow;
1842
1843         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1844         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1845         mono_w32file_delete (dest);
1846
1847         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1848          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1849          * and not have it runtime error" */
1850         attrs = mono_w32file_get_attributes (orig);
1851         if (attrs == INVALID_FILE_ATTRIBUTES) {
1852                 g_free (shadow);
1853                 return (char *)filename;
1854         }
1855
1856         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1857
1858         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1859          * overwritten when updated in their original locations. */
1860         if (copy_result)
1861                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1862
1863         g_free (dest);
1864         g_free (orig);
1865
1866         if (copy_result == FALSE) {
1867                 g_free (shadow);
1868
1869                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1870                 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1871                         return NULL; /* file not found, shadow copy failed */
1872
1873                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1874                 return NULL;
1875         }
1876
1877         /* attempt to copy .mdb, .config if they exist */
1878         sibling_source = g_strconcat (filename, ".config", NULL);
1879         sibling_source_len = strlen (sibling_source);
1880         sibling_target = g_strconcat (shadow, ".config", NULL);
1881         sibling_target_len = strlen (sibling_target);
1882
1883         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1884         if (copy_result)
1885                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".pdb", sibling_target, sibling_target_len, 11);
1886         if (copy_result)
1887                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1888         
1889         g_free (sibling_source);
1890         g_free (sibling_target);
1891         
1892         if (!copy_result)  {
1893                 g_free (shadow);
1894                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1895                 return NULL;
1896         }
1897
1898         /* Create a .ini file containing the original assembly location */
1899         if (!shadow_copy_create_ini (shadow, filename)) {
1900                 g_free (shadow);
1901                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1902                 return NULL;
1903         }
1904
1905         utbuf.actime = src_sbuf.st_atime;
1906         utbuf.modtime = src_sbuf.st_mtime;
1907         utime (shadow, &utbuf);
1908         
1909         return shadow;
1910 }
1911 #endif /* DISABLE_SHADOW_COPY */
1912
1913 /**
1914  * mono_domain_from_appdomain:
1915  */
1916 MonoDomain *
1917 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1918 {
1919         HANDLE_FUNCTION_ENTER ();
1920         MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1921         MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1922         HANDLE_FUNCTION_RETURN_VAL (result);
1923 }
1924
1925 MonoDomain *
1926 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1927 {
1928         HANDLE_FUNCTION_ENTER ();
1929         MonoDomain *dom = NULL;
1930         if (MONO_HANDLE_IS_NULL (appdomain))
1931                 goto leave;
1932
1933         if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1934                 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1935                 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1936                 
1937                 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1938         } else
1939                 dom = MONO_HANDLE_GETVAL (appdomain, data);
1940
1941 leave:
1942         HANDLE_FUNCTION_RETURN_VAL (dom);
1943 }
1944
1945
1946 static gboolean
1947 try_load_from (MonoAssembly **assembly,
1948                const gchar *path1, const gchar *path2,
1949                const gchar *path3, const gchar *path4,
1950                gboolean refonly, gboolean is_private,
1951                MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1952 {
1953         gchar *fullpath;
1954         gboolean found = FALSE;
1955         
1956         *assembly = NULL;
1957         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1958
1959         if (IS_PORTABILITY_SET) {
1960                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1961                 if (new_fullpath) {
1962                         g_free (fullpath);
1963                         fullpath = new_fullpath;
1964                         found = TRUE;
1965                 }
1966         } else
1967                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1968         
1969         if (found)
1970                 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1971
1972         g_free (fullpath);
1973         return (*assembly != NULL);
1974 }
1975
1976 static MonoAssembly *
1977 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1978 {
1979         MonoAssembly *result = NULL;
1980         gchar **path;
1981         gchar *filename;
1982         const gchar *local_culture;
1983         gint len;
1984         gboolean is_private = FALSE;
1985
1986         if (!culture || *culture == '\0') {
1987                 local_culture = "";
1988         } else {
1989                 local_culture = culture;
1990         }
1991
1992         filename =  g_strconcat (name, ".dll", NULL);
1993         len = strlen (filename);
1994
1995         for (path = search_path; *path; path++) {
1996                 if (**path == '\0') {
1997                         is_private = TRUE;
1998                         continue; /* Ignore empty ApplicationBase */
1999                 }
2000
2001                 /* See test cases in bug #58992 and bug #57710 */
2002                 /* 1st try: [culture]/[name].dll (culture may be empty) */
2003                 strcpy (filename + len - 4, ".dll");
2004                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2005                         break;
2006
2007                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2008                 strcpy (filename + len - 4, ".exe");
2009                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2010                         break;
2011
2012                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2013                 strcpy (filename + len - 4, ".dll");
2014                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2015                         break;
2016
2017                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2018                 strcpy (filename + len - 4, ".exe");
2019                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2020                         break;
2021         }
2022
2023         g_free (filename);
2024         return result;
2025 }
2026
2027 /*
2028  * Try loading the assembly from ApplicationBase and PrivateBinPath 
2029  * and then from assemblies_path if any.
2030  * LOCKING: This is called from the assembly loading code, which means the caller
2031  * might hold the loader lock. Thus, this function must not acquire the domain lock.
2032  */
2033 static MonoAssembly *
2034 mono_domain_assembly_preload (MonoAssemblyName *aname,
2035                               gchar **assemblies_path,
2036                               gpointer user_data)
2037 {
2038         MonoDomain *domain = mono_domain_get ();
2039         MonoAssembly *result = NULL;
2040         gboolean refonly = GPOINTER_TO_UINT (user_data);
2041
2042         set_domain_search_path (domain);
2043
2044         MonoAssemblyCandidatePredicate predicate = NULL;
2045         void* predicate_ud = NULL;
2046 #if !defined(DISABLE_DESKTOP_LOADER)
2047         if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2048                 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2049                 predicate_ud = aname;
2050         }
2051 #endif
2052         if (domain->search_path && domain->search_path [0] != NULL) {
2053                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2054                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2055                         for (int i = 0; domain->search_path [i]; i++) {
2056                                 const char *p = domain->search_path[i];
2057                                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2058                         }
2059                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);                    
2060                 }
2061                 result = real_load (domain->search_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2062         }
2063
2064         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2065                 result = real_load (assemblies_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2066         }
2067
2068         return result;
2069 }
2070
2071 /*
2072  * Check whenever a given assembly was already loaded in the current appdomain.
2073  */
2074 static MonoAssembly *
2075 mono_domain_assembly_search (MonoAssemblyName *aname,
2076                                                          gpointer user_data)
2077 {
2078         MonoDomain *domain = mono_domain_get ();
2079         GSList *tmp;
2080         MonoAssembly *ass;
2081         gboolean refonly = GPOINTER_TO_UINT (user_data);
2082
2083         mono_domain_assemblies_lock (domain);
2084         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2085                 ass = (MonoAssembly *)tmp->data;
2086                 /* Dynamic assemblies can't match here in MS.NET */
2087                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2088                         continue;
2089
2090                 mono_domain_assemblies_unlock (domain);
2091                 return ass;
2092         }
2093         mono_domain_assemblies_unlock (domain);
2094
2095         return NULL;
2096 }
2097
2098 MonoReflectionAssemblyHandle
2099 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2100 {
2101         error_init (error);
2102         MonoDomain *domain = mono_domain_get ();
2103         char *name, *filename;
2104         MonoImageOpenStatus status = MONO_IMAGE_OK;
2105         MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2106
2107         name = NULL;
2108         result = NULL;
2109
2110         if (fname == NULL) {
2111                 mono_error_set_argument_null (error, "assemblyFile", "");
2112                 goto leave;
2113         }
2114                 
2115         name = filename = mono_string_handle_to_utf8 (fname, error);
2116         if (!is_ok (error))
2117                 goto leave;
2118         
2119         MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2120         
2121         if (!ass) {
2122                 if (status == MONO_IMAGE_IMAGE_INVALID)
2123                         mono_error_set_bad_image_name (error, g_strdup (name), "");
2124                 else
2125                         mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2126                 goto leave;
2127         }
2128
2129         result = mono_assembly_get_object_handle (domain, ass, error);
2130
2131 leave:
2132         g_free (name);
2133         return result;
2134 }
2135
2136 MonoReflectionAssemblyHandle
2137 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, 
2138                                             MonoArrayHandle raw_assembly,
2139                                             MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2140                                             MonoBoolean refonly,
2141                                             MonoError *error)
2142 {
2143         error_init (error);
2144         MonoAssembly *ass;
2145         MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2146         MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2147         MonoImageOpenStatus status;
2148         guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2149
2150         /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2151         char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2152         if (!assembly_data) {
2153                 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2154                 return refass;
2155         }
2156         uint32_t gchandle;
2157         mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2158         memcpy (assembly_data, raw_data, raw_assembly_len);
2159         mono_gchandle_free (gchandle); /* unpin */
2160         MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2161         
2162         MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2163
2164         if (!image) {
2165                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2166                 return refass;
2167         }
2168
2169         if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2170                 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2171                 uint32_t symbol_gchandle;
2172                 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2173                 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2174                 mono_gchandle_free (symbol_gchandle);
2175         }
2176
2177         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2178
2179
2180         if (!ass) {
2181                 mono_image_close (image);
2182                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2183                 return refass; 
2184         }
2185
2186         refass = mono_assembly_get_object_handle (domain, ass, error);
2187         if (!MONO_HANDLE_IS_NULL(refass))
2188                 MONO_HANDLE_SET (refass, evidence, evidence);
2189         return refass;
2190 }
2191
2192 MonoReflectionAssemblyHandle
2193 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2194 {
2195         error_init (error);
2196         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2197         MonoImageOpenStatus status = MONO_IMAGE_OK;
2198         MonoAssembly *ass;
2199         MonoAssemblyName aname;
2200         gchar *name = NULL;
2201         gboolean parsed;
2202
2203         g_assert (assRef);
2204
2205         name = mono_string_handle_to_utf8 (assRef, error);
2206         if (!is_ok (error))
2207                 goto fail;
2208         parsed = mono_assembly_name_parse (name, &aname);
2209         g_free (name);
2210
2211         if (!parsed) {
2212                 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2213                 /* This is a parse error... */
2214                 if (!refOnly) {
2215                         MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2216                         if (!is_ok (error))
2217                                 goto fail;
2218                         if (assm) {
2219                                 refass = mono_assembly_get_object_handle (domain, assm, error);
2220                                 if (!is_ok (error))
2221                                         goto fail;
2222                         }
2223                 }
2224                 return refass;
2225         }
2226
2227         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2228         mono_assembly_name_free (&aname);
2229
2230         if (!ass) {
2231                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2232                 if (!refOnly) {
2233                         ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2234                         if (!is_ok (error))
2235                                 goto fail;
2236                 }
2237                 if (!ass)
2238                         goto fail;
2239         }
2240
2241         g_assert (ass);
2242         MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2243         if (!is_ok (error))
2244                 goto fail;
2245
2246         MONO_HANDLE_SET (refass, evidence, evidence);
2247
2248         return refass;
2249 fail:
2250         return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2251 }
2252
2253 void
2254 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2255 {
2256         error_init (error);
2257         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2258
2259         if (NULL == domain) {
2260                 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2261                 return;
2262         }
2263         
2264         if (domain == mono_get_root_domain ()) {
2265                 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2266                 return;
2267         }
2268
2269         /* 
2270          * Unloading seems to cause problems when running NUnit/NAnt, hence
2271          * this workaround.
2272          */
2273         if (g_hasenv ("MONO_NO_UNLOAD"))
2274                 return;
2275
2276         MonoException *exc = NULL;
2277         mono_domain_try_unload (domain, (MonoObject**)&exc);
2278         if (exc)
2279                 mono_error_set_exception_instance (error, exc);
2280 }
2281
2282 gboolean
2283 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2284 {
2285         error_init (error);
2286         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2287
2288         if (!domain)
2289                 return TRUE;
2290
2291         return mono_domain_is_unloading (domain);
2292 }
2293
2294 void
2295 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2296 {
2297         error_init (error);
2298         mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2299         mono_error_assert_ok (error);
2300 }
2301
2302 gint32
2303 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2304                                             MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2305                                             MonoError *error)
2306 {
2307         error_init (error);
2308         MonoImage *image;
2309         MonoMethod *method;
2310
2311         g_assert (!MONO_HANDLE_IS_NULL (refass));
2312         MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2313         image = assembly->image;
2314         g_assert (image);
2315
2316         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2317
2318         if (!method)
2319                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2320
2321         if (MONO_HANDLE_IS_NULL (args)) {
2322                 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2323                 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2324                 mono_error_assert_ok (error);
2325         }
2326
2327         int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2328         return res;
2329 }
2330
2331 gint32 
2332 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2333 {
2334         return ad->data->domain_id;
2335 }
2336
2337 MonoAppDomainHandle
2338 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2339 {
2340         error_init (error);
2341         MonoDomain *old_domain = mono_domain_get ();
2342
2343         if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2344                 mono_error_set_appdomain_unloaded (error);
2345                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2346         }
2347
2348         return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2349 }
2350
2351 MonoAppDomainHandle
2352 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2353 {
2354         MonoDomain *current_domain = mono_domain_get ();
2355         MonoDomain *domain = mono_domain_get_by_id (domainid);
2356
2357         if (!domain || !mono_domain_set (domain, FALSE)) {
2358                 mono_error_set_appdomain_unloaded (error);
2359                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2360         }
2361
2362         return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2363 }
2364
2365 void
2366 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2367 {
2368         error_init (error);
2369         mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2370 }
2371
2372 void
2373 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2374 {
2375         error_init (error);
2376         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2377
2378         if (!domain) {
2379                 /* 
2380                  * Raise an exception to prevent the managed code from executing a pop
2381                  * later.
2382                  */
2383                 mono_error_set_appdomain_unloaded (error);
2384                 return;
2385         }
2386
2387         mono_thread_push_appdomain_ref (domain);
2388 }
2389
2390 void
2391 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2392 {
2393         error_init (error);
2394         mono_thread_pop_appdomain_ref ();
2395 }
2396
2397 MonoAppContextHandle
2398 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2399 {
2400         error_init (error);
2401         return mono_context_get_handle ();
2402 }
2403
2404 MonoAppContextHandle
2405 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2406 {
2407         error_init (error);
2408         return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2409 }
2410
2411 MonoAppContextHandle
2412 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2413 {
2414         error_init (error);
2415         MonoAppContextHandle old_context = mono_context_get_handle ();
2416
2417         mono_context_set_handle (mc);
2418
2419         return old_context;
2420 }
2421
2422 MonoStringHandle
2423 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2424 {
2425         error_init (error);
2426         MonoDomain* mono_root_domain = mono_get_root_domain ();
2427         mono_domain_lock (mono_root_domain);
2428         if (process_guid_set) {
2429                 mono_domain_unlock (mono_root_domain);
2430                 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2431         }
2432         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2433         memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2434         mono_gchandle_free (gchandle);
2435         process_guid_set = TRUE;
2436         mono_domain_unlock (mono_root_domain);
2437         return newguid;
2438 }
2439
2440 /**
2441  * mono_domain_is_unloading:
2442  */
2443 gboolean
2444 mono_domain_is_unloading (MonoDomain *domain)
2445 {
2446         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2447                 return TRUE;
2448         else
2449                 return FALSE;
2450 }
2451
2452 static void
2453 clear_cached_vtable (MonoVTable *vtable)
2454 {
2455         MonoClass *klass = vtable->klass;
2456         MonoDomain *domain = vtable->domain;
2457         MonoClassRuntimeInfo *runtime_info;
2458         void *data;
2459
2460         runtime_info = klass->runtime_info;
2461         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2462                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2463         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2464                 mono_gc_free_fixed (data);
2465 }
2466
2467 static G_GNUC_UNUSED void
2468 zero_static_data (MonoVTable *vtable)
2469 {
2470         MonoClass *klass = vtable->klass;
2471         void *data;
2472
2473         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2474                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2475 }
2476
2477 typedef struct unload_data {
2478         gboolean done;
2479         MonoDomain *domain;
2480         char *failure_reason;
2481         gint32 refcount;
2482 } unload_data;
2483
2484 static void
2485 unload_data_unref (unload_data *data)
2486 {
2487         gint32 count;
2488         do {
2489                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2490                 g_assert (count >= 1 && count <= 2);
2491                 if (count == 1) {
2492                         g_free (data);
2493                         return;
2494                 }
2495         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2496 }
2497
2498 static void
2499 deregister_reflection_info_roots_from_list (MonoImage *image)
2500 {
2501         GSList *list = image->reflection_info_unregister_classes;
2502
2503         while (list) {
2504                 MonoClass *klass = (MonoClass *)list->data;
2505
2506                 mono_class_free_ref_info (klass);
2507
2508                 list = list->next;
2509         }
2510
2511         image->reflection_info_unregister_classes = NULL;
2512 }
2513
2514 static void
2515 deregister_reflection_info_roots (MonoDomain *domain)
2516 {
2517         GSList *list;
2518
2519         mono_domain_assemblies_lock (domain);
2520         for (list = domain->domain_assemblies; list; list = list->next) {
2521                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2522                 MonoImage *image = assembly->image;
2523                 int i;
2524
2525                 /*
2526                  * No need to take the image lock here since dynamic images are appdomain bound and
2527                  * at this point the mutator is gone.  Taking the image lock here would mean
2528                  * promoting it from a simple lock to a complex lock, which we better avoid if
2529                  * possible.
2530                  */
2531                 if (image_is_dynamic (image))
2532                         deregister_reflection_info_roots_from_list (image);
2533
2534                 for (i = 0; i < image->module_count; ++i) {
2535                         MonoImage *module = image->modules [i];
2536                         if (module && image_is_dynamic (module))
2537                                 deregister_reflection_info_roots_from_list (module);
2538                 }
2539         }
2540         mono_domain_assemblies_unlock (domain);
2541 }
2542
2543 static gsize WINAPI
2544 unload_thread_main (void *arg)
2545 {
2546         MonoError error;
2547         unload_data *data = (unload_data*)arg;
2548         MonoDomain *domain = data->domain;
2549         MonoInternalThread *internal;
2550         int i;
2551
2552         internal = mono_thread_internal_current ();
2553
2554         MonoString *thread_name_str = mono_string_new_checked (mono_domain_get (), "Domain unloader", &error);
2555         if (is_ok (&error))
2556                 mono_thread_set_name_internal (internal, thread_name_str, TRUE, FALSE, &error);
2557         if (!is_ok (&error)) {
2558                 data->failure_reason = g_strdup (mono_error_get_message (&error));
2559                 mono_error_cleanup (&error);
2560                 goto failure;
2561         }
2562
2563         /* 
2564          * FIXME: Abort our parent thread last, so we can return a failure 
2565          * indication if aborting times out.
2566          */
2567         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2568                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2569                 goto failure;
2570         }
2571
2572         if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2573                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2574                 goto failure;
2575         }
2576
2577         /* Finalize all finalizable objects in the doomed appdomain */
2578         if (!mono_domain_finalize (domain, -1)) {
2579                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2580                 goto failure;
2581         }
2582
2583         /* Clear references to our vtables in class->runtime_info.
2584          * We also hold the loader lock because we're going to change
2585          * class->runtime_info.
2586          */
2587
2588         mono_loader_lock (); //FIXME why do we need the loader lock here?
2589         mono_domain_lock (domain);
2590 #ifdef HAVE_SGEN_GC
2591         /*
2592          * We need to make sure that we don't have any remsets
2593          * pointing into static data of the to-be-freed domain because
2594          * at the next collections they would be invalid.  So what we
2595          * do is we first zero all static data and then do a minor
2596          * collection.  Because all references in the static data will
2597          * now be null we won't do any unnecessary copies and after
2598          * the collection there won't be any more remsets.
2599          */
2600         for (i = 0; i < domain->class_vtable_array->len; ++i)
2601                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2602         mono_gc_collect (0);
2603 #endif
2604         for (i = 0; i < domain->class_vtable_array->len; ++i)
2605                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2606         deregister_reflection_info_roots (domain);
2607
2608         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2609
2610         mono_domain_unlock (domain);
2611         mono_loader_unlock ();
2612
2613         domain->state = MONO_APPDOMAIN_UNLOADED;
2614
2615         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2616
2617         /* remove from the handle table the items related to this domain */
2618         mono_gchandle_free_domain (domain);
2619
2620         mono_domain_free (domain, FALSE);
2621
2622         mono_gc_collect (mono_gc_max_generation ());
2623
2624         mono_atomic_store_release (&data->done, TRUE);
2625         unload_data_unref (data);
2626         return 0;
2627
2628 failure:
2629         mono_atomic_store_release (&data->done, TRUE);
2630         unload_data_unref (data);
2631         return 1;
2632 }
2633
2634 /**
2635  * mono_domain_unload:
2636  * \param domain The domain to unload
2637  *
2638  * Unloads an appdomain. Follows the process outlined in the comment
2639  * for \c mono_domain_try_unload.
2640  */
2641 void
2642 mono_domain_unload (MonoDomain *domain)
2643 {
2644         MonoObject *exc = NULL;
2645         mono_domain_try_unload (domain, &exc);
2646 }
2647
2648 static MonoThreadInfoWaitRet
2649 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2650 {
2651         MonoThreadInfoWaitRet result;
2652
2653         MONO_ENTER_GC_SAFE;
2654         result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2655         MONO_EXIT_GC_SAFE;
2656
2657         return result;
2658 }
2659
2660 /**
2661  * mono_domain_unload:
2662  * \param domain The domain to unload
2663  * \param exc Exception information
2664  *
2665  *  Unloads an appdomain. Follows the process outlined in:
2666  *  http://blogs.gotdotnet.com/cbrumme
2667  *
2668  *  If doing things the 'right' way is too hard or complex, we do it the 
2669  *  'simple' way, which means do everything needed to avoid crashes and
2670  *  memory leaks, but not much else.
2671  *
2672  *  It is required to pass a valid reference to the exc argument, upon return
2673  *  from this function *exc will be set to the exception thrown, if any.
2674  *
2675  *  If this method is not called from an icall (embedded scenario for instance),
2676  *  it must not be called with any managed frames on the stack, since the unload
2677  *  process could end up trying to abort the current thread.
2678  */
2679 void
2680 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2681 {
2682         MonoError error;
2683         MonoThreadHandle *thread_handle;
2684         MonoAppDomainState prev_state;
2685         MonoMethod *method;
2686         unload_data *thread_data;
2687         MonoInternalThread *internal;
2688         MonoDomain *caller_domain = mono_domain_get ();
2689
2690         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2691
2692         /* Atomically change our state to UNLOADING */
2693         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2694                 MONO_APPDOMAIN_UNLOADING_START,
2695                 MONO_APPDOMAIN_CREATED);
2696         if (prev_state != MONO_APPDOMAIN_CREATED) {
2697                 switch (prev_state) {
2698                 case MONO_APPDOMAIN_UNLOADING_START:
2699                 case MONO_APPDOMAIN_UNLOADING:
2700                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2701                         return;
2702                 case MONO_APPDOMAIN_UNLOADED:
2703                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2704                         return;
2705                 default:
2706                         g_warning ("Invalid appdomain state %d", prev_state);
2707                         g_assert_not_reached ();
2708                 }
2709         }
2710
2711         mono_domain_set (domain, FALSE);
2712         /* Notify OnDomainUnload listeners */
2713         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2714         g_assert (method);
2715
2716         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2717
2718         if (!mono_error_ok (&error)) {
2719                 if (*exc)
2720                         mono_error_cleanup (&error);
2721                 else
2722                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2723         }
2724
2725         if (*exc) {
2726                 /* Roll back the state change */
2727                 domain->state = MONO_APPDOMAIN_CREATED;
2728                 mono_domain_set (caller_domain, FALSE);
2729                 return;
2730         }
2731         mono_domain_set (caller_domain, FALSE);
2732
2733         thread_data = g_new0 (unload_data, 1);
2734         thread_data->domain = domain;
2735         thread_data->failure_reason = NULL;
2736         thread_data->done = FALSE;
2737         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2738
2739         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2740         domain->state = MONO_APPDOMAIN_UNLOADING;
2741         /* 
2742          * First we create a separate thread for unloading, since
2743          * we might have to abort some threads, including the current one.
2744          *
2745          * Have to attach to the runtime so shutdown can wait for this thread.
2746          *
2747          * Force it to be attached to avoid racing during shutdown.
2748          */
2749         internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2750         mono_error_assert_ok (&error);
2751
2752         thread_handle = mono_threads_open_thread_handle (internal->handle);
2753
2754         /* Wait for the thread */       
2755         while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2756                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2757                         /* The unload thread tries to abort us */
2758                         /* The icall wrapper will execute the abort */
2759                         mono_threads_close_thread_handle (thread_handle);
2760                         unload_data_unref (thread_data);
2761                         return;
2762                 }
2763         }
2764
2765         mono_threads_close_thread_handle (thread_handle);
2766
2767         if (thread_data->failure_reason) {
2768                 /* Roll back the state change */
2769                 domain->state = MONO_APPDOMAIN_CREATED;
2770
2771                 g_warning ("%s", thread_data->failure_reason);
2772
2773                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2774
2775                 g_free (thread_data->failure_reason);
2776                 thread_data->failure_reason = NULL;
2777         }
2778
2779         unload_data_unref (thread_data);
2780 }