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