Merge pull request #4536 from kumpera/block-rebind-of-banned-assemblies
[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                 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1193                         g_hash_table_insert (ht, tmp->data, tmp->data);
1194                 }
1195         }
1196
1197         /* FIXME: handle lazy loaded assemblies */
1198
1199         if (!g_hash_table_lookup (ht, ass)) {
1200                 mono_assembly_addref (ass);
1201                 g_hash_table_insert (ht, ass, ass);
1202                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1203                 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);
1204         }
1205
1206         if (ass->image->references) {
1207                 for (i = 0; i < ass->image->nreferences; i++) {
1208                         if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1209                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1210                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1211                                 }
1212                         }
1213                 }
1214         }
1215         if (destroy_ht)
1216                 g_hash_table_destroy (ht);
1217 }
1218
1219 static void
1220 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1221 {
1222         static MonoClassField *assembly_load_field;
1223         static MonoMethod *assembly_load_method;
1224         MonoError error;
1225         MonoDomain *domain = mono_domain_get ();
1226         MonoClass *klass;
1227         gpointer load_value;
1228         void *params [1];
1229
1230         if (!domain->domain)
1231                 /* This can happen during startup */
1232                 return;
1233 #ifdef ASSEMBLY_LOAD_DEBUG
1234         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1235 #endif
1236         klass = domain->domain->mbr.obj.vtable->klass;
1237
1238         mono_domain_assemblies_lock (domain);
1239         add_assemblies_to_domain (domain, assembly, NULL);
1240         mono_domain_assemblies_unlock (domain);
1241
1242         if (assembly_load_field == NULL) {
1243                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1244                 g_assert (assembly_load_field);
1245         }
1246
1247         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1248         if (load_value == NULL) {
1249                 /* No events waiting to be triggered */
1250                 return;
1251         }
1252
1253         MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1254         mono_error_assert_ok (&error);
1255
1256         if (assembly_load_method == NULL) {
1257                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1258                 g_assert (assembly_load_method);
1259         }
1260
1261         *params = MONO_HANDLE_RAW(ref_assembly);
1262
1263         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1264         mono_error_cleanup (&error);
1265 }
1266
1267 /*
1268  * LOCKING: Acquires the domain assemblies lock.
1269  */
1270 static void
1271 set_domain_search_path (MonoDomain *domain)
1272 {
1273         MonoError error;
1274         MonoAppDomainSetup *setup;
1275         gchar **tmp;
1276         gchar *search_path = NULL;
1277         gint i;
1278         gint npaths = 0;
1279         gchar **pvt_split = NULL;
1280         GError *gerror = NULL;
1281         gint appbaselen = -1;
1282
1283         /* 
1284          * We use the low-level domain assemblies lock, since this is called from
1285          * assembly loads hooks, which means this thread might hold the loader lock.
1286          */
1287         mono_domain_assemblies_lock (domain);
1288
1289         if (!domain->setup) {
1290                 mono_domain_assemblies_unlock (domain);
1291                 return;
1292         }
1293
1294         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1295                 mono_domain_assemblies_unlock (domain);
1296                 return;
1297         }
1298         setup = domain->setup;
1299         if (!setup->application_base) {
1300                 mono_domain_assemblies_unlock (domain);
1301                 return; /* Must set application base to get private path working */
1302         }
1303
1304         npaths++;
1305         
1306         if (setup->private_bin_path) {
1307                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1308                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1309                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1310                         mono_error_cleanup (&error);
1311                         mono_domain_assemblies_unlock (domain);
1312                         return;
1313                 }
1314         }
1315         
1316         if (domain->private_bin_path) {
1317                 if (search_path == NULL)
1318                         search_path = domain->private_bin_path;
1319                 else {
1320                         gchar *tmp2 = search_path;
1321                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1322                         g_free (tmp2);
1323                 }
1324         }
1325         
1326         if (search_path) {
1327                 /*
1328                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1329                  * directories relative to ApplicationBase separated by semicolons (see
1330                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1331                  * The loop below copes with the fact that some Unix applications may use ':' (or
1332                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1333                  * ';' for the subsequent split.
1334                  *
1335                  * The issue was reported in bug #81446
1336                  */
1337
1338 #ifndef TARGET_WIN32
1339                 gint slen;
1340
1341                 slen = strlen (search_path);
1342                 for (i = 0; i < slen; i++)
1343                         if (search_path [i] == ':')
1344                                 search_path [i] = ';';
1345 #endif
1346                 
1347                 pvt_split = g_strsplit (search_path, ";", 1000);
1348                 g_free (search_path);
1349                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1350         }
1351
1352         if (!npaths) {
1353                 if (pvt_split)
1354                         g_strfreev (pvt_split);
1355                 /*
1356                  * Don't do this because the first time is called, the domain
1357                  * setup is not finished.
1358                  *
1359                  * domain->search_path = g_malloc (sizeof (char *));
1360                  * domain->search_path [0] = NULL;
1361                 */
1362                 mono_domain_assemblies_unlock (domain);
1363                 return;
1364         }
1365
1366         if (domain->search_path)
1367                 g_strfreev (domain->search_path);
1368
1369         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1370         tmp [npaths] = NULL;
1371
1372         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1373         if (!mono_error_ok (&error)) {
1374                 mono_error_cleanup (&error);
1375                 g_strfreev (pvt_split);
1376                 g_free (tmp);
1377
1378                 mono_domain_assemblies_unlock (domain);
1379                 return;
1380         }
1381
1382         domain->search_path = tmp;
1383
1384         /* FIXME: is this needed? */
1385         if (strncmp (*tmp, "file://", 7) == 0) {
1386                 gchar *file = *tmp;
1387                 gchar *uri = *tmp;
1388                 gchar *tmpuri;
1389
1390                 if (uri [7] != '/')
1391                         uri = g_strdup_printf ("file:///%s", uri + 7);
1392
1393                 tmpuri = uri;
1394                 uri = mono_escape_uri_string (tmpuri);
1395                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1396                 g_free (uri);
1397
1398                 if (tmpuri != file)
1399                         g_free (tmpuri);
1400
1401                 if (gerror != NULL) {
1402                         g_warning ("%s\n", gerror->message);
1403                         g_error_free (gerror);
1404                         *tmp = file;
1405                 } else {
1406                         g_free (file);
1407                 }
1408         }
1409
1410         for (i = 1; pvt_split && i < npaths; i++) {
1411                 if (g_path_is_absolute (pvt_split [i - 1])) {
1412                         tmp [i] = g_strdup (pvt_split [i - 1]);
1413                 } else {
1414                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1415                 }
1416
1417                 if (strchr (tmp [i], '.')) {
1418                         gchar *reduced;
1419                         gchar *freeme;
1420
1421                         reduced = mono_path_canonicalize (tmp [i]);
1422                         if (appbaselen == -1)
1423                                 appbaselen = strlen (tmp [0]);
1424
1425                         if (strncmp (tmp [0], reduced, appbaselen)) {
1426                                 g_free (reduced);
1427                                 g_free (tmp [i]);
1428                                 tmp [i] = g_strdup ("");
1429                                 continue;
1430                         }
1431
1432                         freeme = tmp [i];
1433                         tmp [i] = reduced;
1434                         g_free (freeme);
1435                 }
1436         }
1437         
1438         if (setup->private_bin_path_probe != NULL) {
1439                 g_free (tmp [0]);
1440                 tmp [0] = g_strdup ("");
1441         }
1442                 
1443         domain->setup->path_changed = FALSE;
1444
1445         g_strfreev (pvt_split);
1446
1447         mono_domain_assemblies_unlock (domain);
1448 }
1449
1450 #ifdef DISABLE_SHADOW_COPY
1451 gboolean
1452 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1453 {
1454         return FALSE;
1455 }
1456
1457 char *
1458 mono_make_shadow_copy (const char *filename, MonoError *error)
1459 {
1460         error_init (error);
1461         return (char *) filename;
1462 }
1463 #else
1464 static gboolean
1465 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1466 {
1467         guint16 *orig, *dest;
1468         gboolean copy_result;
1469         gint32 copy_error;
1470         
1471         strcpy (src + srclen - tail_len, extension);
1472
1473         if (IS_PORTABILITY_CASE) {
1474                 gchar *file = mono_portability_find_file (src, TRUE);
1475
1476                 if (file == NULL)
1477                         return TRUE;
1478
1479                 g_free (file);
1480         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1481                 return TRUE;
1482         }
1483
1484         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1485
1486         strcpy (target + targetlen - tail_len, extension);
1487         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1488         
1489         mono_w32file_delete (dest);
1490
1491         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1492
1493         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1494          * overwritten when updated in their original locations. */
1495         if (copy_result)
1496                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1497
1498         g_free (orig);
1499         g_free (dest);
1500         
1501         return copy_result;
1502 }
1503
1504 static gint32 
1505 get_cstring_hash (const char *str)
1506 {
1507         int len, i;
1508         const char *p;
1509         gint32 h = 0;
1510         
1511         if (!str || !str [0])
1512                 return 0;
1513                 
1514         len = strlen (str);
1515         p = str;
1516         for (i = 0; i < len; i++) {
1517                 h = (h << 5) - h + *p;
1518                 p++;
1519         }
1520         
1521         return h;
1522 }
1523
1524 /*
1525  * Returned memory is malloc'd. Called must free it 
1526  */
1527 static char *
1528 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1529 {
1530         MonoAppDomainSetup *setup;
1531         char *cache_path, *appname;
1532         char *userdir;
1533         char *location;
1534
1535         error_init (error);
1536         
1537         setup = domain->setup;
1538         if (setup->cache_path != NULL && setup->application_name != NULL) {
1539                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1540                 return_val_if_nok (error, NULL);
1541
1542 #ifndef TARGET_WIN32
1543                 {
1544                         gint i;
1545                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1546                                 if (cache_path [i] == '\\')
1547                                         cache_path [i] = '/';
1548                 }
1549 #endif
1550
1551                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1552                 if (!mono_error_ok (error)) {
1553                         g_free (cache_path);
1554                         return NULL;
1555                 }
1556
1557                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1558                 g_free (appname);
1559                 g_free (cache_path);
1560         } else {
1561                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1562                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1563                 g_free (userdir);
1564         }
1565         return location;
1566 }
1567
1568 static char *
1569 get_shadow_assembly_location (const char *filename, MonoError *error)
1570 {
1571         gint32 hash = 0, hash2 = 0;
1572         char name_hash [9];
1573         char path_hash [30];
1574         char *bname = g_path_get_basename (filename);
1575         char *dirname = g_path_get_dirname (filename);
1576         char *location, *tmploc;
1577         MonoDomain *domain = mono_domain_get ();
1578
1579         error_init (error);
1580         
1581         hash = get_cstring_hash (bname);
1582         hash2 = get_cstring_hash (dirname);
1583         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1584         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1585         tmploc = get_shadow_assembly_location_base (domain, error);
1586         if (!mono_error_ok (error)) {
1587                 g_free (bname);
1588                 g_free (dirname);
1589                 return NULL;
1590         }
1591
1592         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1593         g_free (tmploc);
1594         g_free (bname);
1595         g_free (dirname);
1596         return location;
1597 }
1598
1599 static gboolean
1600 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1601 {
1602         struct stat sbuf_dest;
1603         gchar *stat_src;
1604         gchar *real_src = mono_portability_find_file (src, TRUE);
1605
1606         if (!real_src)
1607                 stat_src = (gchar*)src;
1608         else
1609                 stat_src = real_src;
1610
1611         if (stat (stat_src, sbuf_src) == -1) {
1612                 time_t tnow = time (NULL);
1613
1614                 if (real_src)
1615                         g_free (real_src);
1616
1617                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1618                 sbuf_src->st_mtime = tnow;
1619                 sbuf_src->st_atime = tnow;
1620                 return TRUE;
1621         }
1622
1623         if (real_src)
1624                 g_free (real_src);
1625
1626         if (stat (dest, &sbuf_dest) == -1)
1627                 return TRUE;
1628         
1629         if (sbuf_src->st_size == sbuf_dest.st_size &&
1630             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1631                 return FALSE;
1632
1633         return TRUE;
1634 }
1635
1636 static gboolean
1637 shadow_copy_create_ini (const char *shadow, const char *filename)
1638 {
1639         char *dir_name;
1640         char *ini_file;
1641         guint16 *u16_ini;
1642         gboolean result;
1643         guint32 n;
1644         HANDLE *handle;
1645         gchar *full_path;
1646
1647         dir_name = g_path_get_dirname (shadow);
1648         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1649         g_free (dir_name);
1650         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1651                 g_free (ini_file);
1652                 return TRUE;
1653         }
1654
1655         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1656         g_free (ini_file);
1657         if (!u16_ini) {
1658                 return FALSE;
1659         }
1660         handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1661         g_free (u16_ini);
1662         if (handle == INVALID_HANDLE_VALUE) {
1663                 return FALSE;
1664         }
1665
1666         full_path = mono_path_resolve_symlinks (filename);
1667         result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1668         g_free (full_path);
1669         mono_w32file_close (handle);
1670         return result;
1671 }
1672
1673 gboolean
1674 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1675 {
1676         MonoError error;
1677         MonoAppDomainSetup *setup;
1678         gchar *all_dirs;
1679         gchar **dir_ptr;
1680         gchar **directories;
1681         gchar *shadow_status_string;
1682         gchar *base_dir;
1683         gboolean shadow_enabled;
1684         gboolean found = FALSE;
1685
1686         if (domain == NULL)
1687                 return FALSE;
1688
1689         setup = domain->setup;
1690         if (setup == NULL || setup->shadow_copy_files == NULL)
1691                 return FALSE;
1692
1693         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1694         if (!mono_error_ok (&error)) {
1695                 mono_error_cleanup (&error);
1696                 return FALSE;
1697         }
1698         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1699         g_free (shadow_status_string);
1700
1701         if (!shadow_enabled)
1702                 return FALSE;
1703
1704         if (setup->shadow_copy_directories == NULL)
1705                 return TRUE;
1706
1707         /* Is dir_name a shadow_copy destination already? */
1708         base_dir = get_shadow_assembly_location_base (domain, &error);
1709         if (!mono_error_ok (&error)) {
1710                 mono_error_cleanup (&error);
1711                 return FALSE;
1712         }
1713
1714         if (strstr (dir_name, base_dir)) {
1715                 g_free (base_dir);
1716                 return TRUE;
1717         }
1718         g_free (base_dir);
1719
1720         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1721         if (!mono_error_ok (&error)) {
1722                 mono_error_cleanup (&error);
1723                 return FALSE;
1724         }
1725
1726         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1727         dir_ptr = directories;
1728         while (*dir_ptr) {
1729                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1730                         found = TRUE;
1731                         break;
1732                 }
1733                 dir_ptr++;
1734         }
1735         g_strfreev (directories);
1736         g_free (all_dirs);
1737         return found;
1738 }
1739
1740 /*
1741 This function raises exceptions so it can cause as sorts of nasty stuff if called
1742 while holding a lock.
1743 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1744 or NULL if source file not found.
1745 FIXME bubble up the error instead of raising it here
1746 */
1747 char *
1748 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1749 {
1750         MonoError error;
1751         gchar *sibling_source, *sibling_target;
1752         gint sibling_source_len, sibling_target_len;
1753         guint16 *orig, *dest;
1754         guint32 attrs;
1755         char *shadow;
1756         gboolean copy_result;
1757         struct stat src_sbuf;
1758         struct utimbuf utbuf;
1759         char *dir_name = g_path_get_dirname (filename);
1760         MonoDomain *domain = mono_domain_get ();
1761         char *shadow_dir;
1762         gint32 copy_error;
1763
1764         error_init (oerror);
1765
1766         set_domain_search_path (domain);
1767
1768         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1769                 g_free (dir_name);
1770                 return (char *) filename;
1771         }
1772
1773         /* Is dir_name a shadow_copy destination already? */
1774         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1775         if (!mono_error_ok (&error)) {
1776                 mono_error_cleanup (&error);
1777                 g_free (dir_name);
1778                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1779                 return NULL;
1780         }
1781
1782         if (strstr (dir_name, shadow_dir)) {
1783                 g_free (shadow_dir);
1784                 g_free (dir_name);
1785                 return (char *) filename;
1786         }
1787         g_free (shadow_dir);
1788         g_free (dir_name);
1789
1790         shadow = get_shadow_assembly_location (filename, &error);
1791         if (!mono_error_ok (&error)) {
1792                 mono_error_cleanup (&error);
1793                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1794                 return NULL;
1795         }
1796
1797         if (g_ensure_directory_exists (shadow) == FALSE) {
1798                 g_free (shadow);
1799                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1800                 return NULL;
1801         }       
1802
1803         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1804                 return (char*) shadow;
1805
1806         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1807         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1808         mono_w32file_delete (dest);
1809
1810         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1811          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1812          * and not have it runtime error" */
1813         attrs = mono_w32file_get_attributes (orig);
1814         if (attrs == INVALID_FILE_ATTRIBUTES) {
1815                 g_free (shadow);
1816                 return (char *)filename;
1817         }
1818
1819         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1820
1821         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1822          * overwritten when updated in their original locations. */
1823         if (copy_result)
1824                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1825
1826         g_free (dest);
1827         g_free (orig);
1828
1829         if (copy_result == FALSE) {
1830                 g_free (shadow);
1831
1832                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1833                 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1834                         return NULL; /* file not found, shadow copy failed */
1835
1836                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1837                 return NULL;
1838         }
1839
1840         /* attempt to copy .mdb, .config if they exist */
1841         sibling_source = g_strconcat (filename, ".config", NULL);
1842         sibling_source_len = strlen (sibling_source);
1843         sibling_target = g_strconcat (shadow, ".config", NULL);
1844         sibling_target_len = strlen (sibling_target);
1845         
1846         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1847         if (copy_result)
1848                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1849         
1850         g_free (sibling_source);
1851         g_free (sibling_target);
1852         
1853         if (!copy_result)  {
1854                 g_free (shadow);
1855                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1856                 return NULL;
1857         }
1858
1859         /* Create a .ini file containing the original assembly location */
1860         if (!shadow_copy_create_ini (shadow, filename)) {
1861                 g_free (shadow);
1862                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1863                 return NULL;
1864         }
1865
1866         utbuf.actime = src_sbuf.st_atime;
1867         utbuf.modtime = src_sbuf.st_mtime;
1868         utime (shadow, &utbuf);
1869         
1870         return shadow;
1871 }
1872 #endif /* DISABLE_SHADOW_COPY */
1873
1874 MonoDomain *
1875 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1876 {
1877         HANDLE_FUNCTION_ENTER ();
1878         MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1879         MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1880         HANDLE_FUNCTION_RETURN_VAL (result);
1881 }
1882
1883 MonoDomain *
1884 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1885 {
1886         HANDLE_FUNCTION_ENTER ();
1887         MonoDomain *dom = NULL;
1888         if (MONO_HANDLE_IS_NULL (appdomain))
1889                 goto leave;
1890
1891         if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1892                 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1893                 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1894                 
1895                 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1896         } else
1897                 dom = MONO_HANDLE_GETVAL (appdomain, data);
1898
1899 leave:
1900         HANDLE_FUNCTION_RETURN_VAL (dom);
1901 }
1902
1903
1904 static gboolean
1905 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1906                                         const gchar *path3, const gchar *path4,
1907                                         gboolean refonly, gboolean is_private)
1908 {
1909         gchar *fullpath;
1910         gboolean found = FALSE;
1911         
1912         *assembly = NULL;
1913         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1914
1915         if (IS_PORTABILITY_SET) {
1916                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1917                 if (new_fullpath) {
1918                         g_free (fullpath);
1919                         fullpath = new_fullpath;
1920                         found = TRUE;
1921                 }
1922         } else
1923                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1924         
1925         if (found)
1926                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1927
1928         g_free (fullpath);
1929         return (*assembly != NULL);
1930 }
1931
1932 static MonoAssembly *
1933 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1934 {
1935         MonoAssembly *result = NULL;
1936         gchar **path;
1937         gchar *filename;
1938         const gchar *local_culture;
1939         gint len;
1940         gboolean is_private = FALSE;
1941
1942         if (!culture || *culture == '\0') {
1943                 local_culture = "";
1944         } else {
1945                 local_culture = culture;
1946         }
1947
1948         filename =  g_strconcat (name, ".dll", NULL);
1949         len = strlen (filename);
1950
1951         for (path = search_path; *path; path++) {
1952                 if (**path == '\0') {
1953                         is_private = TRUE;
1954                         continue; /* Ignore empty ApplicationBase */
1955                 }
1956
1957                 /* See test cases in bug #58992 and bug #57710 */
1958                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1959                 strcpy (filename + len - 4, ".dll");
1960                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1961                         break;
1962
1963                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1964                 strcpy (filename + len - 4, ".exe");
1965                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1966                         break;
1967
1968                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1969                 strcpy (filename + len - 4, ".dll");
1970                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1971                         break;
1972
1973                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1974                 strcpy (filename + len - 4, ".exe");
1975                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1976                         break;
1977         }
1978
1979         g_free (filename);
1980         return result;
1981 }
1982
1983 /*
1984  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1985  * and then from assemblies_path if any.
1986  * LOCKING: This is called from the assembly loading code, which means the caller
1987  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1988  */
1989 static MonoAssembly *
1990 mono_domain_assembly_preload (MonoAssemblyName *aname,
1991                               gchar **assemblies_path,
1992                               gpointer user_data)
1993 {
1994         MonoDomain *domain = mono_domain_get ();
1995         MonoAssembly *result = NULL;
1996         gboolean refonly = GPOINTER_TO_UINT (user_data);
1997
1998         set_domain_search_path (domain);
1999
2000         if (domain->search_path && domain->search_path [0] != NULL) {
2001                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
2002         }
2003
2004         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2005                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
2006         }
2007
2008         return result;
2009 }
2010
2011 /*
2012  * Check whenever a given assembly was already loaded in the current appdomain.
2013  */
2014 static MonoAssembly *
2015 mono_domain_assembly_search (MonoAssemblyName *aname,
2016                                                          gpointer user_data)
2017 {
2018         MonoDomain *domain = mono_domain_get ();
2019         GSList *tmp;
2020         MonoAssembly *ass;
2021         gboolean refonly = GPOINTER_TO_UINT (user_data);
2022
2023         mono_domain_assemblies_lock (domain);
2024         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2025                 ass = (MonoAssembly *)tmp->data;
2026                 /* Dynamic assemblies can't match here in MS.NET */
2027                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2028                         continue;
2029
2030                 mono_domain_assemblies_unlock (domain);
2031                 return ass;
2032         }
2033         mono_domain_assemblies_unlock (domain);
2034
2035         return NULL;
2036 }
2037
2038 MonoReflectionAssemblyHandle
2039 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2040 {
2041         error_init (error);
2042         MonoDomain *domain = mono_domain_get ();
2043         char *name, *filename;
2044         MonoImageOpenStatus status = MONO_IMAGE_OK;
2045         MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2046
2047         name = NULL;
2048         result = NULL;
2049
2050         if (fname == NULL) {
2051                 mono_error_set_argument_null (error, "assemblyFile", "");
2052                 goto leave;
2053         }
2054                 
2055         name = filename = mono_string_handle_to_utf8 (fname, error);
2056         if (!is_ok (error))
2057                 goto leave;
2058         
2059         MonoAssembly *ass = mono_assembly_open_a_lot (filename, &status, refOnly, TRUE);
2060         
2061         if (!ass) {
2062                 if (status == MONO_IMAGE_IMAGE_INVALID)
2063                         mono_error_set_bad_image_name (error, g_strdup (name), "");
2064                 else
2065                         mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2066                 goto leave;
2067         }
2068
2069         result = mono_assembly_get_object_handle (domain, ass, error);
2070
2071 leave:
2072         g_free (name);
2073         return result;
2074 }
2075
2076 MonoReflectionAssemblyHandle
2077 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, 
2078                                             MonoArrayHandle raw_assembly,
2079                                             MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2080                                             MonoBoolean refonly,
2081                                             MonoError *error)
2082 {
2083         error_init (error);
2084         MonoAssembly *ass;
2085         MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2086         MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2087         MonoImageOpenStatus status;
2088         guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2089
2090         /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2091         char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2092         if (!assembly_data) {
2093                 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2094                 return refass;
2095         }
2096         uint32_t gchandle;
2097         mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2098         memcpy (assembly_data, raw_data, raw_assembly_len);
2099         mono_gchandle_free (gchandle); /* unpin */
2100         MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2101         
2102         MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2103
2104         if (!image) {
2105                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2106                 return refass;
2107         }
2108
2109         if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2110                 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2111                 uint32_t symbol_gchandle;
2112                 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2113                 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2114                 mono_gchandle_free (symbol_gchandle);
2115         }
2116
2117         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2118
2119
2120         if (!ass) {
2121                 mono_image_close (image);
2122                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2123                 return refass; 
2124         }
2125
2126         refass = mono_assembly_get_object_handle (domain, ass, error);
2127         if (!MONO_HANDLE_IS_NULL(refass))
2128                 MONO_HANDLE_SET (refass, evidence, evidence);
2129         return refass;
2130 }
2131
2132 MonoReflectionAssemblyHandle
2133 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2134 {
2135         error_init (error);
2136         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2137         MonoImageOpenStatus status = MONO_IMAGE_OK;
2138         MonoAssembly *ass;
2139         MonoAssemblyName aname;
2140         gchar *name = NULL;
2141         gboolean parsed;
2142
2143         g_assert (assRef);
2144
2145         name = mono_string_handle_to_utf8 (assRef, error);
2146         if (!is_ok (error))
2147                 goto fail;
2148         parsed = mono_assembly_name_parse (name, &aname);
2149         g_free (name);
2150
2151         if (!parsed) {
2152                 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2153                 /* This is a parse error... */
2154                 if (!refOnly) {
2155                         MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2156                         if (!is_ok (error))
2157                                 goto fail;
2158                         if (assm) {
2159                                 refass = mono_assembly_get_object_handle (domain, assm, error);
2160                                 if (!is_ok (error))
2161                                         goto fail;
2162                         }
2163                 }
2164                 return refass;
2165         }
2166
2167         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2168         mono_assembly_name_free (&aname);
2169
2170         if (!ass) {
2171                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2172                 if (!refOnly) {
2173                         ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2174                         if (!is_ok (error))
2175                                 goto fail;
2176                 }
2177                 if (!ass)
2178                         goto fail;
2179         }
2180
2181         g_assert (ass);
2182         MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2183         if (!is_ok (error))
2184                 goto fail;
2185
2186         MONO_HANDLE_SET (refass, evidence, evidence);
2187
2188         return refass;
2189 fail:
2190         return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2191 }
2192
2193 void
2194 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2195 {
2196         error_init (error);
2197         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2198
2199         if (NULL == domain) {
2200                 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2201                 return;
2202         }
2203         
2204         if (domain == mono_get_root_domain ()) {
2205                 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2206                 return;
2207         }
2208
2209         /* 
2210          * Unloading seems to cause problems when running NUnit/NAnt, hence
2211          * this workaround.
2212          */
2213         if (g_getenv ("MONO_NO_UNLOAD"))
2214                 return;
2215 #ifdef __native_client__
2216         return;
2217 #endif
2218
2219         MonoException *exc = NULL;
2220         mono_domain_try_unload (domain, (MonoObject**)&exc);
2221         if (exc)
2222                 mono_error_set_exception_instance (error, exc);
2223 }
2224
2225 gboolean
2226 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2227 {
2228         error_init (error);
2229         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2230
2231         if (!domain)
2232                 return TRUE;
2233
2234         return mono_domain_is_unloading (domain);
2235 }
2236
2237 void
2238 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2239 {
2240         mono_unhandled_exception ((MonoObject*) exc);
2241 }
2242
2243 gint32
2244 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2245                                             MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2246                                             MonoError *error)
2247 {
2248         error_init (error);
2249         MonoImage *image;
2250         MonoMethod *method;
2251
2252         g_assert (!MONO_HANDLE_IS_NULL (refass));
2253         MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2254         image = assembly->image;
2255         g_assert (image);
2256
2257         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2258
2259         if (!method)
2260                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2261
2262         if (MONO_HANDLE_IS_NULL (args)) {
2263                 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2264                 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2265                 mono_error_assert_ok (error);
2266         }
2267
2268         int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2269         return res;
2270 }
2271
2272 gint32 
2273 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2274 {
2275         return ad->data->domain_id;
2276 }
2277
2278 MonoAppDomainHandle
2279 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2280 {
2281         error_init (error);
2282         MonoDomain *old_domain = mono_domain_get ();
2283
2284         if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2285                 mono_error_set_appdomain_unloaded (error);
2286                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2287         }
2288
2289         return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2290 }
2291
2292 MonoAppDomainHandle
2293 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2294 {
2295         MonoDomain *current_domain = mono_domain_get ();
2296         MonoDomain *domain = mono_domain_get_by_id (domainid);
2297
2298         if (!domain || !mono_domain_set (domain, FALSE)) {
2299                 mono_error_set_appdomain_unloaded (error);
2300                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2301         }
2302
2303         return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2304 }
2305
2306 void
2307 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2308 {
2309         error_init (error);
2310         mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2311 }
2312
2313 void
2314 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2315 {
2316         error_init (error);
2317         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2318
2319         if (!domain) {
2320                 /* 
2321                  * Raise an exception to prevent the managed code from executing a pop
2322                  * later.
2323                  */
2324                 mono_error_set_appdomain_unloaded (error);
2325                 return;
2326         }
2327
2328         mono_thread_push_appdomain_ref (domain);
2329 }
2330
2331 void
2332 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2333 {
2334         error_init (error);
2335         mono_thread_pop_appdomain_ref ();
2336 }
2337
2338 MonoAppContext * 
2339 ves_icall_System_AppDomain_InternalGetContext ()
2340 {
2341         return mono_context_get ();
2342 }
2343
2344 MonoAppContext * 
2345 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2346 {
2347         return mono_domain_get ()->default_context;
2348 }
2349
2350 MonoAppContext * 
2351 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2352 {
2353         MonoAppContext *old_context = mono_context_get ();
2354
2355         mono_context_set (mc);
2356
2357         return old_context;
2358 }
2359
2360 MonoStringHandle
2361 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2362 {
2363         error_init (error);
2364         MonoDomain* mono_root_domain = mono_get_root_domain ();
2365         mono_domain_lock (mono_root_domain);
2366         if (process_guid_set) {
2367                 mono_domain_unlock (mono_root_domain);
2368                 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2369         }
2370         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2371         memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2372         mono_gchandle_free (gchandle);
2373         process_guid_set = TRUE;
2374         mono_domain_unlock (mono_root_domain);
2375         return newguid;
2376 }
2377
2378 gboolean
2379 mono_domain_is_unloading (MonoDomain *domain)
2380 {
2381         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2382                 return TRUE;
2383         else
2384                 return FALSE;
2385 }
2386
2387 static void
2388 clear_cached_vtable (MonoVTable *vtable)
2389 {
2390         MonoClass *klass = vtable->klass;
2391         MonoDomain *domain = vtable->domain;
2392         MonoClassRuntimeInfo *runtime_info;
2393         void *data;
2394
2395         runtime_info = klass->runtime_info;
2396         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2397                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2398         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2399                 mono_gc_free_fixed (data);
2400 }
2401
2402 static G_GNUC_UNUSED void
2403 zero_static_data (MonoVTable *vtable)
2404 {
2405         MonoClass *klass = vtable->klass;
2406         void *data;
2407
2408         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2409                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2410 }
2411
2412 typedef struct unload_data {
2413         gboolean done;
2414         MonoDomain *domain;
2415         char *failure_reason;
2416         gint32 refcount;
2417 } unload_data;
2418
2419 static void
2420 unload_data_unref (unload_data *data)
2421 {
2422         gint32 count;
2423         do {
2424                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2425                 g_assert (count >= 1 && count <= 2);
2426                 if (count == 1) {
2427                         g_free (data);
2428                         return;
2429                 }
2430         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2431 }
2432
2433 static void
2434 deregister_reflection_info_roots_from_list (MonoImage *image)
2435 {
2436         GSList *list = image->reflection_info_unregister_classes;
2437
2438         while (list) {
2439                 MonoClass *klass = (MonoClass *)list->data;
2440
2441                 mono_class_free_ref_info (klass);
2442
2443                 list = list->next;
2444         }
2445
2446         image->reflection_info_unregister_classes = NULL;
2447 }
2448
2449 static void
2450 deregister_reflection_info_roots (MonoDomain *domain)
2451 {
2452         GSList *list;
2453
2454         mono_domain_assemblies_lock (domain);
2455         for (list = domain->domain_assemblies; list; list = list->next) {
2456                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2457                 MonoImage *image = assembly->image;
2458                 int i;
2459
2460                 /*
2461                  * No need to take the image lock here since dynamic images are appdomain bound and
2462                  * at this point the mutator is gone.  Taking the image lock here would mean
2463                  * promoting it from a simple lock to a complex lock, which we better avoid if
2464                  * possible.
2465                  */
2466                 if (image_is_dynamic (image))
2467                         deregister_reflection_info_roots_from_list (image);
2468
2469                 for (i = 0; i < image->module_count; ++i) {
2470                         MonoImage *module = image->modules [i];
2471                         if (module && image_is_dynamic (module))
2472                                 deregister_reflection_info_roots_from_list (module);
2473                 }
2474         }
2475         mono_domain_assemblies_unlock (domain);
2476 }
2477
2478 static gsize WINAPI
2479 unload_thread_main (void *arg)
2480 {
2481         MonoError error;
2482         unload_data *data = (unload_data*)arg;
2483         MonoDomain *domain = data->domain;
2484         MonoInternalThread *internal;
2485         int i;
2486
2487         internal = mono_thread_internal_current ();
2488
2489         mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "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         domain->state = MONO_APPDOMAIN_UNLOADED;
2547
2548         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2549
2550         /* remove from the handle table the items related to this domain */
2551         mono_gchandle_free_domain (domain);
2552
2553         mono_domain_free (domain, FALSE);
2554
2555         mono_gc_collect (mono_gc_max_generation ());
2556
2557         mono_atomic_store_release (&data->done, TRUE);
2558         unload_data_unref (data);
2559         return 0;
2560
2561 failure:
2562         mono_atomic_store_release (&data->done, TRUE);
2563         unload_data_unref (data);
2564         return 1;
2565 }
2566
2567 /*
2568  * mono_domain_unload:
2569  * @domain: The domain to unload
2570  *
2571  *  Unloads an appdomain. Follows the process outlined in the comment
2572  *  for mono_domain_try_unload.
2573  */
2574 void
2575 mono_domain_unload (MonoDomain *domain)
2576 {
2577         MonoObject *exc = NULL;
2578         mono_domain_try_unload (domain, &exc);
2579 }
2580
2581 static MonoThreadInfoWaitRet
2582 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2583 {
2584         MonoThreadInfoWaitRet result;
2585
2586         MONO_ENTER_GC_SAFE;
2587         result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2588         MONO_EXIT_GC_SAFE;
2589
2590         return result;
2591 }
2592
2593 /*
2594  * mono_domain_unload:
2595  * @domain: The domain to unload
2596  * @exc: Exception information
2597  *
2598  *  Unloads an appdomain. Follows the process outlined in:
2599  *  http://blogs.gotdotnet.com/cbrumme
2600  *
2601  *  If doing things the 'right' way is too hard or complex, we do it the 
2602  *  'simple' way, which means do everything needed to avoid crashes and
2603  *  memory leaks, but not much else.
2604  *
2605  *  It is required to pass a valid reference to the exc argument, upon return
2606  *  from this function *exc will be set to the exception thrown, if any.
2607  *
2608  *  If this method is not called from an icall (embedded scenario for instance),
2609  *  it must not be called with any managed frames on the stack, since the unload
2610  *  process could end up trying to abort the current thread.
2611  */
2612 void
2613 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2614 {
2615         MonoError error;
2616         MonoThreadHandle *thread_handle;
2617         MonoAppDomainState prev_state;
2618         MonoMethod *method;
2619         unload_data *thread_data;
2620         MonoInternalThread *internal;
2621         MonoDomain *caller_domain = mono_domain_get ();
2622
2623         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2624
2625         /* Atomically change our state to UNLOADING */
2626         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2627                 MONO_APPDOMAIN_UNLOADING_START,
2628                 MONO_APPDOMAIN_CREATED);
2629         if (prev_state != MONO_APPDOMAIN_CREATED) {
2630                 switch (prev_state) {
2631                 case MONO_APPDOMAIN_UNLOADING_START:
2632                 case MONO_APPDOMAIN_UNLOADING:
2633                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2634                         return;
2635                 case MONO_APPDOMAIN_UNLOADED:
2636                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2637                         return;
2638                 default:
2639                         g_warning ("Invalid appdomain state %d", prev_state);
2640                         g_assert_not_reached ();
2641                 }
2642         }
2643
2644         mono_domain_set (domain, FALSE);
2645         /* Notify OnDomainUnload listeners */
2646         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2647         g_assert (method);
2648
2649         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2650
2651         if (!mono_error_ok (&error)) {
2652                 if (*exc)
2653                         mono_error_cleanup (&error);
2654                 else
2655                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2656         }
2657
2658         if (*exc) {
2659                 /* Roll back the state change */
2660                 domain->state = MONO_APPDOMAIN_CREATED;
2661                 mono_domain_set (caller_domain, FALSE);
2662                 return;
2663         }
2664         mono_domain_set (caller_domain, FALSE);
2665
2666         thread_data = g_new0 (unload_data, 1);
2667         thread_data->domain = domain;
2668         thread_data->failure_reason = NULL;
2669         thread_data->done = FALSE;
2670         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2671
2672         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2673         domain->state = MONO_APPDOMAIN_UNLOADING;
2674         /* 
2675          * First we create a separate thread for unloading, since
2676          * we might have to abort some threads, including the current one.
2677          *
2678          * Have to attach to the runtime so shutdown can wait for this thread.
2679          *
2680          * Force it to be attached to avoid racing during shutdown.
2681          */
2682         internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2683         mono_error_assert_ok (&error);
2684
2685         thread_handle = mono_threads_open_thread_handle (internal->handle);
2686
2687         /* Wait for the thread */       
2688         while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2689                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2690                         /* The unload thread tries to abort us */
2691                         /* The icall wrapper will execute the abort */
2692                         mono_threads_close_thread_handle (thread_handle);
2693                         unload_data_unref (thread_data);
2694                         return;
2695                 }
2696         }
2697
2698         mono_threads_close_thread_handle (thread_handle);
2699
2700         if (thread_data->failure_reason) {
2701                 /* Roll back the state change */
2702                 domain->state = MONO_APPDOMAIN_CREATED;
2703
2704                 g_warning ("%s", thread_data->failure_reason);
2705
2706                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2707
2708                 g_free (thread_data->failure_reason);
2709                 thread_data->failure_reason = NULL;
2710         }
2711
2712         unload_data_unref (thread_data);
2713 }