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