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