2003-02-21 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Author:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <string.h>
14
15 #include <mono/os/gc_wrapper.h>
16
17 #include <mono/metadata/object.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/assembly.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/socket-io.h>
23 #include <mono/metadata/tabledefs.h>
24 #include <mono/metadata/gc-internal.h>
25
26 HANDLE mono_delegate_semaphore = NULL;
27 CRITICAL_SECTION mono_delegate_section;
28
29 static MonoAssembly *
30 mono_domain_assembly_preload (MonoAssemblyName *aname,
31                               gchar **assemblies_path,
32                               gpointer user_data);
33
34 static void
35 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
36
37 static MonoMethod *
38 look_for_method_by_name (MonoClass *klass, const gchar *name);
39
40 /*
41  * mono_runtime_init:
42  * @domain: domain returned by mono_init ()
43  *
44  * Initialize the core AppDomain: this function will run also some
45  * IL initialization code, so it needs the execution engine to be fully 
46  * operational.
47  *
48  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
49  * we know the entry_assembly.
50  *
51  */
52 void
53 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
54                    MonoThreadAttachCB attach_cb)
55 {
56         MonoAppDomainSetup *setup;
57         MonoAppDomain *ad;
58         MonoClass *class;
59         
60         mono_install_assembly_preload_hook (mono_domain_assembly_preload, NULL);
61         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
62         mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
63
64         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
65         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
66
67         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
68         ad = (MonoAppDomain *) mono_object_new (domain, class);
69         ad->data = domain;
70         domain->domain = ad;
71         domain->setup = setup;
72
73         mono_delegate_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
74         g_assert (mono_delegate_semaphore != INVALID_HANDLE_VALUE);
75         InitializeCriticalSection (&mono_delegate_section);
76
77         mono_thread_init (start_cb, attach_cb);
78         
79         /* GC init has to happen after thread init */
80         mono_gc_init ();
81
82         mono_network_init ();
83
84         return;
85 }
86
87 /* This must not be called while there are still running threads executing
88  * managed code.
89  */
90 void
91 mono_runtime_cleanup (MonoDomain *domain)
92 {
93         /* Not really needed, but do it anyway */
94         mono_gc_cleanup ();
95         
96         mono_network_cleanup ();
97 }
98
99 gboolean
100 mono_domain_has_type_resolve (MonoDomain *domain)
101 {
102         static MonoClassField *field = NULL;
103         MonoObject *o;
104
105         if (field == NULL) {
106                 MonoClass *klass = mono_defaults.appdomain_class;
107                 int i;
108
109                 for (i = 0; i < klass->field.count; ++i)
110                         if (strcmp (klass->fields [i].name, "TypeResolve") == 0)
111                                 field = &klass->fields [i];
112                 g_assert (field);
113         }
114
115         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
116         return o != NULL;
117 }
118
119 MonoReflectionAssembly *
120 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
121 {
122         MonoClass *klass;
123         void *params [1];
124         static MonoMethod *method = NULL;
125
126         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
127
128         if (method == NULL) {
129                 klass = domain->domain->mbr.obj.vtable->klass;
130                 g_assert (klass);
131
132                 method = look_for_method_by_name (klass, "DoTypeResolve");
133                 if (method == NULL) {
134                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
135                         return NULL;
136                 }
137         }
138
139         if (name)
140                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
141         else
142                 *params = tb;
143         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
144 }
145
146 void
147 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
148 {
149         MonoDomain* domain = mono_domain_get ();
150         MonoAssembly *assembly;
151         gchar *str;
152         gchar *config_suffix;
153         
154         MONO_ARCH_SAVE_REGS;
155
156         assembly = domain->entry_assembly;
157         g_assert (assembly);
158
159         setup->application_base = mono_string_new (domain, assembly->basedir);
160
161         config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
162         str = g_build_filename (assembly->basedir, config_suffix, NULL);
163         g_free (config_suffix);
164         setup->configuration_file = mono_string_new (domain, str);
165         g_free (str);
166 }
167
168 MonoObject *
169 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
170 {
171         MonoDomain *add = ad->data;
172         MonoObject *o;
173         char *str;
174
175         MONO_ARCH_SAVE_REGS;
176
177         g_assert (ad != NULL);
178         g_assert (name != NULL);
179
180         str = mono_string_to_utf8 (name);
181
182         mono_domain_lock (add);
183
184         if (!strcmp (str, "APPBASE"))
185                 o = (MonoObject *)add->setup->application_base;
186         else if (!strcmp (str, "APP_CONFIG_FILE"))
187                 o = (MonoObject *)add->setup->configuration_file;
188         else if (!strcmp (str, "DYNAMIC_BASE"))
189                 o = (MonoObject *)add->setup->dynamic_base;
190         else if (!strcmp (str, "APP_NAME"))
191                 o = (MonoObject *)add->setup->application_name;
192         else if (!strcmp (str, "CACHE_BASE"))
193                 o = (MonoObject *)add->setup->cache_path;
194         else if (!strcmp (str, "PRIVATE_BINPATH"))
195                 o = (MonoObject *)add->setup->private_bin_path;
196         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
197                 o = (MonoObject *)add->setup->private_bin_path_probe;
198         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
199                 o = (MonoObject *)add->setup->shadow_copy_directories;
200         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
201                 o = (MonoObject *)add->setup->shadow_copy_files;
202         else 
203                 o = mono_g_hash_table_lookup (add->env, name);
204
205         mono_domain_unlock (add);
206         g_free (str);
207
208         if (!o)
209                 return NULL;
210
211         return o;
212 }
213
214 void
215 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
216 {
217         MonoDomain *add = ad->data;
218
219         MONO_ARCH_SAVE_REGS;
220
221         g_assert (ad != NULL);
222         g_assert (name != NULL);
223
224         mono_domain_lock (add);
225
226         mono_g_hash_table_insert (add->env, name, data);
227
228         mono_domain_unlock (add);
229 }
230
231 MonoAppDomainSetup *
232 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
233 {
234         MONO_ARCH_SAVE_REGS;
235
236         g_assert (ad != NULL);
237         g_assert (ad->data != NULL);
238
239         return ad->data->setup;
240 }
241
242 MonoString *
243 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
244 {
245         MONO_ARCH_SAVE_REGS;
246
247         g_assert (ad != NULL);
248         g_assert (ad->data != NULL);
249
250         return mono_string_new (ad->data, ad->data->friendly_name);
251 }
252
253 MonoAppDomain *
254 ves_icall_System_AppDomain_getCurDomain ()
255 {
256         MonoDomain *add = mono_domain_get ();
257
258         MONO_ARCH_SAVE_REGS;
259
260         return add->domain;
261 }
262
263 MonoAppDomain *
264 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
265 {
266         /*MonoDomain *domain = mono_domain_get (); */
267         MonoClass *adclass;
268         MonoAppDomain *ad;
269         MonoDomain *data;
270         
271         MONO_ARCH_SAVE_REGS;
272
273         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
274
275         /* FIXME: pin all those objects */
276         data = mono_domain_create();
277
278         ad = (MonoAppDomain *) mono_object_new (data, adclass);
279         ad->data = data;
280         data->domain = ad;
281         data->setup = setup;
282         data->friendly_name = mono_string_to_utf8 (friendly_name);
283
284         /* FIXME: what to do next ? */
285
286         return ad;
287 }
288
289 typedef struct {
290         MonoArray *res;
291         MonoDomain *domain;
292         int idx;
293 } add_assembly_helper_t;
294
295 static void
296 add_assembly (gpointer key, gpointer value, gpointer user_data)
297 {
298         add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
299
300         mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
301 }
302
303 MonoArray *
304 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
305 {
306         MonoDomain *domain = ad->data; 
307         static MonoClass *System_Reflection_Assembly;
308         MonoArray *res;
309         add_assembly_helper_t ah;
310         
311         MONO_ARCH_SAVE_REGS;
312
313         if (!System_Reflection_Assembly)
314                 System_Reflection_Assembly = mono_class_from_name (
315                         mono_defaults.corlib, "System.Reflection", "Assembly");
316
317         res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
318
319         ah.domain = domain;
320         ah.res = res;
321         ah.idx = 0;
322         mono_domain_lock (domain);
323         g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
324         mono_domain_unlock (domain);
325
326         return res;
327 }
328
329 /*
330  * Used to find methods in AppDomain class.
331  * It only works if there are no multiple signatures for any given method name
332  */
333 static MonoMethod *
334 look_for_method_by_name (MonoClass *klass, const gchar *name)
335 {
336         gint i;
337         MonoMethod *method;
338
339         for (i = 0; i < klass->method.count; i++) {
340                 method = klass->methods [i];
341                 if (!strcmp (method->name, name))
342                         return method;
343         }
344
345         return NULL;
346 }
347
348 static MonoReflectionAssembly *
349 try_assembly_resolve (MonoDomain *domain, MonoString *fname)
350 {
351         MonoClass *klass;
352         MonoMethod *method;
353         void *params [1];
354
355         g_assert (domain != NULL && fname != NULL);
356
357         klass = domain->domain->mbr.obj.vtable->klass;
358         g_assert (klass);
359         
360         method = look_for_method_by_name (klass, "DoAssemblyResolve");
361         if (method == NULL) {
362                 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
363                 return NULL;
364         }
365
366         *params = fname;
367         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
368 }
369
370 static void
371 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass)
372 {
373         gint i;
374
375         if (g_hash_table_lookup (domain->assemblies, ass->aname.name))
376                 return; /* This is ok while no lazy loading of assemblies */
377
378         mono_domain_lock (domain);
379         g_hash_table_insert (domain->assemblies, (gpointer) ass->aname.name, ass);
380         mono_domain_unlock (domain);
381
382         for (i = 0; ass->image->references [i] != NULL; i++)
383                 add_assemblies_to_domain (domain, ass->image->references [i]);
384 }
385
386 static void
387 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
388 {
389         MonoDomain *domain = mono_domain_get ();
390         MonoReflectionAssembly *ref_assembly;
391         MonoClass *klass;
392         MonoMethod *method;
393         void *params [1];
394
395         klass = domain->domain->mbr.obj.vtable->klass;
396
397         
398         method = look_for_method_by_name (klass, "DoAssemblyLoad");
399         if (method == NULL) {
400                 g_warning ("Method AppDomain.DoAssemblyLoad not found.\n");
401                 return;
402         }
403
404         add_assemblies_to_domain (domain, assembly);
405
406         ref_assembly = mono_assembly_get_object (domain, assembly);
407         g_assert (ref_assembly);
408
409         *params = ref_assembly;
410         mono_runtime_invoke (method, domain->domain, params, NULL);
411 }
412
413 static void
414 set_domain_search_path (MonoDomain *domain)
415 {
416         MonoAppDomainSetup *setup;
417         gchar **tmp;
418         gchar *utf8;
419         gint i;
420         gint npaths = 0;
421         gchar **pvt_split = NULL;
422
423         if (domain->search_path != NULL)
424                 return;
425
426         setup = domain->setup;
427         if (setup->application_base)
428                 npaths++;
429
430         if (setup->private_bin_path) {
431                 utf8 = mono_string_to_utf8 (setup->private_bin_path);
432                 pvt_split = g_strsplit (utf8, G_SEARCHPATH_SEPARATOR_S, 1000);
433                 g_free (utf8);
434                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
435         }
436
437         if (!npaths) {
438                 if (pvt_split)
439                         g_strfreev (pvt_split);
440                 /*
441                  * Don't do this because the first time is called, the domain
442                  * setup is not finished.
443                  *
444                  * domain->search_path = g_malloc (sizeof (char *));
445                  * domain->search_path [0] = NULL;
446                 */
447                 return;
448         }
449
450         domain->search_path = tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
451         tmp [npaths] = NULL;
452         if (setup->application_base) {
453                 *tmp = mono_string_to_utf8 (setup->application_base);
454                 /* FIXME: is this needed? */
455                 if (strncmp (*tmp, "file://", 7) == 0) {
456                         gchar *file = *tmp;
457                         *tmp = g_strdup (*tmp + 7);
458                         g_free (file);
459                 }
460                 
461         } else {
462                 *tmp = g_strdup ("");
463         }
464
465         for (i = 1; pvt_split && i < npaths; i++) {
466                 if (*tmp [0] == '\0' || g_path_is_absolute (pvt_split [i - 1])) {
467                         tmp [i] = g_strdup (pvt_split [i - 1]);
468                         continue;
469                 }
470
471                 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
472         }
473         
474         if (setup->private_bin_path_probe != NULL && setup->application_base) {
475                 g_free (tmp [0]);
476                 tmp [0] = g_strdup ("");
477         }
478                 
479
480         g_strfreev (pvt_split);
481 }
482
483 static MonoAssembly *
484 real_load (gchar **search_path, gchar *filename)
485 {
486         MonoAssembly *result;
487         gchar **path;
488         gchar *fullpath;
489
490         for (path = search_path; *path; path++) {
491                 if (**path == '\0')
492                         continue; /* Ignore empty ApplicationBase */
493                 fullpath = g_build_filename (*path, filename, NULL);
494                 result = mono_assembly_open (fullpath, NULL);
495                 g_free (fullpath);
496                 if (result)
497                         return result;
498         }
499
500         return NULL;
501 }
502
503 /*
504  * Try loading the assembly from ApplicationBase and PrivateBinPath 
505  * and then from assemblies_path if any.
506  */
507 static MonoAssembly *
508 mono_domain_assembly_preload (MonoAssemblyName *aname,
509                               gchar **assemblies_path,
510                               gpointer user_data)
511 {
512         MonoDomain *domain = mono_domain_get ();
513         MonoAssembly *result;
514         gchar *dll, *exe;
515
516         set_domain_search_path (domain);
517
518         dll = g_strconcat (aname->name, ".dll", NULL);
519         exe = g_strdup (dll);
520         strcpy (exe + strlen (exe) - 4, ".exe");
521
522         if (domain->search_path && domain->search_path [0] != NULL) {
523                 /* TODO: should also search in name/name.dll and name/name.exe from appbase */
524                 result = real_load (domain->search_path, dll);
525                 if (result) {
526                         g_free (dll);
527                         g_free (exe);
528                         return result;
529                 }
530
531                 result = real_load (domain->search_path, exe);
532                 if (result) {
533                         g_free (dll);
534                         g_free (exe);
535                         return result;
536                 }
537         }
538
539         if (assemblies_path && assemblies_path [0] != NULL) {
540                 result = real_load (assemblies_path, dll);
541                 if (result) {
542                         g_free (dll);
543                         g_free (exe);
544                         return result;
545                 }
546
547                 result = real_load (assemblies_path, exe);
548                 if (result) {
549                         g_free (dll);
550                         g_free (exe);
551                         return result;
552                 }
553         }
554         
555         g_free (dll);
556         g_free (exe);
557         return NULL;
558 }
559
560 MonoReflectionAssembly *
561 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
562 {
563         MonoDomain *domain = mono_domain_get ();
564         char *name, *filename;
565         MonoImageOpenStatus status = MONO_IMAGE_OK;
566         MonoAssembly *ass;
567
568         MONO_ARCH_SAVE_REGS;
569
570         if (fname == NULL) {
571                 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
572                 mono_raise_exception (exc);
573         }
574                 
575         name = filename = mono_string_to_utf8 (fname);
576
577         /* FIXME: move uri handling to mono_assembly_open */
578         if (strncmp (filename, "file://", 7) == 0)
579                 filename += 7;
580
581         ass = mono_assembly_open (filename, &status);
582         
583         g_free (name);
584
585         if (!ass){
586                 MonoException *exc = mono_get_exception_file_not_found (fname);
587                 mono_raise_exception (exc);
588         }
589
590         return mono_assembly_get_object (domain, ass);
591 }
592
593 static void
594 free_assembly_name (MonoAssemblyName *aname)
595 {
596         if (aname == NULL)
597                 return;
598
599         g_free ((void *) aname->name);
600         g_free ((void *) aname->culture);
601         g_free ((void *) aname->hash_value);
602 }
603
604 static gboolean
605 get_info_from_assembly_name (MonoReflectionAssemblyName *assRef, MonoAssemblyName *aname)
606 {
607         gchar *name;
608         gchar *value;
609         gchar **parts;
610         gchar **tmp;
611         gint major, minor, build, revision;
612
613         memset (aname, 0, sizeof (MonoAssemblyName));
614
615         name = mono_string_to_utf8 (assRef->name);
616         parts = tmp = g_strsplit (name, ",", 4);
617         g_free (name);
618         if (!tmp || !*tmp) {
619                 g_strfreev (tmp);
620                 return FALSE;
621         }
622
623         value = g_strstrip (*tmp);
624         /* g_print ("Assembly name: %s\n", value); */
625         aname->name = g_strdup (value);
626         tmp++;
627         if (!*tmp) {
628                 g_strfreev (parts);
629                 return TRUE;
630         }
631
632         value = g_strstrip (*tmp);
633         if (strncmp (value, "Version=", 8)) {
634                 g_strfreev (parts);
635                 return FALSE;
636         }
637         
638         if (sscanf (value + 8, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4) {
639                 g_strfreev (parts);
640                 return FALSE;
641         }
642
643         /* g_print ("Version: %u.%u.%u.%u\n", major, minor, build, revision); */
644         aname->major = major;
645         aname->minor = minor;
646         aname->build = build;
647         aname->revision = revision;
648         tmp++;
649
650         if (!*tmp) {
651                 g_strfreev (parts);
652                 return FALSE;
653         }
654
655         value = g_strstrip (*tmp);
656         if (strncmp (value, "Culture=", 8)) {
657                 g_strfreev (parts);
658                 return FALSE;
659         }
660
661         /* g_print ("Culture: %s\n", aname->culture); */
662         aname->culture = g_strstrip (g_strdup (value + 8));
663         tmp++;
664
665         if (!*tmp) {
666                 g_strfreev (parts);
667                 return FALSE;
668         }
669
670         value = g_strstrip (*tmp);
671         if (strncmp (value, "PublicKeyToken=", 15)) {
672                 g_strfreev (parts);
673                 return FALSE;
674         }
675
676         value += 15;
677         if (*value && strcmp (value, "null")) {
678                 gint i, len;
679                 gchar h, l;
680                 gchar *result;
681                 
682                 value = g_strstrip (g_strdup (value));
683                 len = strlen (value);
684                 if (len % 2) {
685                         g_strfreev (parts);
686                         return FALSE;
687                 }
688                 
689                 aname->hash_len = len / 2;
690                 aname->hash_value = g_malloc0 (aname->hash_len);
691                 result = (gchar *) aname->hash_value;
692                 
693                 for (i = 0; i < len; i++) {
694                         if (i % 2) {
695                                 l = g_ascii_xdigit_value (value [i]);
696                                 if (l == -1) {
697                                         g_strfreev (parts);
698                                         return FALSE;
699                                 }
700                                 result [i / 2] = (h * 16) + l;
701                         } else {
702                                 h = g_ascii_xdigit_value (value [i]);
703                                 if (h == -1) {
704                                         g_strfreev (parts);
705                                         return FALSE;
706                                 }
707                         }
708                 }
709
710                 /*
711                 g_print ("PublicKeyToken: ");
712                 for (i = 0; i < aname->hash_len; i++) {
713                         g_print ("%x", 0x00FF & aname->hash_value [i]); 
714                 }
715                 g_print ("\n");
716                 */
717         }
718
719         g_strfreev (parts);
720         return TRUE;
721 }
722
723 MonoReflectionAssembly *
724 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoReflectionAssemblyName *assRef, MonoObject *evidence)
725 {
726         MonoDomain *domain = ad->data; 
727         MonoImageOpenStatus status = MONO_IMAGE_OK;
728         MonoAssembly *ass;
729         MonoAssemblyName aname;
730         MonoReflectionAssembly *refass = NULL;
731
732         MONO_ARCH_SAVE_REGS;
733
734         memset (&aname, 0, sizeof (aname));
735
736         /* FIXME : examine evidence? */
737
738         g_assert (assRef != NULL);
739         g_assert (assRef->name != NULL);
740
741         if (!get_info_from_assembly_name (assRef, &aname)) {
742                 MonoException *exc;
743
744                 free_assembly_name (&aname);
745                 /* This is a parse error... */
746                 exc = mono_get_exception_file_not_found (assRef->name);
747                 mono_raise_exception (exc);
748         }
749
750         ass = mono_assembly_load (&aname, NULL, &status);
751         free_assembly_name (&aname);
752
753         if (!ass && (refass = try_assembly_resolve (domain, assRef->name)) == NULL){
754                 /* FIXME: it doesn't make much sense since we really don't have a filename ... */
755                 MonoException *exc = mono_get_exception_file_not_found (assRef->name);
756                 mono_raise_exception (exc);
757         }
758
759         if (refass != NULL)
760                 return refass;
761
762         return mono_assembly_get_object (domain, ass);
763 }
764
765 void
766 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
767 {
768         MonoDomain * domain = mono_domain_get_by_id (domain_id);
769
770         MONO_ARCH_SAVE_REGS;
771
772         if (NULL == domain) {
773                 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
774                 mono_raise_exception (exc);
775         }
776         
777
778         mono_domain_unload (domain, FALSE);
779 }
780
781 gint32
782 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, 
783                                             MonoObject *evidence, MonoArray *args)
784 {
785         MonoAssembly *assembly;
786         MonoImage *image;
787         MonoMethod *method;
788         char *filename;
789         gint32 res;
790
791         MONO_ARCH_SAVE_REGS;
792
793         filename = mono_string_to_utf8 (file);
794         assembly = mono_assembly_open (filename, NULL);
795         g_free (filename);
796
797         if (!assembly) {
798                 mono_raise_exception ((MonoException *)mono_exception_from_name (
799                         mono_defaults.corlib, "System.IO", "FileNotFoundException"));
800         }
801
802         image = assembly->image;
803
804         method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
805
806         if (!method)
807                 g_error ("No entry point method found in %s", image->name);
808
809         if (!args)
810                 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
811
812         res = mono_runtime_exec_main (method, (MonoArray *)args, NULL);
813
814         return res;
815 }
816
817 gint32 
818 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
819 {
820         MONO_ARCH_SAVE_REGS;
821
822         return ad->data->domain_id;
823 }
824
825 MonoAppDomain * 
826 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
827 {
828         MonoDomain *old_domain = mono_domain_get();
829
830         MONO_ARCH_SAVE_REGS;
831
832         mono_domain_set(ad->data);
833
834         return old_domain->domain;
835 }
836
837 MonoAppDomain * 
838 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
839 {
840         MonoDomain *current_domain = mono_domain_get ();
841         MonoDomain *domain = mono_domain_get_by_id (domainid);
842
843         MONO_ARCH_SAVE_REGS;
844
845         mono_domain_set (domain);
846         
847         return current_domain->domain;
848 }
849
850 MonoAppContext * 
851 ves_icall_System_AppDomain_InternalGetContext ()
852 {
853         MONO_ARCH_SAVE_REGS;
854
855         return mono_context_get ();
856 }
857
858 MonoAppContext * 
859 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
860 {
861         MonoAppContext *old_context = mono_context_get ();
862         MonoDomain *context_domain = mono_domain_get_by_id (mc->domain_id);
863
864         MONO_ARCH_SAVE_REGS;
865
866         mono_context_set (mc);
867         mono_domain_set (context_domain);
868         
869         return old_context;
870 }