[scripts] Don't build in checked mode
[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, ".config", sibling_target, sibling_target_len, 7);
1847         
1848         g_free (sibling_source);
1849         g_free (sibling_target);
1850         
1851         if (!copy_result)  {
1852                 g_free (shadow);
1853                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1854                 return NULL;
1855         }
1856
1857         /* Create a .ini file containing the original assembly location */
1858         if (!shadow_copy_create_ini (shadow, filename)) {
1859                 g_free (shadow);
1860                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1861                 return NULL;
1862         }
1863
1864         utbuf.actime = src_sbuf.st_atime;
1865         utbuf.modtime = src_sbuf.st_mtime;
1866         utime (shadow, &utbuf);
1867         
1868         return shadow;
1869 }
1870 #endif /* DISABLE_SHADOW_COPY */
1871
1872 /**
1873  * mono_domain_from_appdomain:
1874  */
1875 MonoDomain *
1876 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1877 {
1878         HANDLE_FUNCTION_ENTER ();
1879         MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1880         MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1881         HANDLE_FUNCTION_RETURN_VAL (result);
1882 }
1883
1884 MonoDomain *
1885 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1886 {
1887         HANDLE_FUNCTION_ENTER ();
1888         MonoDomain *dom = NULL;
1889         if (MONO_HANDLE_IS_NULL (appdomain))
1890                 goto leave;
1891
1892         if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1893                 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1894                 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1895                 
1896                 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1897         } else
1898                 dom = MONO_HANDLE_GETVAL (appdomain, data);
1899
1900 leave:
1901         HANDLE_FUNCTION_RETURN_VAL (dom);
1902 }
1903
1904
1905 static gboolean
1906 try_load_from (MonoAssembly **assembly,
1907                const gchar *path1, const gchar *path2,
1908                const gchar *path3, const gchar *path4,
1909                gboolean refonly, gboolean is_private,
1910                MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1911 {
1912         gchar *fullpath;
1913         gboolean found = FALSE;
1914         
1915         *assembly = NULL;
1916         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1917
1918         if (IS_PORTABILITY_SET) {
1919                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1920                 if (new_fullpath) {
1921                         g_free (fullpath);
1922                         fullpath = new_fullpath;
1923                         found = TRUE;
1924                 }
1925         } else
1926                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1927         
1928         if (found)
1929                 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1930
1931         g_free (fullpath);
1932         return (*assembly != NULL);
1933 }
1934
1935 static MonoAssembly *
1936 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1937 {
1938         MonoAssembly *result = NULL;
1939         gchar **path;
1940         gchar *filename;
1941         const gchar *local_culture;
1942         gint len;
1943         gboolean is_private = FALSE;
1944
1945         if (!culture || *culture == '\0') {
1946                 local_culture = "";
1947         } else {
1948                 local_culture = culture;
1949         }
1950
1951         filename =  g_strconcat (name, ".dll", NULL);
1952         len = strlen (filename);
1953
1954         for (path = search_path; *path; path++) {
1955                 if (**path == '\0') {
1956                         is_private = TRUE;
1957                         continue; /* Ignore empty ApplicationBase */
1958                 }
1959
1960                 /* See test cases in bug #58992 and bug #57710 */
1961                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1962                 strcpy (filename + len - 4, ".dll");
1963                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1964                         break;
1965
1966                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1967                 strcpy (filename + len - 4, ".exe");
1968                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1969                         break;
1970
1971                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1972                 strcpy (filename + len - 4, ".dll");
1973                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1974                         break;
1975
1976                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1977                 strcpy (filename + len - 4, ".exe");
1978                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1979                         break;
1980         }
1981
1982         g_free (filename);
1983         return result;
1984 }
1985
1986 /*
1987  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1988  * and then from assemblies_path if any.
1989  * LOCKING: This is called from the assembly loading code, which means the caller
1990  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1991  */
1992 static MonoAssembly *
1993 mono_domain_assembly_preload (MonoAssemblyName *aname,
1994                               gchar **assemblies_path,
1995                               gpointer user_data)
1996 {
1997         MonoDomain *domain = mono_domain_get ();
1998         MonoAssembly *result = NULL;
1999         gboolean refonly = GPOINTER_TO_UINT (user_data);
2000
2001         set_domain_search_path (domain);
2002
2003         if (domain->search_path && domain->search_path [0] != NULL) {
2004                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2005                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2006                         for (int i = 0; domain->search_path [i]; i++) {
2007                                 const char *p = domain->search_path[i];
2008                                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2009                         }
2010                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);                    
2011                 }
2012                 result = real_load (domain->search_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2013         }
2014
2015         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2016                 result = real_load (assemblies_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2017         }
2018
2019         return result;
2020 }
2021
2022 /*
2023  * Check whenever a given assembly was already loaded in the current appdomain.
2024  */
2025 static MonoAssembly *
2026 mono_domain_assembly_search (MonoAssemblyName *aname,
2027                                                          gpointer user_data)
2028 {
2029         MonoDomain *domain = mono_domain_get ();
2030         GSList *tmp;
2031         MonoAssembly *ass;
2032         gboolean refonly = GPOINTER_TO_UINT (user_data);
2033
2034         mono_domain_assemblies_lock (domain);
2035         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2036                 ass = (MonoAssembly *)tmp->data;
2037                 /* Dynamic assemblies can't match here in MS.NET */
2038                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2039                         continue;
2040
2041                 mono_domain_assemblies_unlock (domain);
2042                 return ass;
2043         }
2044         mono_domain_assemblies_unlock (domain);
2045
2046         return NULL;
2047 }
2048
2049 MonoReflectionAssemblyHandle
2050 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2051 {
2052         error_init (error);
2053         MonoDomain *domain = mono_domain_get ();
2054         char *name, *filename;
2055         MonoImageOpenStatus status = MONO_IMAGE_OK;
2056         MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2057
2058         name = NULL;
2059         result = NULL;
2060
2061         if (fname == NULL) {
2062                 mono_error_set_argument_null (error, "assemblyFile", "");
2063                 goto leave;
2064         }
2065                 
2066         name = filename = mono_string_handle_to_utf8 (fname, error);
2067         if (!is_ok (error))
2068                 goto leave;
2069         
2070         MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2071         
2072         if (!ass) {
2073                 if (status == MONO_IMAGE_IMAGE_INVALID)
2074                         mono_error_set_bad_image_name (error, g_strdup (name), "");
2075                 else
2076                         mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2077                 goto leave;
2078         }
2079
2080         result = mono_assembly_get_object_handle (domain, ass, error);
2081
2082 leave:
2083         g_free (name);
2084         return result;
2085 }
2086
2087 MonoReflectionAssemblyHandle
2088 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, 
2089                                             MonoArrayHandle raw_assembly,
2090                                             MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2091                                             MonoBoolean refonly,
2092                                             MonoError *error)
2093 {
2094         error_init (error);
2095         MonoAssembly *ass;
2096         MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2097         MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2098         MonoImageOpenStatus status;
2099         guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2100
2101         /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2102         char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2103         if (!assembly_data) {
2104                 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2105                 return refass;
2106         }
2107         uint32_t gchandle;
2108         mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2109         memcpy (assembly_data, raw_data, raw_assembly_len);
2110         mono_gchandle_free (gchandle); /* unpin */
2111         MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2112         
2113         MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2114
2115         if (!image) {
2116                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2117                 return refass;
2118         }
2119
2120         if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2121                 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2122                 uint32_t symbol_gchandle;
2123                 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2124                 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2125                 mono_gchandle_free (symbol_gchandle);
2126         }
2127
2128         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2129
2130
2131         if (!ass) {
2132                 mono_image_close (image);
2133                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2134                 return refass; 
2135         }
2136
2137         refass = mono_assembly_get_object_handle (domain, ass, error);
2138         if (!MONO_HANDLE_IS_NULL(refass))
2139                 MONO_HANDLE_SET (refass, evidence, evidence);
2140         return refass;
2141 }
2142
2143 MonoReflectionAssemblyHandle
2144 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2145 {
2146         error_init (error);
2147         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2148         MonoImageOpenStatus status = MONO_IMAGE_OK;
2149         MonoAssembly *ass;
2150         MonoAssemblyName aname;
2151         gchar *name = NULL;
2152         gboolean parsed;
2153
2154         g_assert (assRef);
2155
2156         name = mono_string_handle_to_utf8 (assRef, error);
2157         if (!is_ok (error))
2158                 goto fail;
2159         parsed = mono_assembly_name_parse (name, &aname);
2160         g_free (name);
2161
2162         if (!parsed) {
2163                 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2164                 /* This is a parse error... */
2165                 if (!refOnly) {
2166                         MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2167                         if (!is_ok (error))
2168                                 goto fail;
2169                         if (assm) {
2170                                 refass = mono_assembly_get_object_handle (domain, assm, error);
2171                                 if (!is_ok (error))
2172                                         goto fail;
2173                         }
2174                 }
2175                 return refass;
2176         }
2177
2178         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2179         mono_assembly_name_free (&aname);
2180
2181         if (!ass) {
2182                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2183                 if (!refOnly) {
2184                         ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2185                         if (!is_ok (error))
2186                                 goto fail;
2187                 }
2188                 if (!ass)
2189                         goto fail;
2190         }
2191
2192         g_assert (ass);
2193         MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2194         if (!is_ok (error))
2195                 goto fail;
2196
2197         MONO_HANDLE_SET (refass, evidence, evidence);
2198
2199         return refass;
2200 fail:
2201         return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2202 }
2203
2204 void
2205 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2206 {
2207         error_init (error);
2208         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2209
2210         if (NULL == domain) {
2211                 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2212                 return;
2213         }
2214         
2215         if (domain == mono_get_root_domain ()) {
2216                 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2217                 return;
2218         }
2219
2220         /* 
2221          * Unloading seems to cause problems when running NUnit/NAnt, hence
2222          * this workaround.
2223          */
2224         if (g_hasenv ("MONO_NO_UNLOAD"))
2225                 return;
2226
2227 #ifdef __native_client__
2228         return;
2229 #endif
2230
2231         MonoException *exc = NULL;
2232         mono_domain_try_unload (domain, (MonoObject**)&exc);
2233         if (exc)
2234                 mono_error_set_exception_instance (error, exc);
2235 }
2236
2237 gboolean
2238 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2239 {
2240         error_init (error);
2241         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2242
2243         if (!domain)
2244                 return TRUE;
2245
2246         return mono_domain_is_unloading (domain);
2247 }
2248
2249 void
2250 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2251 {
2252         error_init (error);
2253         mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2254         mono_error_assert_ok (error);
2255 }
2256
2257 gint32
2258 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2259                                             MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2260                                             MonoError *error)
2261 {
2262         error_init (error);
2263         MonoImage *image;
2264         MonoMethod *method;
2265
2266         g_assert (!MONO_HANDLE_IS_NULL (refass));
2267         MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2268         image = assembly->image;
2269         g_assert (image);
2270
2271         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2272
2273         if (!method)
2274                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2275
2276         if (MONO_HANDLE_IS_NULL (args)) {
2277                 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2278                 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2279                 mono_error_assert_ok (error);
2280         }
2281
2282         int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2283         return res;
2284 }
2285
2286 gint32 
2287 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2288 {
2289         return ad->data->domain_id;
2290 }
2291
2292 MonoAppDomainHandle
2293 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2294 {
2295         error_init (error);
2296         MonoDomain *old_domain = mono_domain_get ();
2297
2298         if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2299                 mono_error_set_appdomain_unloaded (error);
2300                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2301         }
2302
2303         return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2304 }
2305
2306 MonoAppDomainHandle
2307 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2308 {
2309         MonoDomain *current_domain = mono_domain_get ();
2310         MonoDomain *domain = mono_domain_get_by_id (domainid);
2311
2312         if (!domain || !mono_domain_set (domain, FALSE)) {
2313                 mono_error_set_appdomain_unloaded (error);
2314                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2315         }
2316
2317         return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2318 }
2319
2320 void
2321 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2322 {
2323         error_init (error);
2324         mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2325 }
2326
2327 void
2328 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2329 {
2330         error_init (error);
2331         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2332
2333         if (!domain) {
2334                 /* 
2335                  * Raise an exception to prevent the managed code from executing a pop
2336                  * later.
2337                  */
2338                 mono_error_set_appdomain_unloaded (error);
2339                 return;
2340         }
2341
2342         mono_thread_push_appdomain_ref (domain);
2343 }
2344
2345 void
2346 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2347 {
2348         error_init (error);
2349         mono_thread_pop_appdomain_ref ();
2350 }
2351
2352 MonoAppContextHandle
2353 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2354 {
2355         error_init (error);
2356         return mono_context_get_handle ();
2357 }
2358
2359 MonoAppContextHandle
2360 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2361 {
2362         error_init (error);
2363         return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2364 }
2365
2366 MonoAppContextHandle
2367 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2368 {
2369         error_init (error);
2370         MonoAppContextHandle old_context = mono_context_get_handle ();
2371
2372         mono_context_set_handle (mc);
2373
2374         return old_context;
2375 }
2376
2377 MonoStringHandle
2378 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2379 {
2380         error_init (error);
2381         MonoDomain* mono_root_domain = mono_get_root_domain ();
2382         mono_domain_lock (mono_root_domain);
2383         if (process_guid_set) {
2384                 mono_domain_unlock (mono_root_domain);
2385                 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2386         }
2387         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2388         memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2389         mono_gchandle_free (gchandle);
2390         process_guid_set = TRUE;
2391         mono_domain_unlock (mono_root_domain);
2392         return newguid;
2393 }
2394
2395 /**
2396  * mono_domain_is_unloading:
2397  */
2398 gboolean
2399 mono_domain_is_unloading (MonoDomain *domain)
2400 {
2401         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2402                 return TRUE;
2403         else
2404                 return FALSE;
2405 }
2406
2407 static void
2408 clear_cached_vtable (MonoVTable *vtable)
2409 {
2410         MonoClass *klass = vtable->klass;
2411         MonoDomain *domain = vtable->domain;
2412         MonoClassRuntimeInfo *runtime_info;
2413         void *data;
2414
2415         runtime_info = klass->runtime_info;
2416         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2417                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2418         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2419                 mono_gc_free_fixed (data);
2420 }
2421
2422 static G_GNUC_UNUSED void
2423 zero_static_data (MonoVTable *vtable)
2424 {
2425         MonoClass *klass = vtable->klass;
2426         void *data;
2427
2428         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2429                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2430 }
2431
2432 typedef struct unload_data {
2433         gboolean done;
2434         MonoDomain *domain;
2435         char *failure_reason;
2436         gint32 refcount;
2437 } unload_data;
2438
2439 static void
2440 unload_data_unref (unload_data *data)
2441 {
2442         gint32 count;
2443         do {
2444                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2445                 g_assert (count >= 1 && count <= 2);
2446                 if (count == 1) {
2447                         g_free (data);
2448                         return;
2449                 }
2450         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2451 }
2452
2453 static void
2454 deregister_reflection_info_roots_from_list (MonoImage *image)
2455 {
2456         GSList *list = image->reflection_info_unregister_classes;
2457
2458         while (list) {
2459                 MonoClass *klass = (MonoClass *)list->data;
2460
2461                 mono_class_free_ref_info (klass);
2462
2463                 list = list->next;
2464         }
2465
2466         image->reflection_info_unregister_classes = NULL;
2467 }
2468
2469 static void
2470 deregister_reflection_info_roots (MonoDomain *domain)
2471 {
2472         GSList *list;
2473
2474         mono_domain_assemblies_lock (domain);
2475         for (list = domain->domain_assemblies; list; list = list->next) {
2476                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2477                 MonoImage *image = assembly->image;
2478                 int i;
2479
2480                 /*
2481                  * No need to take the image lock here since dynamic images are appdomain bound and
2482                  * at this point the mutator is gone.  Taking the image lock here would mean
2483                  * promoting it from a simple lock to a complex lock, which we better avoid if
2484                  * possible.
2485                  */
2486                 if (image_is_dynamic (image))
2487                         deregister_reflection_info_roots_from_list (image);
2488
2489                 for (i = 0; i < image->module_count; ++i) {
2490                         MonoImage *module = image->modules [i];
2491                         if (module && image_is_dynamic (module))
2492                                 deregister_reflection_info_roots_from_list (module);
2493                 }
2494         }
2495         mono_domain_assemblies_unlock (domain);
2496 }
2497
2498 static gsize WINAPI
2499 unload_thread_main (void *arg)
2500 {
2501         MonoError error;
2502         unload_data *data = (unload_data*)arg;
2503         MonoDomain *domain = data->domain;
2504         MonoInternalThread *internal;
2505         int i;
2506
2507         internal = mono_thread_internal_current ();
2508
2509         mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2510         if (!is_ok (&error)) {
2511                 data->failure_reason = g_strdup (mono_error_get_message (&error));
2512                 mono_error_cleanup (&error);
2513                 goto failure;
2514         }
2515
2516         /* 
2517          * FIXME: Abort our parent thread last, so we can return a failure 
2518          * indication if aborting times out.
2519          */
2520         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2521                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2522                 goto failure;
2523         }
2524
2525         if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2526                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2527                 goto failure;
2528         }
2529
2530         /* Finalize all finalizable objects in the doomed appdomain */
2531         if (!mono_domain_finalize (domain, -1)) {
2532                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2533                 goto failure;
2534         }
2535
2536         /* Clear references to our vtables in class->runtime_info.
2537          * We also hold the loader lock because we're going to change
2538          * class->runtime_info.
2539          */
2540
2541         mono_loader_lock (); //FIXME why do we need the loader lock here?
2542         mono_domain_lock (domain);
2543 #ifdef HAVE_SGEN_GC
2544         /*
2545          * We need to make sure that we don't have any remsets
2546          * pointing into static data of the to-be-freed domain because
2547          * at the next collections they would be invalid.  So what we
2548          * do is we first zero all static data and then do a minor
2549          * collection.  Because all references in the static data will
2550          * now be null we won't do any unnecessary copies and after
2551          * the collection there won't be any more remsets.
2552          */
2553         for (i = 0; i < domain->class_vtable_array->len; ++i)
2554                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2555         mono_gc_collect (0);
2556 #endif
2557         for (i = 0; i < domain->class_vtable_array->len; ++i)
2558                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2559         deregister_reflection_info_roots (domain);
2560
2561         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2562
2563         mono_domain_unlock (domain);
2564         mono_loader_unlock ();
2565
2566         domain->state = MONO_APPDOMAIN_UNLOADED;
2567
2568         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2569
2570         /* remove from the handle table the items related to this domain */
2571         mono_gchandle_free_domain (domain);
2572
2573         mono_domain_free (domain, FALSE);
2574
2575         mono_gc_collect (mono_gc_max_generation ());
2576
2577         mono_atomic_store_release (&data->done, TRUE);
2578         unload_data_unref (data);
2579         return 0;
2580
2581 failure:
2582         mono_atomic_store_release (&data->done, TRUE);
2583         unload_data_unref (data);
2584         return 1;
2585 }
2586
2587 /**
2588  * mono_domain_unload:
2589  * \param domain The domain to unload
2590  *
2591  * Unloads an appdomain. Follows the process outlined in the comment
2592  * for \c mono_domain_try_unload.
2593  */
2594 void
2595 mono_domain_unload (MonoDomain *domain)
2596 {
2597         MonoObject *exc = NULL;
2598         mono_domain_try_unload (domain, &exc);
2599 }
2600
2601 static MonoThreadInfoWaitRet
2602 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2603 {
2604         MonoThreadInfoWaitRet result;
2605
2606         MONO_ENTER_GC_SAFE;
2607         result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2608         MONO_EXIT_GC_SAFE;
2609
2610         return result;
2611 }
2612
2613 /**
2614  * mono_domain_unload:
2615  * \param domain The domain to unload
2616  * \param exc Exception information
2617  *
2618  *  Unloads an appdomain. Follows the process outlined in:
2619  *  http://blogs.gotdotnet.com/cbrumme
2620  *
2621  *  If doing things the 'right' way is too hard or complex, we do it the 
2622  *  'simple' way, which means do everything needed to avoid crashes and
2623  *  memory leaks, but not much else.
2624  *
2625  *  It is required to pass a valid reference to the exc argument, upon return
2626  *  from this function *exc will be set to the exception thrown, if any.
2627  *
2628  *  If this method is not called from an icall (embedded scenario for instance),
2629  *  it must not be called with any managed frames on the stack, since the unload
2630  *  process could end up trying to abort the current thread.
2631  */
2632 void
2633 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2634 {
2635         MonoError error;
2636         MonoThreadHandle *thread_handle;
2637         MonoAppDomainState prev_state;
2638         MonoMethod *method;
2639         unload_data *thread_data;
2640         MonoInternalThread *internal;
2641         MonoDomain *caller_domain = mono_domain_get ();
2642
2643         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2644
2645         /* Atomically change our state to UNLOADING */
2646         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2647                 MONO_APPDOMAIN_UNLOADING_START,
2648                 MONO_APPDOMAIN_CREATED);
2649         if (prev_state != MONO_APPDOMAIN_CREATED) {
2650                 switch (prev_state) {
2651                 case MONO_APPDOMAIN_UNLOADING_START:
2652                 case MONO_APPDOMAIN_UNLOADING:
2653                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2654                         return;
2655                 case MONO_APPDOMAIN_UNLOADED:
2656                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2657                         return;
2658                 default:
2659                         g_warning ("Invalid appdomain state %d", prev_state);
2660                         g_assert_not_reached ();
2661                 }
2662         }
2663
2664         mono_domain_set (domain, FALSE);
2665         /* Notify OnDomainUnload listeners */
2666         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2667         g_assert (method);
2668
2669         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2670
2671         if (!mono_error_ok (&error)) {
2672                 if (*exc)
2673                         mono_error_cleanup (&error);
2674                 else
2675                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2676         }
2677
2678         if (*exc) {
2679                 /* Roll back the state change */
2680                 domain->state = MONO_APPDOMAIN_CREATED;
2681                 mono_domain_set (caller_domain, FALSE);
2682                 return;
2683         }
2684         mono_domain_set (caller_domain, FALSE);
2685
2686         thread_data = g_new0 (unload_data, 1);
2687         thread_data->domain = domain;
2688         thread_data->failure_reason = NULL;
2689         thread_data->done = FALSE;
2690         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2691
2692         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2693         domain->state = MONO_APPDOMAIN_UNLOADING;
2694         /* 
2695          * First we create a separate thread for unloading, since
2696          * we might have to abort some threads, including the current one.
2697          *
2698          * Have to attach to the runtime so shutdown can wait for this thread.
2699          *
2700          * Force it to be attached to avoid racing during shutdown.
2701          */
2702         internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2703         mono_error_assert_ok (&error);
2704
2705         thread_handle = mono_threads_open_thread_handle (internal->handle);
2706
2707         /* Wait for the thread */       
2708         while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2709                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2710                         /* The unload thread tries to abort us */
2711                         /* The icall wrapper will execute the abort */
2712                         mono_threads_close_thread_handle (thread_handle);
2713                         unload_data_unref (thread_data);
2714                         return;
2715                 }
2716         }
2717
2718         mono_threads_close_thread_handle (thread_handle);
2719
2720         if (thread_data->failure_reason) {
2721                 /* Roll back the state change */
2722                 domain->state = MONO_APPDOMAIN_CREATED;
2723
2724                 g_warning ("%s", thread_data->failure_reason);
2725
2726                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2727
2728                 g_free (thread_data->failure_reason);
2729                 thread_data->failure_reason = NULL;
2730         }
2731
2732         unload_data_unref (thread_data);
2733 }