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