Tue Mar 26 19:56:10 CET 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/cil-coff.h>
23
24 static guint32 appdomain_thread_id = 0;
25
26 static MonoJitInfoTable *
27 mono_jit_info_table_new ()
28 {
29         return g_array_new (FALSE, FALSE, sizeof (gpointer));
30 }
31
32 static void
33 mono_jit_info_table_free (MonoJitInfoTable *table)
34 {
35         g_array_free (table, TRUE);
36 }
37
38 static int
39 mono_jit_info_table_index (MonoJitInfoTable *table, gpointer addr)
40 {
41         int left = 0, right = table->len;
42
43         while (left < right) {
44                 int pos = (left + right) / 2;
45                 MonoJitInfo *ji = g_array_index (table, gpointer, pos);
46                 gpointer start = ji->code_start;
47                 gpointer end = start + ji->code_size;
48
49                 if (addr < start)
50                         right = pos;
51                 else if (addr >= end) 
52                         left = pos + 1;
53                 else
54                         return pos;
55         }
56
57         return left;
58 }
59
60 MonoJitInfo *
61 mono_jit_info_table_find (MonoDomain *domain, gpointer addr)
62 {
63         MonoJitInfoTable *table = domain->jit_info_table;
64         int left = 0, right = table->len;
65
66         while (left < right) {
67                 int pos = (left + right) / 2;
68                 MonoJitInfo *ji = g_array_index (table, gpointer, pos);
69                 gpointer start = ji->code_start;
70                 gpointer end = start + ji->code_size;
71
72                 if (addr < start)
73                         right = pos;
74                 else if (addr >= end) 
75                         left = pos + 1;
76                 else
77                         return ji;
78         }
79
80         /* maybe irt is shared code, so we also search in the root domain */
81         if (domain != mono_root_domain)
82                 return mono_jit_info_table_find (domain, addr);
83
84         return NULL;
85 }
86
87 void
88 mono_jit_info_table_add (MonoDomain *domain, MonoJitInfo *ji)
89 {
90         MonoJitInfoTable *table = domain->jit_info_table;
91         gpointer start = ji->code_start;
92         int pos = mono_jit_info_table_index (table, start);
93
94         g_array_insert_val (table, pos, ji);
95 }
96
97 static int
98 ldstr_hash (const char* str)
99 {
100         guint len, h;
101         const char *end;
102         len = mono_metadata_decode_blob_size (str, &str) - 1;
103         end = str + len;
104         h = *str;
105         /*
106          * FIXME: The distribution may not be so nice with lots of
107          * null chars in the string.
108          */
109         for (str += 1; str < end; str++)
110                 h = (h << 5) - h + *str;
111         return h;
112 }
113
114 static gboolean
115 ldstr_equal (const char *str1, const char *str2) {
116         int len, len2;
117         len = mono_metadata_decode_blob_size (str1, NULL) - 1;
118         len2 = mono_metadata_decode_blob_size (str2, NULL) - 1;
119         if (len != len2)
120                 return 0;
121         return memcmp (str1, str2, len) == 0;
122 }
123
124 #if HAVE_BOEHM_GC
125 static void
126 domain_finalizer (void *obj, void *data) {
127         g_print ("domain finalized\n");
128 }
129 #endif
130
131 static MonoDomain *
132 mono_create_domain ()
133 {
134         MonoDomain *domain;
135
136 #if HAVE_BOEHM_GC
137         domain = GC_malloc (sizeof (MonoDomain));
138         GC_register_finalizer (domain, domain_finalizer, NULL, NULL, NULL);
139 #else
140         domain = g_new0 (MonoDomain, 1);
141 #endif
142         domain->domain = NULL;
143         domain->setup = NULL;
144         domain->friendly_name = NULL;
145
146         domain->mp = mono_mempool_new ();
147         domain->env = g_hash_table_new (g_str_hash, g_str_equal);
148         domain->assemblies = g_hash_table_new (g_str_hash, g_str_equal);
149         domain->class_vtable_hash = mono_g_hash_table_new (NULL, NULL);
150         domain->jit_code_hash = g_hash_table_new (NULL, NULL);
151         domain->ldstr_table = mono_g_hash_table_new ((GHashFunc)ldstr_hash, (GCompareFunc)ldstr_equal);
152         domain->jit_info_table = mono_jit_info_table_new ();
153         return domain;
154 }
155
156 MonoDomain *mono_root_domain = NULL;
157
158 /**
159  * mono_init:
160  * 
161  * Creates the initial application domain and initializes the mono_defaults
162  * structure.
163  *
164  * Returns: the initial domain.
165  */
166 MonoDomain *
167 mono_init (const char *filename)
168 {
169         static MonoDomain *domain = NULL;
170         MonoAppDomainSetup *setup;
171         MonoAppDomain *ad;
172         MonoAssembly *ass;
173         MonoClass *class;
174         MonoString *name;
175         enum MonoImageOpenStatus status = MONO_IMAGE_OK;
176
177         if (domain)
178                 g_assert_not_reached ();
179
180         appdomain_thread_id = TlsAlloc ();
181
182         domain = mono_create_domain ();
183         mono_root_domain = domain;
184
185         TlsSetValue (appdomain_thread_id, domain);
186
187         /* find the corlib */
188         ass = mono_assembly_open (CORLIB_NAME, NULL, &status);
189         if ((status != MONO_IMAGE_OK) || (ass == NULL)) {
190                 switch (status){
191                 case MONO_IMAGE_ERROR_ERRNO:
192                         g_print ("The assembly corlib.dll was not found or could not be loaded.\n");
193                         g_print ("It should have been installed in the `%s' directory.\n", MONO_ASSEMBLIES);
194                         break;
195                 case MONO_IMAGE_IMAGE_INVALID:
196                         g_print ("The file %s/corlib.dll is an invalid CIL image\n", MONO_ASSEMBLIES);
197                         break;
198                 case MONO_IMAGE_MISSING_ASSEMBLYREF:
199                         g_print ("Minning assembly reference in %s/corlib.dll\n", MONO_ASSEMBLIES);
200                         break;
201                 case MONO_IMAGE_OK:
202                         /* to suppress compiler warning */
203                 }
204                 
205                 exit (1);
206         }
207         mono_defaults.corlib = ass->image;
208
209         mono_defaults.object_class = mono_class_from_name (
210                 mono_defaults.corlib, "System", "Object");
211         g_assert (mono_defaults.object_class != 0);
212
213         mono_defaults.void_class = mono_class_from_name (
214                 mono_defaults.corlib, "System", "Void");
215         g_assert (mono_defaults.void_class != 0);
216
217         mono_defaults.boolean_class = mono_class_from_name (
218                 mono_defaults.corlib, "System", "Boolean");
219         g_assert (mono_defaults.boolean_class != 0);
220
221         mono_defaults.byte_class = mono_class_from_name (
222                 mono_defaults.corlib, "System", "Byte");
223         g_assert (mono_defaults.byte_class != 0);
224
225         mono_defaults.sbyte_class = mono_class_from_name (
226                 mono_defaults.corlib, "System", "SByte");
227         g_assert (mono_defaults.sbyte_class != 0);
228
229         mono_defaults.int16_class = mono_class_from_name (
230                 mono_defaults.corlib, "System", "Int16");
231         g_assert (mono_defaults.int16_class != 0);
232
233         mono_defaults.uint16_class = mono_class_from_name (
234                 mono_defaults.corlib, "System", "UInt16");
235         g_assert (mono_defaults.uint16_class != 0);
236
237         mono_defaults.int32_class = mono_class_from_name (
238                 mono_defaults.corlib, "System", "Int32");
239         g_assert (mono_defaults.int32_class != 0);
240
241         mono_defaults.uint32_class = mono_class_from_name (
242                 mono_defaults.corlib, "System", "UInt32");
243         g_assert (mono_defaults.uint32_class != 0);
244
245         mono_defaults.uint_class = mono_class_from_name (
246                 mono_defaults.corlib, "System", "UIntPtr");
247         g_assert (mono_defaults.uint_class != 0);
248
249         mono_defaults.int_class = mono_class_from_name (
250                 mono_defaults.corlib, "System", "IntPtr");
251         g_assert (mono_defaults.int_class != 0);
252
253         mono_defaults.int64_class = mono_class_from_name (
254                 mono_defaults.corlib, "System", "Int64");
255         g_assert (mono_defaults.int64_class != 0);
256
257         mono_defaults.uint64_class = mono_class_from_name (
258                 mono_defaults.corlib, "System", "UInt64");
259         g_assert (mono_defaults.uint64_class != 0);
260
261         mono_defaults.single_class = mono_class_from_name (
262                 mono_defaults.corlib, "System", "Single");
263         g_assert (mono_defaults.single_class != 0);
264
265         mono_defaults.double_class = mono_class_from_name (
266                 mono_defaults.corlib, "System", "Double");
267         g_assert (mono_defaults.double_class != 0);
268
269         mono_defaults.char_class = mono_class_from_name (
270                 mono_defaults.corlib, "System", "Char");
271         g_assert (mono_defaults.char_class != 0);
272
273         mono_defaults.string_class = mono_class_from_name (
274                 mono_defaults.corlib, "System", "String");
275         g_assert (mono_defaults.string_class != 0);
276
277         mono_defaults.enum_class = mono_class_from_name (
278                 mono_defaults.corlib, "System", "Enum");
279         g_assert (mono_defaults.enum_class != 0);
280
281         mono_defaults.array_class = mono_class_from_name (
282                 mono_defaults.corlib, "System", "Array");
283         g_assert (mono_defaults.array_class != 0);
284
285         mono_defaults.multicastdelegate_class = mono_class_from_name (
286                 mono_defaults.corlib, "System", "MulticastDelegate");
287         g_assert (mono_defaults.multicastdelegate_class != 0 );
288
289         mono_defaults.asyncresult_class = mono_class_from_name (
290                 mono_defaults.corlib, "System.Runtime.Remoting.Messaging", 
291                 "AsyncResult");
292         g_assert (mono_defaults.asyncresult_class != 0 );
293
294         mono_defaults.waithandle_class = mono_class_from_name (
295                 mono_defaults.corlib, "System.Threading", "WaitHandle");
296         g_assert (mono_defaults.waithandle_class != 0 );
297
298         mono_defaults.typehandle_class = mono_class_from_name (
299                 mono_defaults.corlib, "System", "RuntimeTypeHandle");
300         g_assert (mono_defaults.typehandle_class != 0);
301
302         mono_defaults.methodhandle_class = mono_class_from_name (
303                 mono_defaults.corlib, "System", "RuntimeMethodHandle");
304         g_assert (mono_defaults.methodhandle_class != 0);
305
306         mono_defaults.fieldhandle_class = mono_class_from_name (
307                 mono_defaults.corlib, "System", "RuntimeFieldHandle");
308         g_assert (mono_defaults.fieldhandle_class != 0);
309
310         mono_defaults.monotype_class = mono_class_from_name (
311                 mono_defaults.corlib, "System", "MonoType");
312         g_assert (mono_defaults.monotype_class != 0);
313
314         mono_defaults.exception_class = mono_class_from_name (
315                 mono_defaults.corlib, "System", "Exception");
316         g_assert (mono_defaults.exception_class != 0);
317
318         mono_defaults.thread_class = mono_class_from_name (
319                 mono_defaults.corlib, "System.Threading", "Thread");
320         g_assert (mono_defaults.thread_class != 0);
321
322         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
323         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
324         ves_icall_System_AppDomainSetup_InitAppDomainSetup (setup);
325
326         name = mono_string_new (domain, g_path_get_basename (filename));
327
328         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
329         ad = (MonoAppDomain *) mono_object_new (domain, class);
330         ad->data = domain;
331         domain->domain = ad;
332         domain->setup = setup;
333         domain->friendly_name = name;
334
335         return domain;
336 }
337
338 void
339 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
340 {
341         // fixme: implement me
342 }
343
344 /**
345  * mono_domain_transfer_object:
346  * @src: the source domain
347  * @dst: the destination domain
348  * @obj: the object to transfer
349  *
350  * This function is used to transfer objects between domains. This is done by
351  * marshalling or serialisation. 
352  */
353 static MonoObject *
354 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj)
355 {
356         MonoClass *klass;
357         MonoObject *res;        
358
359         if (!obj)
360                 return NULL;
361
362         g_assert (obj->vtable->domain == src);
363
364         /* fixme: transfer an object from one domain into another */
365
366         klass = obj->vtable->klass;
367
368         if (MONO_CLASS_IS_ARRAY (klass)) {
369                 MonoArray *ao = (MonoArray *)obj;
370                 int esize, ecount, i;
371                 guint32 *sizes;
372                 
373                 sizes = alloca (klass->rank * sizeof(guint32) * 2);
374                 esize = mono_array_element_size (klass);
375                 ecount = 1;
376                 for (i = 0; i < klass->rank; ++i) {
377                         sizes [i] = ao->bounds [i].length;
378                         ecount *= ao->bounds [i].length;
379                         sizes [i + klass->rank] = ao->bounds [i].lower_bound;
380                 }
381                 res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
382                 if (klass->element_class->valuetype) {
383                         memcpy (res, (char *)ao + sizeof(MonoArray), esize * ecount);
384                 } else {
385                         g_assert (esize == sizeof (gpointer));
386                         for (i = 0; i < ecount; i++) {
387                                 int offset = sizeof (MonoArray) + esize * i;
388                                 gpointer *src_ea = (gpointer *)((char *)ao + offset);
389                                 gpointer *dst_ea = (gpointer *)((char *)res + offset);
390
391                                 *dst_ea = mono_domain_transfer_object (src, dst, *src_ea);
392                         }
393                 }
394         } else if (klass == mono_defaults.string_class) {
395                 MonoString *str = (MonoString *)obj;
396                 res = (MonoObject *)mono_string_new_utf16 (dst, 
397                         (const guint16 *)str->c_str->vector, str->length); 
398         } else {
399                 // fixme: we need generic marshalling code here */
400                 g_assert_not_reached ();
401         }
402         
403         return res;
404 }
405
406 MonoObject *
407 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
408 {
409         MonoDomain *add = ad->data;
410         MonoDomain *cur = mono_domain_get ();
411         MonoObject *o;
412         char *str;
413
414         g_assert (ad != NULL);
415         g_assert (name != NULL);
416
417         str = mono_string_to_utf8 (name);
418
419         if (!strcmp (str, "APPBASE"))
420                 o = (MonoObject *)add->setup->application_base;
421         else if (!strcmp (str, "APP_CONFIG_FILE"))
422                 o = (MonoObject *)add->setup->configuration_file;
423         else if (!strcmp (str, "DYNAMIC_BASE"))
424                 o = (MonoObject *)add->setup->dynamic_base;
425         else if (!strcmp (str, "APP_NAME"))
426                 o = (MonoObject *)add->setup->application_name;
427         else if (!strcmp (str, "CACHE_BASE"))
428                 o = (MonoObject *)add->setup->cache_path;
429         else if (!strcmp (str, "PRIVATE_BINPATH"))
430                 o = (MonoObject *)add->setup->private_bin_path;
431         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
432                 o = (MonoObject *)add->setup->private_bin_path_probe;
433         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
434                 o = (MonoObject *)add->setup->shadow_copy_directories;
435         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
436                 o = (MonoObject *)add->setup->shadow_copy_files;
437         else 
438                 o = g_hash_table_lookup (add->env, str);
439
440         g_free (str);
441
442         if (!o)
443                 return NULL;
444
445         return mono_domain_transfer_object (add, cur, o);
446 }
447
448 void
449 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
450 {
451         MonoDomain *add = ad->data;
452         MonoDomain *cur = mono_domain_get ();
453         MonoObject *o;
454         char *str;
455
456         g_assert (ad != NULL);
457         g_assert (name != NULL);
458
459         o = mono_domain_transfer_object (cur, add, data);
460
461         /* fixme: need a hash func for MonoString */
462         str = mono_string_to_utf8 (name);
463         g_hash_table_insert (add->env, str, o);
464         g_free (str);
465 }
466
467 MonoAppDomainSetup *
468 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
469 {
470         g_assert (ad != NULL);
471         g_assert (ad->data != NULL);
472
473         return ad->data->setup;
474 }
475
476 MonoString *
477 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
478 {
479         g_assert (ad != NULL);
480         g_assert (ad->data != NULL);
481
482         return ad->data->friendly_name;
483 }
484
485 /**
486  * mono_domain_get:
487  *
488  * Returns the current domain.
489  */
490 inline MonoDomain *
491 mono_domain_get ()
492 {
493         return ((MonoDomain *)TlsGetValue (appdomain_thread_id));
494 }
495
496 /**
497  * mono_domain_set:
498  * @domain: the new domain
499  *
500  * Sets the current domain to @domain.
501  */
502 inline void
503 mono_domain_set (MonoDomain *domain)
504 {
505         TlsSetValue (appdomain_thread_id, domain);
506 }
507
508 MonoAppDomain *
509 ves_icall_System_AppDomain_getCurDomain ()
510 {
511         MonoDomain *add = mono_domain_get ();
512         return add->domain;
513 }
514
515 MonoAppDomain *
516 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
517 {
518         MonoDomain *domain = mono_domain_get (); 
519         MonoClass *adclass;
520         MonoAppDomain *ad;
521         MonoDomain *data;
522         
523         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
524         
525         // fixme: pin all those objects
526         ad = (MonoAppDomain *) mono_object_new (domain, adclass);
527         ad->data = data = mono_create_domain ();
528         data->domain = ad;
529         data->setup = setup;
530         data->friendly_name = friendly_name;
531
532         // fixme: what to do next ?
533
534         return ad;
535 }
536
537 typedef struct {
538         MonoArray *res;
539         MonoDomain *domain;
540         int idx;
541 } add_assembly_helper_t;
542
543 static void
544 add_assembly (gpointer key, gpointer value, gpointer user_data)
545 {
546         add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
547
548         mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
549 }
550
551 MonoArray *
552 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
553 {
554         MonoDomain *domain = ad->data; 
555         static MonoClass *System_Reflection_Assembly;
556         MonoArray *res;
557         add_assembly_helper_t ah;
558         
559         if (!System_Reflection_Assembly)
560                 System_Reflection_Assembly = mono_class_from_name (
561                         mono_defaults.corlib, "System.Reflection", "Assembly");
562
563         res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
564
565         ah.domain = domain;
566         ah.res = res;
567         ah.idx = 0;
568         g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
569
570         return res;
571 }
572
573
574 MonoReflectionAssembly *
575 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoReflectionAssemblyName *assRef, MonoObject *evidence)
576 {
577         MonoDomain *domain = ad->data; 
578         char *name, *filename;
579         enum MonoImageOpenStatus status = MONO_IMAGE_OK;
580         MonoAssembly *ass;
581
582         /* FIXME : examine evidence? */
583
584         g_assert (assRef != NULL);
585         g_assert (assRef->name != NULL);
586
587         /* FIXME : examine version, culture info */
588
589         name = filename = mono_string_to_utf8 (assRef->name);
590
591         if (strncmp (filename, "file://", 7) == 0)
592                 filename += 7;
593
594         ass = mono_assembly_open (filename, NULL, &status);
595         
596         g_free (name);
597
598         if (!ass)
599                 mono_raise_exception ((MonoException *)mono_exception_from_name (mono_defaults.corlib, "System.IO", "FileNotFoundException"));
600
601         return mono_assembly_get_object (domain, ass);
602 }
603
604 void
605 ves_icall_System_AppDomain_Unload (MonoAppDomain *ad)
606 {
607         mono_domain_unload (ad->data, FALSE);
608 }
609
610 /**
611  * mono_domain_assembly_open:
612  * @domain: the application domain
613  * @name: file name of the assembly
614  *
615  * fixme: maybe we should integrate this with mono_assembly_open ??
616  */
617 MonoAssembly *
618 mono_domain_assembly_open (MonoDomain *domain, char *name)
619 {
620         MonoAssembly *ass, *tmp;
621         int i;
622
623         if ((ass = g_hash_table_lookup (domain->assemblies, name)))
624                 return ass;
625
626         if (!(ass = mono_assembly_open (name, NULL, NULL)))
627                 return NULL;
628
629         g_hash_table_insert (domain->assemblies, ass->name, ass);
630
631         // fixme: maybe this must be recursive ?
632         for (i = 0; (tmp = ass->image->references [i]) != NULL; i++) {
633                 if (!g_hash_table_lookup (domain->assemblies, tmp->name))
634                         g_hash_table_insert (domain->assemblies, tmp->name, tmp);
635         }
636
637         return ass;
638 }
639
640 static void
641 remove_assembly (gpointer key, gpointer value, gpointer user_data)
642 {
643         mono_assembly_close ((MonoAssembly *)value);
644 }
645
646 void
647 mono_domain_unload (MonoDomain *domain, gboolean force)
648 {
649         if ((domain == mono_root_domain) && !force) {
650                 g_warning ("cant unload root domain");
651                 return;
652         }
653
654         g_hash_table_foreach (domain->assemblies, remove_assembly, NULL);
655
656         g_hash_table_destroy (domain->env);
657         g_hash_table_destroy (domain->assemblies);
658         mono_g_hash_table_destroy (domain->class_vtable_hash);
659         g_hash_table_destroy (domain->jit_code_hash);
660         mono_g_hash_table_destroy (domain->ldstr_table);
661         mono_jit_info_table_free (domain->jit_info_table);
662         mono_mempool_destroy (domain->mp);
663         
664         // fixme: anything else required ? */
665
666 #if HAVE_BOEHM_GC
667 #else
668         g_free (domain);
669 #endif
670
671         if ((domain == mono_root_domain))
672                 mono_root_domain = NULL;
673 }
674
675 gint32
676 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, 
677                                             MonoObject *evidence, MonoArray *args)
678 {
679         MonoDomain *cdom = mono_domain_get ();
680         MonoAssembly *assembly;
681         MonoImage *image;
682         MonoCLIImageInfo *iinfo;
683         MonoMethod *method;
684         MonoObject *margs;
685         char *filename;
686         gint32 res;
687
688         mono_domain_set (ad->data);
689
690         filename = mono_string_to_utf8 (file);
691         assembly = mono_assembly_open (filename, NULL, NULL);
692         g_free (filename);
693
694         if (!assembly) {
695                 mono_raise_exception ((MonoException *)mono_exception_from_name (
696                         mono_defaults.corlib, "System.IO", "FileNotFoundException"));
697         }
698
699         image = assembly->image;
700         iinfo = image->image_info;
701         method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
702
703         if (!method)
704                 g_error ("No entry point method found in %s", image->name);
705
706         margs = mono_domain_transfer_object (cdom, ad->data, (MonoObject *)args);
707         res = mono_runtime_exec_main (method, (MonoArray *)margs);
708
709         mono_domain_set (cdom);
710
711         return res;
712 }
713