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