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