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