2002-05-23 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/cil-coff.h>
23
24 HANDLE mono_delegate_semaphore = NULL;
25 CRITICAL_SECTION mono_delegate_section;
26 int mono_runtime_shutdown = 0;
27
28 /*
29  * mono_runtime_init:
30  * @domain: domain returned by mono_init ()
31  *
32  * Initialize the core AppDomain: this function will run also some
33  * IL initialization code, so it needs the execution engine to be fully 
34  * operational.
35  */
36 void
37 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb)
38 {
39         MonoAppDomainSetup *setup;
40         MonoAppDomain *ad;
41         MonoClass *class;
42         
43         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
44         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
45         ves_icall_System_AppDomainSetup_InitAppDomainSetup (setup);
46
47         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
48         ad = (MonoAppDomain *) mono_object_new (domain, class);
49         ad->data = domain;
50         domain->domain = ad;
51         domain->setup = setup;
52
53         mono_delegate_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
54         g_assert (mono_delegate_semaphore != INVALID_HANDLE_VALUE);
55         InitializeCriticalSection (&mono_delegate_section);
56         
57         mono_thread_init (domain, start_cb);
58
59         mono_network_init ();
60
61         return;
62 }
63
64 void
65 mono_runtime_cleanup (MonoDomain *domain)
66 {
67         mono_runtime_shutdown = 1;
68
69         mono_network_cleanup ();
70
71         /* signal all waiters in order to stop all workers (max. 0xffff) */
72         ReleaseSemaphore (mono_delegate_semaphore, 0xffff, NULL);
73
74         mono_thread_cleanup ();
75                 
76
77 }
78
79 void
80 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
81 {
82         // fixme: implement me
83 }
84
85 /**
86  * mono_domain_transfer_object:
87  * @src: the source domain
88  * @dst: the destination domain
89  * @obj: the object to transfer
90  *
91  * This function is used to transfer objects between domains. This is done by
92  * marshalling or serialisation. 
93  */
94 static MonoObject *
95 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj)
96 {
97         MonoClass *klass;
98         MonoObject *res;        
99
100         if (!obj)
101                 return NULL;
102
103         g_assert (obj->vtable->domain == src);
104
105         /* fixme: transfer an object from one domain into another */
106
107         klass = obj->vtable->klass;
108
109         if (MONO_CLASS_IS_ARRAY (klass)) {
110                 MonoArray *ao = (MonoArray *)obj;
111                 int esize, ecount, i;
112                 guint32 *sizes;
113                 
114                 esize = mono_array_element_size (klass);
115                 if (ao->bounds == NULL) {
116                         ecount = mono_array_length (ao);
117                         res = (MonoObject *)mono_array_new_full (dst, klass, &ecount, NULL);
118                 }
119                 else {
120                         sizes = alloca (klass->rank * sizeof(guint32) * 2);
121                         ecount = 1;
122                         for (i = 0; i < klass->rank; ++i) {
123                                 sizes [i] = ao->bounds [i].length;
124                                 ecount *= ao->bounds [i].length;
125                                 sizes [i + klass->rank] = ao->bounds [i].lower_bound;
126                         }
127                         res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
128                 }
129                 if (klass->element_class->valuetype) {
130                         memcpy (res, (char *)ao + sizeof(MonoArray), esize * ecount);
131                 } else {
132                         g_assert (esize == sizeof (gpointer));
133                         for (i = 0; i < ecount; i++) {
134                                 int offset = sizeof (MonoArray) + esize * i;
135                                 gpointer *src_ea = (gpointer *)((char *)ao + offset);
136                                 gpointer *dst_ea = (gpointer *)((char *)res + offset);
137
138                                 *dst_ea = mono_domain_transfer_object (src, dst, *src_ea);
139                         }
140                 }
141         } else if (klass == mono_defaults.string_class) {
142                 MonoString *str = (MonoString *)obj;
143                 res = (MonoObject *)mono_string_new_utf16 (dst, 
144                         (const guint16 *)mono_string_chars (str), str->length); 
145         } else {
146                 // fixme: we need generic marshalling code here */
147                 g_assert_not_reached ();
148         }
149         
150         return res;
151 }
152
153 MonoObject *
154 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
155 {
156         MonoDomain *add = ad->data;
157         MonoDomain *cur = mono_domain_get ();
158         MonoObject *o;
159         char *str;
160
161         g_assert (ad != NULL);
162         g_assert (name != NULL);
163
164         str = mono_string_to_utf8 (name);
165
166         mono_domain_lock (add);
167         if (!strcmp (str, "APPBASE"))
168                 o = (MonoObject *)add->setup->application_base;
169         else if (!strcmp (str, "APP_CONFIG_FILE"))
170                 o = (MonoObject *)add->setup->configuration_file;
171         else if (!strcmp (str, "DYNAMIC_BASE"))
172                 o = (MonoObject *)add->setup->dynamic_base;
173         else if (!strcmp (str, "APP_NAME"))
174                 o = (MonoObject *)add->setup->application_name;
175         else if (!strcmp (str, "CACHE_BASE"))
176                 o = (MonoObject *)add->setup->cache_path;
177         else if (!strcmp (str, "PRIVATE_BINPATH"))
178                 o = (MonoObject *)add->setup->private_bin_path;
179         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
180                 o = (MonoObject *)add->setup->private_bin_path_probe;
181         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
182                 o = (MonoObject *)add->setup->shadow_copy_directories;
183         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
184                 o = (MonoObject *)add->setup->shadow_copy_files;
185         else 
186                 o = g_hash_table_lookup (add->env, str);
187
188         mono_domain_unlock (add);
189         g_free (str);
190
191         if (!o)
192                 return NULL;
193
194         return mono_domain_transfer_object (add, cur, o);
195 }
196
197 void
198 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
199 {
200         MonoDomain *add = ad->data;
201         MonoDomain *cur = mono_domain_get ();
202         MonoObject *o;
203         char *str;
204
205         g_assert (ad != NULL);
206         g_assert (name != NULL);
207
208         o = mono_domain_transfer_object (cur, add, data);
209
210         /* fixme: need a hash func for MonoString */
211         str = mono_string_to_utf8 (name);
212         mono_domain_lock (add);
213         g_hash_table_insert (add->env, str, o);
214         mono_domain_unlock (add);
215         g_free (str);
216 }
217
218 MonoAppDomainSetup *
219 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
220 {
221         g_assert (ad != NULL);
222         g_assert (ad->data != NULL);
223
224         return ad->data->setup;
225 }
226
227 MonoString *
228 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
229 {
230         g_assert (ad != NULL);
231         g_assert (ad->data != NULL);
232
233         return mono_string_new (ad->data, ad->data->friendly_name);
234 }
235
236 MonoAppDomain *
237 ves_icall_System_AppDomain_getCurDomain ()
238 {
239         MonoDomain *add = mono_domain_get ();
240         return add->domain;
241 }
242
243 MonoAppDomain *
244 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
245 {
246         MonoDomain *domain = mono_domain_get (); 
247         MonoClass *adclass;
248         MonoAppDomain *ad;
249         MonoDomain *data;
250         
251         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
252         
253         // fixme: pin all those objects
254         ad = (MonoAppDomain *) mono_object_new (domain, adclass);
255         ad->data = data = mono_domain_create ();
256         data->domain = ad;
257         data->setup = setup;
258         data->friendly_name = mono_string_to_utf8 (friendly_name);
259
260         // fixme: what to do next ?
261
262         return ad;
263 }
264
265 typedef struct {
266         MonoArray *res;
267         MonoDomain *domain;
268         int idx;
269 } add_assembly_helper_t;
270
271 static void
272 add_assembly (gpointer key, gpointer value, gpointer user_data)
273 {
274         add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
275
276         mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
277 }
278
279 MonoArray *
280 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
281 {
282         MonoDomain *domain = ad->data; 
283         static MonoClass *System_Reflection_Assembly;
284         MonoArray *res;
285         add_assembly_helper_t ah;
286         
287         if (!System_Reflection_Assembly)
288                 System_Reflection_Assembly = mono_class_from_name (
289                         mono_defaults.corlib, "System.Reflection", "Assembly");
290
291         res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
292
293         ah.domain = domain;
294         ah.res = res;
295         ah.idx = 0;
296         mono_domain_lock (domain);
297         g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
298         mono_domain_unlock (domain);
299
300         return res;
301 }
302
303 MonoReflectionAssembly *
304 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
305 {
306         MonoDomain *domain = mono_domain_get ();
307         char *name, *filename;
308         MonoImageOpenStatus status = MONO_IMAGE_OK;
309         MonoAssembly *ass;
310
311         name = filename = mono_string_to_utf8 (fname);
312
313         /* FIXME: move uri handling to mono_assembly_open */
314         if (strncmp (filename, "file://", 7) == 0)
315                 filename += 7;
316
317         ass = mono_assembly_open (filename, &status);
318         
319         g_free (name);
320
321         if (!ass)
322                 mono_raise_exception ((MonoException *)mono_exception_from_name (mono_defaults.corlib, "System.IO", "FileNotFoundException"));
323
324         return mono_assembly_get_object (domain, ass);
325 }
326
327
328 MonoReflectionAssembly *
329 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoReflectionAssemblyName *assRef, MonoObject *evidence)
330 {
331         MonoDomain *domain = ad->data; 
332         char *name;
333         MonoImageOpenStatus status = MONO_IMAGE_OK;
334         MonoAssembly *ass;
335         MonoAssemblyName aname;
336
337         memset (&aname, 0, sizeof (aname));
338
339         /* FIXME : examine evidence? */
340
341         g_assert (assRef != NULL);
342         g_assert (assRef->name != NULL);
343
344         /* FIXME : examine version, culture info */
345
346         name = aname.name = mono_string_to_utf8 (assRef->name);
347
348         ass = mono_assembly_load (&aname, NULL, &status);
349         
350         g_free (name);
351
352         if (!ass)
353                 mono_raise_exception ((MonoException *)mono_exception_from_name (mono_defaults.corlib, "System.IO", "FileNotFoundException"));
354
355         return mono_assembly_get_object (domain, ass);
356 }
357
358 void
359 ves_icall_System_AppDomain_Unload (MonoAppDomain *ad)
360 {
361         mono_domain_unload (ad->data, FALSE);
362 }
363
364 gint32
365 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, 
366                                             MonoObject *evidence, MonoArray *args)
367 {
368         MonoDomain *cdom = mono_domain_get ();
369         MonoAssembly *assembly;
370         MonoImage *image;
371         MonoCLIImageInfo *iinfo;
372         MonoMethod *method;
373         MonoObject *margs;
374         char *filename;
375         gint32 res;
376
377         mono_domain_set (ad->data);
378
379         filename = mono_string_to_utf8 (file);
380         assembly = mono_assembly_open (filename, NULL);
381         g_free (filename);
382
383         if (!assembly) {
384                 mono_raise_exception ((MonoException *)mono_exception_from_name (
385                         mono_defaults.corlib, "System.IO", "FileNotFoundException"));
386         }
387
388         image = assembly->image;
389         iinfo = image->image_info;
390         method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
391
392         if (!method)
393                 g_error ("No entry point method found in %s", image->name);
394
395         margs = mono_domain_transfer_object (cdom, ad->data, (MonoObject *)args);
396         res = mono_runtime_exec_main (method, (MonoArray *)margs, NULL);
397
398         mono_domain_set (cdom);
399
400         return res;
401 }
402