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