2002-08-16 Dietmar Maurer <dietmar@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/threads.h>
23 #include <mono/metadata/socket-io.h>
24 #include <mono/metadata/tabledefs.h>
25
26 HANDLE mono_delegate_semaphore = NULL;
27 CRITICAL_SECTION mono_delegate_section;
28 int mono_runtime_shutdown = 0;
29
30 static MonoObject *
31 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj);
32
33 /*
34  * mono_runtime_init:
35  * @domain: domain returned by mono_init ()
36  *
37  * Initialize the core AppDomain: this function will run also some
38  * IL initialization code, so it needs the execution engine to be fully 
39  * operational.
40  */
41 void
42 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb)
43 {
44         MonoAppDomainSetup *setup;
45         MonoAppDomain *ad;
46         MonoClass *class;
47         
48         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
49         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
50         ves_icall_System_AppDomainSetup_InitAppDomainSetup (setup);
51
52         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
53         ad = (MonoAppDomain *) mono_object_new (domain, class);
54         ad->data = domain;
55         domain->domain = ad;
56         domain->setup = setup;
57
58         mono_delegate_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
59         g_assert (mono_delegate_semaphore != INVALID_HANDLE_VALUE);
60         InitializeCriticalSection (&mono_delegate_section);
61         
62         mono_thread_init (domain, start_cb);
63
64         mono_network_init ();
65
66         return;
67 }
68
69 void
70 mono_runtime_cleanup (MonoDomain *domain)
71 {
72         mono_runtime_shutdown = 1;
73
74         /* signal all waiters in order to stop all workers (max. 0xffff) */
75         ReleaseSemaphore (mono_delegate_semaphore, 0xffff, NULL);
76
77         mono_thread_cleanup ();
78
79         /* Do this after the thread cleanup, because subthreads might
80          * still be doing socket calls.
81          */
82         mono_network_cleanup ();
83 }
84
85 void
86 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
87 {
88         /* FIXME: implement me */
89 }
90
91 /*
92  * invokes a method in a specific domain.
93  */
94 static MonoObject*
95 mono_runtime_invoke_in_domain (MonoDomain *domain, MonoMethod *method, void *obj, 
96                                void **params, MonoObject **exc)
97 {
98         MonoDomain *cur = mono_domain_get ();
99         MonoObject **real_exc, *default_exc;
100         MonoObject *res;
101
102         if (domain == cur)
103                 return mono_runtime_invoke (method, obj, params, exc);
104
105         if (!exc)
106                 real_exc = &default_exc;
107         else
108                 real_exc = exc;
109
110         *real_exc = NULL;
111         mono_domain_set (domain);
112         res = mono_runtime_invoke (method, obj, params, real_exc);
113         mono_domain_set (cur);
114
115         if (*real_exc) {
116                 /* transfer Exception to the right domain */
117                 *real_exc = mono_domain_transfer_object (domain, cur, *real_exc);
118
119                 if (!exc)
120                         mono_raise_exception ((MonoException *)*real_exc);
121
122         }
123
124         return res;
125 }
126
127 static MonoObject *
128 mono_domain_transfer_array (MonoDomain *src, MonoDomain *dst, MonoArray *ao)
129 {
130         MonoObject *res = NULL;
131         MonoClass *klass;
132         int esize, ecount, i;
133         guint32 *sizes;
134                 
135         klass = ao->obj.vtable->klass;
136
137         esize = mono_array_element_size (klass);
138         if (ao->bounds == NULL) {
139                 ecount = mono_array_length (ao);
140                 res = (MonoObject *)mono_array_new_full (dst, klass, &ecount, NULL);
141         } else {
142                 sizes = alloca (klass->rank * sizeof(guint32) * 2);
143                 ecount = 1;
144                 for (i = 0; i < klass->rank; ++i) {
145                         sizes [i] = ao->bounds [i].length;
146                         ecount *= ao->bounds [i].length;
147                         sizes [i + klass->rank] = ao->bounds [i].lower_bound;
148                 }
149                 res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
150         }
151         if (klass->element_class->valuetype) {
152                 if (klass->element_class->blittable) {
153                         memcpy (((MonoArray *)res)->vector, ao->vector, esize * ecount);
154                 } else {
155                         for (i = 0; i < ecount; i++) {
156                                 MonoObject *s, *d;
157                                 gpointer *src_ea = (gpointer *)mono_array_addr_with_size (ao, esize, i);
158                                 gpointer *dst_ea = (gpointer *)mono_array_addr_with_size ((MonoArray *)res, esize, i);
159                                 s = mono_value_box (src, klass->element_class, src_ea);
160                                 d = mono_domain_transfer_object (src, dst, s);
161                                 memcpy (dst_ea, (char *)d + sizeof(MonoObject), esize);
162                         }
163                 }
164         } else {
165                 g_assert (esize == sizeof (gpointer));
166                 for (i = 0; i < ecount; i++) {
167                         gpointer *src_ea = (gpointer *)mono_array_addr_with_size (ao, esize, i);
168                         gpointer *dst_ea = (gpointer *)mono_array_addr_with_size ((MonoArray *)res, esize, i);
169                         *dst_ea = mono_domain_transfer_object (src, dst, *src_ea);
170                 }
171         }
172         return res;
173 }
174
175 /**
176  * mono_domain_transfer_object:
177  * @src: the source domain
178  * @dst: the destination domain
179  * @obj: the object to transfer
180  *
181  * This function is used to transfer objects between domains. This is done by
182  * marshalling or serialisation. 
183  */
184 static MonoObject *
185 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj)
186 {
187         MonoClass *sic = mono_defaults.serializationinfo_class;
188         MonoClass *klass;
189         MonoObject *res = NULL; 
190         int i;
191
192         if (!obj)
193                 return NULL;
194
195         g_assert (obj->vtable->domain == src);
196
197         klass = obj->vtable->klass;
198
199         /* some special cases */
200         if (klass == mono_defaults.string_class) {
201                 MonoString *str = (MonoString *)obj;
202                 return (MonoObject *)mono_string_new_utf16 (dst, 
203                         (const guint16 *)mono_string_chars (str), str->length); 
204         } 
205
206         if (klass == mono_defaults.monotype_class)
207                 return (MonoObject *) mono_type_get_object (dst, ((MonoReflectionType *)obj)->type);    
208
209         if (MONO_CLASS_IS_ARRAY (klass))
210                 return mono_domain_transfer_array (src, dst, (MonoArray *)obj); 
211
212         if (mono_object_isinst (obj, mono_defaults.iserializeable_class)) {
213                 static MonoMethod *serinfo_ctor1 = NULL, *serinfo_ctor2 = NULL, *get_entries = NULL;
214                 MonoMethod *get_object_data, *ser_ctor;
215                 MonoObject *src_serinfo, *dst_serinfo;
216                 void *pa [2];
217                 MonoStreamingContext ctx;
218                 MonoArray *entries, *trans_entries;
219                 int len;
220
221                 /* get a pointer to the GetObjectData method */ 
222                 get_object_data = klass->vtable [klass->interface_offsets [mono_defaults.iserializeable_class->interface_id]];
223                 g_assert (get_object_data);
224
225                 src_serinfo = mono_object_new (src, sic);
226
227                 if (!serinfo_ctor1) {
228                         for (i = 0; i < sic->method.count; ++i) {
229                                 if (!strcmp (".ctor", sic->methods [i]->name) &&
230                                     sic->methods [i]->signature->param_count == 1) {
231                                         serinfo_ctor1 = sic->methods [i];
232                                         break;
233                                 }
234                         }
235                         g_assert (serinfo_ctor1);
236                 }
237                 
238                 if (!serinfo_ctor2) {
239                         for (i = 0; i < sic->method.count; ++i) {
240                                 if (!strcmp (".ctor", sic->methods [i]->name) &&
241                                     sic->methods [i]->signature->param_count == 2 &&
242                                     sic->methods [i]->signature->params [1]->type == MONO_TYPE_SZARRAY) {
243                                         serinfo_ctor2 = sic->methods [i];
244                                         break;
245                                 }
246                         }
247                         g_assert (serinfo_ctor2);
248                 }
249                 
250                 if (!get_entries) {
251                         for (i = 0; i < sic->method.count; ++i) {
252                                 if (!strcmp ("get_entries", sic->methods [i]->name) &&
253                                     sic->methods [i]->signature->param_count == 0) {
254                                         get_entries = sic->methods [i];
255                                         break;
256                                 }
257                         }
258                         g_assert (get_entries);
259                 }
260
261                 pa [0] = mono_type_get_object (src, &klass->byval_arg);
262                 mono_runtime_invoke_in_domain (src, serinfo_ctor1, src_serinfo, pa, NULL);
263
264                 ctx.additional = NULL;
265                 ctx.state = 128; /* CrossAppDomain */
266                 pa [0] = src_serinfo;
267                 pa [1] = &ctx;
268                 mono_runtime_invoke_in_domain (src, get_object_data, obj, pa, NULL);
269
270                 entries = (MonoArray *)mono_runtime_invoke_in_domain (src, get_entries, src_serinfo, NULL, NULL);
271
272                 g_assert (src_serinfo->vtable->domain == src);
273                 g_assert (entries->obj.vtable->domain == src);
274
275                 /* transfer all SerializationEntry objects */
276                 len = mono_array_length ((MonoArray*)entries);
277                 trans_entries = mono_array_new (dst, entries->obj.vtable->klass->element_class, len);
278
279                 for (i = 0; i < len; i++) {
280                         MonoSerializationEntry *s, *d;
281                         s = (MonoSerializationEntry *)mono_array_addr_with_size (entries, 
282                                 sizeof (MonoSerializationEntry), i);
283                         d = (MonoSerializationEntry *)mono_array_addr_with_size (trans_entries, 
284                                 sizeof (MonoSerializationEntry), i);
285                         d->name = (MonoString *)mono_domain_transfer_object (src, dst, (MonoObject *)s->name);
286                         d->value = mono_domain_transfer_object (src, dst, s->value);
287                         d->type = (MonoReflectionType *)mono_domain_transfer_object (src, dst, (MonoObject *)s->type);
288                 }
289
290                 dst_serinfo = mono_object_new (dst, sic);
291
292                 pa [0] = mono_type_get_object (dst, &klass->byval_arg);
293                 pa [1] = trans_entries;
294                 mono_runtime_invoke_in_domain (dst, serinfo_ctor2, dst_serinfo, pa, NULL);
295
296                 ser_ctor = NULL;
297                 for (i = 0; i < klass->method.count; i++) {
298                         MonoMethod *t = klass->methods [i];
299                         if (!strcmp (t->name, ".ctor") && t->signature->param_count == 2 &&
300                             mono_metadata_type_equal (t->signature->params [0], 
301                                                       &mono_defaults.serializationinfo_class->byval_arg) &&
302                             mono_metadata_type_equal (t->signature->params [1], 
303                                                       &mono_defaults.streamingcontext_class->byval_arg))
304                                 ser_ctor = t;
305                 }
306                 g_assert (ser_ctor);
307
308                 res = mono_object_new (dst, klass);
309
310                 ctx.additional = NULL;
311                 ctx.state = 128; /* CrossAppDomain */
312                 pa [0] = dst_serinfo;
313                 pa [1] = &ctx;
314                 mono_runtime_invoke_in_domain (dst, ser_ctor, res, pa, NULL);
315
316                 return res;
317         }
318
319         if (!(klass->flags & TYPE_ATTRIBUTE_SERIALIZABLE)) {
320                 MonoException *exc = NULL;
321                 char *msg;
322
323                 msg = g_strdup_printf ("klass \"%s.%s\" is not serializable", 
324                                        klass->name_space, klass->name);
325                 exc = mono_get_exception_serialization (msg);
326                 g_free (msg);
327
328                 mono_raise_exception (exc);
329         }
330
331         res = mono_object_new (dst, klass);
332
333         for (i = 0; i < klass->field.count; i++) {
334                 MonoClassField *field = &klass->fields [i];
335                 MonoType *type = field->type;
336                 int size, align;
337                 char *src_ptr, *dst_ptr;
338                 int simple_type;
339
340                 if (type->attrs & FIELD_ATTRIBUTE_STATIC ||
341                     type->attrs & FIELD_ATTRIBUTE_NOT_SERIALIZED)
342                         continue;
343
344                 size = mono_type_size (type, &align);
345
346                 dst_ptr = (char*)res + field->offset;
347                 src_ptr = (char *)obj + field->offset;
348
349                 g_assert (!type->byref);
350                 
351                 simple_type = type->type;
352         handle_enum:
353                 switch (simple_type) {
354                 case MONO_TYPE_BOOLEAN:
355                 case MONO_TYPE_CHAR: 
356                 case MONO_TYPE_I1:
357                 case MONO_TYPE_U1:
358                 case MONO_TYPE_I2:
359                 case MONO_TYPE_U2:
360                 case MONO_TYPE_I4:
361                 case MONO_TYPE_U4:
362                 case MONO_TYPE_I:
363                 case MONO_TYPE_U:
364                 case MONO_TYPE_I8: 
365                 case MONO_TYPE_U8:
366                 case MONO_TYPE_R4:
367                 case MONO_TYPE_R8:
368                         memcpy (dst_ptr, src_ptr, size);
369                         break;
370                 case MONO_TYPE_OBJECT:
371                 case MONO_TYPE_ARRAY:
372                 case MONO_TYPE_SZARRAY:
373                 case MONO_TYPE_CLASS:
374                 case MONO_TYPE_STRING: {
375                         *(MonoObject **)dst_ptr = mono_domain_transfer_object (src, dst, *(MonoObject **)src_ptr);
376                         break;
377                 }
378                 case MONO_TYPE_VALUETYPE: {
379                         MonoObject *boxed_src, *tmp;
380
381                         if (type->data.klass->enumtype) {
382                                 simple_type = type->data.klass->enum_basetype->type;
383                                 goto handle_enum;
384                         }
385                         boxed_src = mono_value_box (src, type->data.klass, src_ptr);
386                         tmp = mono_domain_transfer_object (src, dst, boxed_src);
387                         memcpy (dst_ptr, (char *)tmp + sizeof (MonoObject), size);
388                         break;
389                 }
390                 default:
391                         g_assert_not_reached ();
392                 }
393         }
394
395         return res;
396 }
397
398 MonoObject *
399 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
400 {
401         MonoDomain *add = ad->data;
402         MonoDomain *cur = mono_domain_get ();
403         MonoObject *o;
404         char *str;
405
406         g_assert (ad != NULL);
407         g_assert (name != NULL);
408
409         str = mono_string_to_utf8 (name);
410
411         mono_domain_lock (add);
412         if (!strcmp (str, "APPBASE"))
413                 o = (MonoObject *)add->setup->application_base;
414         else if (!strcmp (str, "APP_CONFIG_FILE"))
415                 o = (MonoObject *)add->setup->configuration_file;
416         else if (!strcmp (str, "DYNAMIC_BASE"))
417                 o = (MonoObject *)add->setup->dynamic_base;
418         else if (!strcmp (str, "APP_NAME"))
419                 o = (MonoObject *)add->setup->application_name;
420         else if (!strcmp (str, "CACHE_BASE"))
421                 o = (MonoObject *)add->setup->cache_path;
422         else if (!strcmp (str, "PRIVATE_BINPATH"))
423                 o = (MonoObject *)add->setup->private_bin_path;
424         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
425                 o = (MonoObject *)add->setup->private_bin_path_probe;
426         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
427                 o = (MonoObject *)add->setup->shadow_copy_directories;
428         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
429                 o = (MonoObject *)add->setup->shadow_copy_files;
430         else 
431                 o = mono_g_hash_table_lookup (add->env, name);
432
433         mono_domain_unlock (add);
434         g_free (str);
435
436         if (!o)
437                 return NULL;
438
439         return mono_domain_transfer_object (add, cur, o);
440 }
441
442 void
443 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
444 {
445         MonoDomain *add = ad->data;
446         MonoDomain *cur = mono_domain_get ();
447         MonoObject *o;
448
449         g_assert (ad != NULL);
450         g_assert (name != NULL);
451
452         o = mono_domain_transfer_object (cur, add, data);
453
454         mono_domain_lock (add);
455         mono_g_hash_table_insert (add->env, name, o);
456
457         mono_domain_unlock (add);
458 }
459
460 MonoAppDomainSetup *
461 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
462 {
463         g_assert (ad != NULL);
464         g_assert (ad->data != NULL);
465
466         return ad->data->setup;
467 }
468
469 MonoString *
470 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
471 {
472         g_assert (ad != NULL);
473         g_assert (ad->data != NULL);
474
475         return mono_string_new (ad->data, ad->data->friendly_name);
476 }
477
478 MonoAppDomain *
479 ves_icall_System_AppDomain_getCurDomain ()
480 {
481         MonoDomain *add = mono_domain_get ();
482         return add->domain;
483 }
484
485 MonoAppDomain *
486 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
487 {
488         MonoDomain *domain = mono_domain_get (); 
489         MonoClass *adclass;
490         MonoAppDomain *ad;
491         MonoDomain *data;
492         
493         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
494         
495         /* FIXME: pin all those objects */
496         ad = (MonoAppDomain *) mono_object_new (domain, adclass);
497         ad->data = data = mono_domain_create ();
498         data->domain = ad;
499         data->setup = setup;
500         data->friendly_name = mono_string_to_utf8 (friendly_name);
501
502         /* FIXME: what to do next ? */
503
504         return ad;
505 }
506
507 typedef struct {
508         MonoArray *res;
509         MonoDomain *domain;
510         int idx;
511 } add_assembly_helper_t;
512
513 static void
514 add_assembly (gpointer key, gpointer value, gpointer user_data)
515 {
516         add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
517
518         mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
519 }
520
521 MonoArray *
522 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
523 {
524         MonoDomain *domain = ad->data; 
525         static MonoClass *System_Reflection_Assembly;
526         MonoArray *res;
527         add_assembly_helper_t ah;
528         
529         if (!System_Reflection_Assembly)
530                 System_Reflection_Assembly = mono_class_from_name (
531                         mono_defaults.corlib, "System.Reflection", "Assembly");
532
533         res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
534
535         ah.domain = domain;
536         ah.res = res;
537         ah.idx = 0;
538         mono_domain_lock (domain);
539         g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
540         mono_domain_unlock (domain);
541
542         return res;
543 }
544
545 MonoReflectionAssembly *
546 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
547 {
548         MonoDomain *domain = mono_domain_get ();
549         char *name, *filename;
550         MonoImageOpenStatus status = MONO_IMAGE_OK;
551         MonoAssembly *ass;
552
553         name = filename = mono_string_to_utf8 (fname);
554
555         /* FIXME: move uri handling to mono_assembly_open */
556         if (strncmp (filename, "file://", 7) == 0)
557                 filename += 7;
558
559         ass = mono_assembly_open (filename, &status);
560         
561         g_free (name);
562
563         if (!ass){
564                 MonoException *exc = mono_get_exception_file_not_found (fname);
565                 mono_raise_exception (exc);
566         }
567
568         return mono_assembly_get_object (domain, ass);
569 }
570
571
572 MonoReflectionAssembly *
573 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoReflectionAssemblyName *assRef, MonoObject *evidence)
574 {
575         MonoDomain *domain = ad->data; 
576         char *name;
577         MonoImageOpenStatus status = MONO_IMAGE_OK;
578         MonoAssembly *ass;
579         MonoAssemblyName aname;
580
581         memset (&aname, 0, sizeof (aname));
582
583         /* FIXME : examine evidence? */
584
585         g_assert (assRef != NULL);
586         g_assert (assRef->name != NULL);
587
588         /* FIXME : examine version, culture info */
589
590         aname.name = name = mono_string_to_utf8 (assRef->name);
591
592         ass = mono_assembly_load (&aname, NULL, &status);
593         
594         g_free (name);
595
596         if (!ass) {
597                 /* FIXME: it doesn't make much sense since we really don't have a filename ... */
598                 MonoException *exc = mono_get_exception_file_not_found (assRef->name);
599                 mono_raise_exception (exc);
600         }
601
602         return mono_assembly_get_object (domain, ass);
603 }
604
605 void
606 ves_icall_System_AppDomain_Unload (MonoAppDomain *ad)
607 {
608         mono_domain_unload (ad->data, FALSE);
609 }
610
611 gint32
612 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, 
613                                             MonoObject *evidence, MonoArray *args)
614 {
615         MonoDomain *cdom = mono_domain_get ();
616         MonoAssembly *assembly;
617         MonoImage *image;
618         MonoMethod *method;
619         MonoObject *margs;
620         char *filename;
621         gint32 res;
622
623         mono_domain_set (ad->data);
624
625         filename = mono_string_to_utf8 (file);
626         assembly = mono_assembly_open (filename, NULL);
627         g_free (filename);
628
629         if (!assembly) {
630                 mono_raise_exception ((MonoException *)mono_exception_from_name (
631                         mono_defaults.corlib, "System.IO", "FileNotFoundException"));
632         }
633
634         image = assembly->image;
635         method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
636
637         if (!method)
638                 g_error ("No entry point method found in %s", image->name);
639
640         margs = mono_domain_transfer_object (cdom, ad->data, (MonoObject *)args);
641         res = mono_runtime_exec_main (method, (MonoArray *)margs, NULL);
642
643         mono_domain_set (cdom);
644
645         return res;
646 }
647