Mon Mar 11 11:12:23 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Author:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <string.h>
13
14 #if HAVE_BOEHM_GC
15 #include <gc/gc.h>
16 #endif
17
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/cil-coff.h>
23
24 static guint32 appdomain_thread_id = 0;
25
26 static int
27 ldstr_hash (const char* str)
28 {
29         guint len, h;
30         const char *end;
31         len = mono_metadata_decode_blob_size (str, &str);
32         end = str + len;
33         h = *str;
34         /*
35          * FIXME: The distribution may not be so nice with lots of
36          * null chars in the string.
37          */
38         for (str += 1; str < end; str++)
39                 h = (h << 5) - h + *str;
40         return h;
41 }
42
43 static gboolean
44 ldstr_equal (const char *str1, const char *str2) {
45         int len, len2;
46         len = mono_metadata_decode_blob_size (str1, NULL);
47         len2 = mono_metadata_decode_blob_size (str2, NULL);
48         if (len != len2)
49                 return 0;
50         return memcmp (str1, str2, len) == 0;
51 }
52
53 static MonoDomain *
54 mono_create_domain ()
55 {
56         MonoDomain *domain;
57
58 #if HAVE_BOEHM_GC
59         domain = GC_malloc (sizeof (MonoDomain));
60 #else
61         domain = g_new0 (MonoDomain, 1);
62 #endif
63         domain->domain = NULL;
64         domain->setup = NULL;
65         domain->friendly_name = NULL;
66
67         domain->mp = mono_mempool_new ();
68         domain->env = g_hash_table_new (g_str_hash, g_str_equal);
69         domain->assemblies = g_hash_table_new (g_str_hash, g_str_equal);
70         domain->class_vtable_hash = g_hash_table_new (NULL, NULL);
71         domain->jit_code_hash = g_hash_table_new (NULL, NULL);
72         domain->ldstr_table = g_hash_table_new ((GHashFunc)ldstr_hash, (GCompareFunc)ldstr_equal);
73
74         return domain;
75 }
76
77 MonoDomain *mono_root_domain = NULL;
78
79 /**
80  * mono_init:
81  * 
82  * Creates the initial application domain and initializes the mono_defaults
83  * structure.
84  *
85  * Returns: the initial domain.
86  */
87 MonoDomain *
88 mono_init (const char *filename)
89 {
90         static MonoDomain *domain = NULL;
91         MonoAppDomainSetup *setup;
92         MonoAppDomain *ad;
93         MonoAssembly *ass;
94         MonoClass *class;
95         MonoString *name;
96         enum MonoImageOpenStatus status = MONO_IMAGE_OK;
97
98         if (domain)
99                 g_assert_not_reached ();
100
101         appdomain_thread_id = TlsAlloc ();
102
103         domain = mono_create_domain ();
104         mono_root_domain = domain;
105
106         TlsSetValue (appdomain_thread_id, domain);
107
108         /* find the corlib */
109         ass = mono_assembly_open (CORLIB_NAME, NULL, &status);
110         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
111                 switch (status){
112                 case MONO_IMAGE_ERROR_ERRNO:
113                         g_print ("The assembly corlib.dll was not found or could not be loaded.\n");
114                         g_print ("It should have been installed in the `%s' directory.\n", MONO_ASSEMBLIES);
115                         break;
116
117                 case MONO_IMAGE_IMAGE_INVALID:
118                         g_print ("The file %s/corlib.dll is an invalid CIL image", MONO_ASSEMBLIES);
119                         break;
120                 }
121                 
122                 exit (1);
123         }
124         mono_defaults.corlib = ass->image;
125
126         mono_defaults.object_class = mono_class_from_name (
127                 mono_defaults.corlib, "System", "Object");
128         g_assert (mono_defaults.object_class != 0);
129
130         mono_defaults.void_class = mono_class_from_name (
131                 mono_defaults.corlib, "System", "Void");
132         g_assert (mono_defaults.void_class != 0);
133
134         mono_defaults.boolean_class = mono_class_from_name (
135                 mono_defaults.corlib, "System", "Boolean");
136         g_assert (mono_defaults.boolean_class != 0);
137
138         mono_defaults.byte_class = mono_class_from_name (
139                 mono_defaults.corlib, "System", "Byte");
140         g_assert (mono_defaults.byte_class != 0);
141
142         mono_defaults.sbyte_class = mono_class_from_name (
143                 mono_defaults.corlib, "System", "SByte");
144         g_assert (mono_defaults.sbyte_class != 0);
145
146         mono_defaults.int16_class = mono_class_from_name (
147                 mono_defaults.corlib, "System", "Int16");
148         g_assert (mono_defaults.int16_class != 0);
149
150         mono_defaults.uint16_class = mono_class_from_name (
151                 mono_defaults.corlib, "System", "UInt16");
152         g_assert (mono_defaults.uint16_class != 0);
153
154         mono_defaults.int32_class = mono_class_from_name (
155                 mono_defaults.corlib, "System", "Int32");
156         g_assert (mono_defaults.int32_class != 0);
157
158         mono_defaults.uint32_class = mono_class_from_name (
159                 mono_defaults.corlib, "System", "UInt32");
160         g_assert (mono_defaults.uint32_class != 0);
161
162         mono_defaults.uint_class = mono_class_from_name (
163                 mono_defaults.corlib, "System", "UIntPtr");
164         g_assert (mono_defaults.uint_class != 0);
165
166         mono_defaults.int_class = mono_class_from_name (
167                 mono_defaults.corlib, "System", "IntPtr");
168         g_assert (mono_defaults.int_class != 0);
169
170         mono_defaults.int64_class = mono_class_from_name (
171                 mono_defaults.corlib, "System", "Int64");
172         g_assert (mono_defaults.int64_class != 0);
173
174         mono_defaults.uint64_class = mono_class_from_name (
175                 mono_defaults.corlib, "System", "UInt64");
176         g_assert (mono_defaults.uint64_class != 0);
177
178         mono_defaults.single_class = mono_class_from_name (
179                 mono_defaults.corlib, "System", "Single");
180         g_assert (mono_defaults.single_class != 0);
181
182         mono_defaults.double_class = mono_class_from_name (
183                 mono_defaults.corlib, "System", "Double");
184         g_assert (mono_defaults.double_class != 0);
185
186         mono_defaults.char_class = mono_class_from_name (
187                 mono_defaults.corlib, "System", "Char");
188         g_assert (mono_defaults.char_class != 0);
189
190         mono_defaults.string_class = mono_class_from_name (
191                 mono_defaults.corlib, "System", "String");
192         g_assert (mono_defaults.string_class != 0);
193
194         mono_defaults.enum_class = mono_class_from_name (
195                 mono_defaults.corlib, "System", "Enum");
196         g_assert (mono_defaults.enum_class != 0);
197
198         mono_defaults.array_class = mono_class_from_name (
199                 mono_defaults.corlib, "System", "Array");
200         g_assert (mono_defaults.array_class != 0);
201
202         mono_defaults.delegate_class = mono_class_from_name (
203                 mono_defaults.corlib, "System", "Delegate");
204         g_assert (mono_defaults.delegate_class != 0);
205
206         mono_defaults.typehandle_class = mono_class_from_name (
207                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
208         g_assert (mono_defaults.typehandle_class != 0);
209
210         mono_defaults.methodhandle_class = mono_class_from_name (
211                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
212         g_assert (mono_defaults.methodhandle_class != 0);
213
214         mono_defaults.fieldhandle_class = mono_class_from_name (
215                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
216         g_assert (mono_defaults.fieldhandle_class != 0);
217
218         mono_defaults.monotype_class = mono_class_from_name (
219                 mono_defaults.corlib, "System", "MonoType");
220         g_assert (mono_defaults.monotype_class != 0);
221
222         mono_defaults.exception_class = mono_class_from_name (
223                 mono_defaults.corlib, "System", "Exception");
224         g_assert (mono_defaults.exception_class != 0);
225
226
227         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
228         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
229         ves_icall_System_AppDomainSetup_InitAppDomainSetup (setup);
230
231         name = mono_string_new (domain, g_path_get_basename (filename));
232
233         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
234         ad = (MonoAppDomain *) mono_object_new (domain, class);
235         ad->data = domain;
236         domain->domain = ad;
237         domain->setup = setup;
238         domain->friendly_name = name;
239
240         return domain;
241 }
242
243 void
244 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
245 {
246         // fixme: implement me
247 }
248
249 /**
250  * mono_domain_transfer_object:
251  * @src: the source domain
252  * @dst: the destination domain
253  * @obj: the object to transfer
254  *
255  * This function is used to transfer objects between domains. This is done by
256  * marshalling or serialisation. 
257  */
258 static MonoObject *
259 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj)
260 {
261         MonoClass *klass;
262         MonoObject *res;        
263
264         if (!obj)
265                 return NULL;
266
267         g_assert (obj->vtable->domain == src);
268
269         /* fixme: transfer an object from one domain into another */
270
271         klass = obj->vtable->klass;
272
273         if (MONO_CLASS_IS_ARRAY (klass)) {
274                 MonoArray *ao = (MonoArray *)obj;
275                 int esize, ecount, i;
276                 guint32 *sizes;
277                 
278                 sizes = alloca (klass->rank * sizeof(guint32) * 2);
279                 esize = mono_array_element_size (klass);
280                 ecount = 1;
281                 for (i = 0; i < klass->rank; ++i) {
282                         sizes [i] = ao->bounds [i].length;
283                         ecount *= ao->bounds [i].length;
284                         sizes [i + klass->rank] = ao->bounds [i].lower_bound;
285                 }
286                 res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
287                 if (klass->element_class->valuetype) {
288                         memcpy (res, (char *)ao + sizeof(MonoArray), esize * ecount);
289                 } else {
290                         g_assert (esize == sizeof (gpointer));
291                         for (i = 0; i < ecount; i++) {
292                                 int offset = sizeof (MonoArray) + esize * i;
293                                 gpointer *src_ea = (gpointer *)((char *)ao + offset);
294                                 gpointer *dst_ea = (gpointer *)((char *)res + offset);
295
296                                 *dst_ea = mono_domain_transfer_object (src, dst, *src_ea);
297                         }
298                 }
299         } else if (klass == mono_defaults.string_class) {
300                 MonoString *str = (MonoString *)obj;
301                 res = (MonoObject *)mono_string_new_utf16 (dst, 
302                         (const guint16 *)str->c_str->vector, str->length); 
303         } else {
304                 // fixme: we need generic marshalling code here */
305                 g_assert_not_reached ();
306         }
307         
308         return res;
309 }
310
311 MonoObject *
312 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
313 {
314         MonoDomain *add = ad->data;
315         MonoDomain *cur = mono_domain_get ();
316         MonoObject *o;
317         char *str;
318
319         g_assert (ad != NULL);
320         g_assert (name != NULL);
321
322         str = mono_string_to_utf8 (name);
323
324         if (!strcmp (str, "APPBASE"))
325                 o = (MonoObject *)add->setup->application_base;
326         else if (!strcmp (str, "APP_CONFIG_FILE"))
327                 o = (MonoObject *)add->setup->configuration_file;
328         else if (!strcmp (str, "DYNAMIC_BASE"))
329                 o = (MonoObject *)add->setup->dynamic_base;
330         else if (!strcmp (str, "APP_NAME"))
331                 o = (MonoObject *)add->setup->application_name;
332         else if (!strcmp (str, "CACHE_BASE"))
333                 o = (MonoObject *)add->setup->cache_path;
334         else if (!strcmp (str, "PRIVATE_BINPATH"))
335                 o = (MonoObject *)add->setup->private_bin_path;
336         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
337                 o = (MonoObject *)add->setup->private_bin_path_probe;
338         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
339                 o = (MonoObject *)add->setup->shadow_copy_directories;
340         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
341                 o = (MonoObject *)add->setup->shadow_copy_files;
342         else 
343                 o = g_hash_table_lookup (add->env, str);
344
345         g_free (str);
346
347         if (!o)
348                 return NULL;
349
350         return mono_domain_transfer_object (add, cur, o);
351 }
352
353 void
354 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
355 {
356         MonoDomain *add = ad->data;
357         MonoDomain *cur = mono_domain_get ();
358         MonoObject *o;
359         char *str;
360
361         g_assert (ad != NULL);
362         g_assert (name != NULL);
363
364         o = mono_domain_transfer_object (cur, add, data);
365
366         /* fixme: need a hash func for MonoString */
367         str = mono_string_to_utf8 (name);
368         g_hash_table_insert (add->env, str, o);
369         g_free (str);
370 }
371
372 MonoAppDomainSetup *
373 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
374 {
375         g_assert (ad != NULL);
376         g_assert (ad->data != NULL);
377
378         return ad->data->setup;
379 }
380
381 MonoString *
382 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
383 {
384         g_assert (ad != NULL);
385         g_assert (ad->data != NULL);
386
387         return ad->data->friendly_name;
388 }
389
390 /**
391  * mono_domain_get:
392  *
393  * Returns the current domain.
394  */
395 inline MonoDomain *
396 mono_domain_get ()
397 {
398         return ((MonoDomain *)TlsGetValue (appdomain_thread_id));
399 }
400
401 /**
402  * mono_domain_set:
403  * @domain: the new domain
404  *
405  * Sets the current domain to @domain.
406  */
407 inline void
408 mono_domain_set (MonoDomain *domain)
409 {
410         TlsSetValue (appdomain_thread_id, domain);
411 }
412
413 MonoAppDomain *
414 ves_icall_System_AppDomain_getCurDomain ()
415 {
416         MonoDomain *add = mono_domain_get ();
417         return add->domain;
418 }
419
420 MonoAppDomain *
421 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
422 {
423         MonoDomain *domain = mono_domain_get (); 
424         MonoClass *adclass;
425         MonoAppDomain *ad;
426         MonoDomain *data;
427         
428         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
429         
430         // fixme: pin all those objects
431         ad = (MonoAppDomain *) mono_object_new (domain, adclass);
432         ad->data = data = mono_create_domain ();
433         data->domain = ad;
434         data->setup = setup;
435         data->friendly_name = friendly_name;
436
437         // fixme: what to do next ?
438
439         return ad;
440 }
441
442 typedef struct {
443         MonoArray *res;
444         MonoDomain *domain;
445         int idx;
446 } add_assembly_helper_t;
447
448 static void
449 add_assembly (gpointer key, gpointer value, gpointer user_data)
450 {
451         add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
452
453         mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
454 }
455
456 MonoArray *
457 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
458 {
459         MonoDomain *domain = ad->data; 
460         static MonoClass *System_Reflection_Assembly;
461         MonoArray *res;
462         add_assembly_helper_t ah;
463         
464         if (!System_Reflection_Assembly)
465                 System_Reflection_Assembly = mono_class_from_name (
466                         mono_defaults.corlib, "System.Reflection", "Assembly");
467
468         res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
469
470         ah.domain = domain;
471         ah.res = res;
472         ah.idx = 0;
473         g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
474
475         return res;
476 }
477
478
479 MonoReflectionAssembly *
480 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoReflectionAssemblyName *assRef, MonoObject *evidence)
481 {
482         MonoDomain *domain = ad->data; 
483         char *name, *filename;
484         enum MonoImageOpenStatus status = MONO_IMAGE_OK;
485         MonoAssembly *ass;
486
487         /* FIXME : examine evidence? */
488
489         g_assert (assRef != NULL);
490         g_assert (assRef->name != NULL);
491
492         /* FIXME : examine version, culture info */
493
494         name = filename = mono_string_to_utf8 (assRef->name);
495
496         if (strncmp (filename, "file://", 7) == 0)
497                 filename += 7;
498
499         ass = mono_assembly_open (filename, NULL, &status);
500         
501         g_free (name);
502
503         if (!ass)
504                 mono_raise_exception ((MonoException *)mono_exception_from_name (mono_defaults.corlib, "System.IO", "FileNotFoundException"));
505
506         return mono_assembly_get_object (domain, ass);
507 }
508
509 void
510 ves_icall_System_AppDomain_Unload (MonoAppDomain *ad)
511 {
512         mono_domain_unload (ad->data, FALSE);
513 }
514
515 /**
516  * mono_domain_assembly_open:
517  * @domain: the application domain
518  * @name: file name of the assembly
519  *
520  * fixme: maybe we should integrate this with mono_assembly_open ??
521  */
522 MonoAssembly *
523 mono_domain_assembly_open (MonoDomain *domain, char *name)
524 {
525         MonoAssembly *ass, *tmp;
526         int i;
527
528         if ((ass = g_hash_table_lookup (domain->assemblies, name)))
529                 return ass;
530
531         if (!(ass = mono_assembly_open (name, NULL, NULL)))
532                 return NULL;
533
534         g_hash_table_insert (domain->assemblies, ass->name, ass);
535
536         // fixme: maybe this must be recursive ?
537         for (i = 0; (tmp = ass->image->references [i]) != NULL; i++) {
538                 if (!g_hash_table_lookup (domain->assemblies, tmp->name))
539                         g_hash_table_insert (domain->assemblies, tmp->name, tmp);
540         }
541
542         return ass;
543 }
544
545 static void
546 remove_assembly (gpointer key, gpointer value, gpointer user_data)
547 {
548         mono_assembly_close ((MonoAssembly *)value);
549 }
550
551 void
552 mono_domain_unload (MonoDomain *domain, gboolean force)
553 {
554         if ((domain == mono_root_domain) && !force) {
555                 g_warning ("cant unload root domain");
556                 return;
557         }
558
559         g_hash_table_foreach (domain->assemblies, remove_assembly, NULL);
560
561         g_hash_table_destroy (domain->env);
562         g_hash_table_destroy (domain->assemblies);
563         g_hash_table_destroy (domain->class_vtable_hash);
564         g_hash_table_destroy (domain->jit_code_hash);
565         g_hash_table_destroy (domain->ldstr_table);
566         mono_mempool_destroy (domain->mp);
567         
568         // fixme: anything else required ? */
569
570 #if HAVE_BOEHM_GC
571 #else
572         g_free (domain);
573 #endif
574
575         if ((domain == mono_root_domain))
576                 mono_root_domain = NULL;
577 }
578
579 gint32
580 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, 
581                                             MonoObject *evidence, MonoArray *args)
582 {
583         MonoDomain *cdom = mono_domain_get ();
584         MonoAssembly *assembly;
585         MonoImage *image;
586         MonoCLIImageInfo *iinfo;
587         MonoMethod *method;
588         MonoObject *margs;
589         char *filename;
590         gint32 res;
591
592         mono_domain_set (ad->data);
593
594         filename = mono_string_to_utf8 (file);
595         assembly = mono_assembly_open (filename, NULL, NULL);
596         g_free (filename);
597
598         if (!assembly) {
599                 mono_raise_exception ((MonoException *)mono_exception_from_name (
600                         mono_defaults.corlib, "System.IO", "FileNotFoundException"));
601         }
602
603         image = assembly->image;
604         iinfo = image->image_info;
605         method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
606
607         if (!method)
608                 g_error ("No entry point method found in %s", image->name);
609
610         margs = mono_domain_transfer_object (cdom, ad->data, (MonoObject *)args);
611         res = mono_runtime_exec_main (method, (MonoArray *)margs);
612
613         mono_domain_set (cdom);
614
615         return res;
616 }