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