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