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