2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
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>
26 HANDLE mono_delegate_semaphore = NULL;
27 CRITICAL_SECTION mono_delegate_section;
28 int mono_runtime_shutdown = 0;
31 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj);
35 * @domain: domain returned by mono_init ()
37 * Initialize the core AppDomain: this function will run also some
38 * IL initialization code, so it needs the execution engine to be fully
42 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb)
44 MonoAppDomainSetup *setup;
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);
52 class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
53 ad = (MonoAppDomain *) mono_object_new (domain, class);
56 domain->setup = setup;
58 mono_delegate_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
59 g_assert (mono_delegate_semaphore != INVALID_HANDLE_VALUE);
60 InitializeCriticalSection (&mono_delegate_section);
62 mono_thread_init (domain, start_cb);
70 mono_runtime_cleanup (MonoDomain *domain)
72 mono_runtime_shutdown = 1;
74 /* signal all waiters in order to stop all workers (max. 0xffff) */
75 ReleaseSemaphore (mono_delegate_semaphore, 0xffff, NULL);
77 mono_thread_cleanup ();
79 /* Do this after the thread cleanup, because subthreads might
80 * still be doing socket calls.
82 mono_network_cleanup ();
86 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
88 /* FIXME: implement me */
92 * invokes a method in a specific domain.
95 mono_runtime_invoke_in_domain (MonoDomain *domain, MonoMethod *method, void *obj,
96 void **params, MonoObject **exc)
98 MonoDomain *cur = mono_domain_get ();
99 MonoObject **real_exc, *default_exc;
103 return mono_runtime_invoke (method, obj, params, exc);
106 real_exc = &default_exc;
111 mono_domain_set (domain);
112 res = mono_runtime_invoke (method, obj, params, real_exc);
113 mono_domain_set (cur);
116 /* transfer Exception to the right domain */
117 *real_exc = mono_domain_transfer_object (domain, cur, *real_exc);
120 mono_raise_exception ((MonoException *)*real_exc);
128 mono_domain_transfer_array (MonoDomain *src, MonoDomain *dst, MonoArray *ao)
130 MonoObject *res = NULL;
132 int esize, ecount, i;
135 klass = ao->obj.vtable->klass;
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);
142 sizes = alloca (klass->rank * sizeof(guint32) * 2);
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;
149 res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
151 if (klass->element_class->valuetype) {
152 if (klass->element_class->blittable) {
153 memcpy (((MonoArray *)res)->vector, ao->vector, esize * ecount);
155 for (i = 0; i < ecount; i++) {
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);
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);
176 * mono_domain_transfer_object:
177 * @src: the source domain
178 * @dst: the destination domain
179 * @obj: the object to transfer
181 * This function is used to transfer objects between domains. This is done by
182 * marshalling or serialisation.
185 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj)
187 MonoClass *sic = mono_defaults.serializationinfo_class;
189 MonoObject *res = NULL;
195 g_assert (obj->vtable->domain == src);
197 klass = obj->vtable->klass;
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);
206 if (klass == mono_defaults.monotype_class)
207 return (MonoObject *) mono_type_get_object (dst, ((MonoReflectionType *)obj)->type);
209 if (MONO_CLASS_IS_ARRAY (klass))
210 return mono_domain_transfer_array (src, dst, (MonoArray *)obj);
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;
217 MonoStreamingContext ctx;
218 MonoArray *entries, *trans_entries;
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);
225 src_serinfo = mono_object_new (src, sic);
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];
235 g_assert (serinfo_ctor1);
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];
247 g_assert (serinfo_ctor2);
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];
258 g_assert (get_entries);
261 pa [0] = mono_type_get_object (src, &klass->byval_arg);
262 mono_runtime_invoke_in_domain (src, serinfo_ctor1, src_serinfo, pa, NULL);
264 ctx.additional = NULL;
265 ctx.state = 128; /* CrossAppDomain */
266 pa [0] = src_serinfo;
268 mono_runtime_invoke_in_domain (src, get_object_data, obj, pa, NULL);
270 entries = (MonoArray *)mono_runtime_invoke_in_domain (src, get_entries, src_serinfo, NULL, NULL);
272 g_assert (src_serinfo->vtable->domain == src);
273 g_assert (entries->obj.vtable->domain == src);
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);
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);
290 dst_serinfo = mono_object_new (dst, sic);
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);
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))
308 res = mono_object_new (dst, klass);
310 ctx.additional = NULL;
311 ctx.state = 128; /* CrossAppDomain */
312 pa [0] = dst_serinfo;
314 mono_runtime_invoke_in_domain (dst, ser_ctor, res, pa, NULL);
319 if (!(klass->flags & TYPE_ATTRIBUTE_SERIALIZABLE)) {
320 MonoException *exc = NULL;
323 msg = g_strdup_printf ("klass \"%s.%s\" is not serializable",
324 klass->name_space, klass->name);
325 exc = mono_get_exception_serialization (msg);
328 mono_raise_exception (exc);
331 res = mono_object_new (dst, klass);
333 for (i = 0; i < klass->field.count; i++) {
334 MonoClassField *field = &klass->fields [i];
335 MonoType *type = field->type;
337 char *src_ptr, *dst_ptr;
340 if (type->attrs & FIELD_ATTRIBUTE_STATIC ||
341 type->attrs & FIELD_ATTRIBUTE_NOT_SERIALIZED)
344 size = mono_type_size (type, &align);
346 dst_ptr = (char*)res + field->offset;
347 src_ptr = (char *)obj + field->offset;
349 g_assert (!type->byref);
351 simple_type = type->type;
353 switch (simple_type) {
354 case MONO_TYPE_BOOLEAN:
368 memcpy (dst_ptr, src_ptr, size);
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);
378 case MONO_TYPE_VALUETYPE: {
379 MonoObject *boxed_src, *tmp;
381 if (type->data.klass->enumtype) {
382 simple_type = type->data.klass->enum_basetype->type;
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);
391 g_assert_not_reached ();
399 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
401 MonoDomain *add = ad->data;
402 MonoDomain *cur = mono_domain_get ();
406 g_assert (ad != NULL);
407 g_assert (name != NULL);
409 str = mono_string_to_utf8 (name);
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;
431 o = mono_g_hash_table_lookup (add->env, name);
433 mono_domain_unlock (add);
439 return mono_domain_transfer_object (add, cur, o);
443 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
445 MonoDomain *add = ad->data;
446 MonoDomain *cur = mono_domain_get ();
449 g_assert (ad != NULL);
450 g_assert (name != NULL);
452 o = mono_domain_transfer_object (cur, add, data);
454 mono_domain_lock (add);
455 mono_g_hash_table_insert (add->env, name, o);
457 mono_domain_unlock (add);
461 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
463 g_assert (ad != NULL);
464 g_assert (ad->data != NULL);
466 return ad->data->setup;
470 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
472 g_assert (ad != NULL);
473 g_assert (ad->data != NULL);
475 return mono_string_new (ad->data, ad->data->friendly_name);
479 ves_icall_System_AppDomain_getCurDomain ()
481 MonoDomain *add = mono_domain_get ();
486 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
488 MonoDomain *domain = mono_domain_get ();
493 adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
495 /* FIXME: pin all those objects */
496 ad = (MonoAppDomain *) mono_object_new (domain, adclass);
497 ad->data = data = mono_domain_create ();
500 data->friendly_name = mono_string_to_utf8 (friendly_name);
502 /* FIXME: what to do next ? */
511 } add_assembly_helper_t;
514 add_assembly (gpointer key, gpointer value, gpointer user_data)
516 add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
518 mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
522 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
524 MonoDomain *domain = ad->data;
525 static MonoClass *System_Reflection_Assembly;
527 add_assembly_helper_t ah;
529 if (!System_Reflection_Assembly)
530 System_Reflection_Assembly = mono_class_from_name (
531 mono_defaults.corlib, "System.Reflection", "Assembly");
533 res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
538 mono_domain_lock (domain);
539 g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
540 mono_domain_unlock (domain);
545 MonoReflectionAssembly *
546 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
548 MonoDomain *domain = mono_domain_get ();
549 char *name, *filename;
550 MonoImageOpenStatus status = MONO_IMAGE_OK;
553 name = filename = mono_string_to_utf8 (fname);
555 /* FIXME: move uri handling to mono_assembly_open */
556 if (strncmp (filename, "file://", 7) == 0)
559 ass = mono_assembly_open (filename, &status);
564 MonoException *exc = mono_get_exception_file_not_found (fname);
565 mono_raise_exception (exc);
568 return mono_assembly_get_object (domain, ass);
572 MonoReflectionAssembly *
573 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoReflectionAssemblyName *assRef, MonoObject *evidence)
575 MonoDomain *domain = ad->data;
577 MonoImageOpenStatus status = MONO_IMAGE_OK;
579 MonoAssemblyName aname;
581 memset (&aname, 0, sizeof (aname));
583 /* FIXME : examine evidence? */
585 g_assert (assRef != NULL);
586 g_assert (assRef->name != NULL);
588 /* FIXME : examine version, culture info */
590 aname.name = name = mono_string_to_utf8 (assRef->name);
592 ass = mono_assembly_load (&aname, NULL, &status);
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);
602 return mono_assembly_get_object (domain, ass);
606 ves_icall_System_AppDomain_Unload (MonoAppDomain *ad)
608 mono_domain_unload (ad->data, FALSE);
612 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file,
613 MonoObject *evidence, MonoArray *args)
615 MonoDomain *cdom = mono_domain_get ();
616 MonoAssembly *assembly;
623 mono_domain_set (ad->data);
625 filename = mono_string_to_utf8 (file);
626 assembly = mono_assembly_open (filename, NULL);
630 mono_raise_exception ((MonoException *)mono_exception_from_name (
631 mono_defaults.corlib, "System.IO", "FileNotFoundException"));
634 image = assembly->image;
635 method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
638 g_error ("No entry point method found in %s", image->name);
640 margs = mono_domain_transfer_object (cdom, ad->data, (MonoObject *)args);
641 res = mono_runtime_exec_main (method, (MonoArray *)margs, NULL);
643 mono_domain_set (cdom);