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