2004-07-05 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2001-2004 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include <mono/os/gc_wrapper.h>
35 #include <mono/utils/strenc.h>
36
37 /*
38  * Enable experimental typed allocation using the GC_gcj_malloc function.
39  */
40 #ifdef HAVE_GC_GCJ_MALLOC
41 #define CREATION_SPEEDUP 1
42 #endif
43
44 void
45 mono_runtime_object_init (MonoObject *this)
46 {
47         int i;
48         MonoMethod *method = NULL;
49         MonoClass *klass = this->vtable->klass;
50
51         for (i = 0; i < klass->method.count; ++i) {
52                 if (!strcmp (".ctor", klass->methods [i]->name) &&
53                     klass->methods [i]->signature->param_count == 0) {
54                         method = klass->methods [i];
55                         break;
56                 }
57         }
58
59         g_assert (method);
60
61         if (method->klass->valuetype)
62                 this = mono_object_unbox (this);
63         mono_runtime_invoke (method, this, NULL, NULL);
64 }
65
66 /* The pseudo algorithm for type initialization from the spec
67 Note it doesn't say anything about domains - only threads.
68
69 2. If the type is initialized you are done.
70 2.1. If the type is not yet initialized, try to take an 
71      initialization lock.  
72 2.2. If successful, record this thread as responsible for 
73      initializing the type and proceed to step 2.3.
74 2.2.1. If not, see whether this thread or any thread 
75      waiting for this thread to complete already holds the lock.
76 2.2.2. If so, return since blocking would create a deadlock.  This thread 
77      will now see an incompletely initialized state for the type, 
78      but no deadlock will arise.
79 2.2.3  If not, block until the type is initialized then return.
80 2.3 Initialize the parent type and then all interfaces implemented 
81     by this type.
82 2.4 Execute the type initialization code for this type.
83 2.5 Mark the type as initialized, release the initialization lock, 
84     awaken any threads waiting for this type to be initialized, 
85     and return.
86
87 */
88
89 typedef struct
90 {
91         guint32 initializing_tid;
92         guint32 waiting_count;
93         CRITICAL_SECTION initialization_section;
94 } TypeInitializationLock;
95
96 /* for locking access to type_initialization_hash and blocked_thread_hash */
97 static CRITICAL_SECTION type_initialization_section;
98
99 /* from vtable to lock */
100 static GHashTable *type_initialization_hash;
101
102 /* from thread id to thread id being waited on */
103 static GHashTable *blocked_thread_hash;
104
105 /* Main thread */
106 static MonoThread *main_thread;
107
108 void
109 mono_type_initialization_init (void)
110 {
111         InitializeCriticalSection (&type_initialization_section);
112         type_initialization_hash = g_hash_table_new (NULL, NULL);
113         blocked_thread_hash = g_hash_table_new (NULL, NULL);
114 }
115
116 /*
117  * mono_runtime_class_init:
118  * @vtable: vtable that needs to be initialized
119  *
120  * This routine calls the class constructor for @vtable.
121  */
122 void
123 mono_runtime_class_init (MonoVTable *vtable)
124 {
125         int i;
126         MonoException *exc;
127         MonoException *exc_to_throw;
128         MonoMethod *method = NULL;
129         MonoClass *klass;
130         gchar *full_name;
131         gboolean found;
132
133         MONO_ARCH_SAVE_REGS;
134
135         if (vtable->initialized)
136                 return;
137
138         exc = NULL;
139         found = FALSE;
140         klass = vtable->klass;
141
142         for (i = 0; i < klass->method.count; ++i) {
143                 method = klass->methods [i];
144                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
145                     (strcmp (".cctor", method->name) == 0)) {
146                         found = TRUE;
147                         break;
148                 }
149         }
150
151         if (found) {
152                 MonoDomain *domain = vtable->domain;
153                 TypeInitializationLock *lock;
154                 guint32 tid = GetCurrentThreadId();
155                 int do_initialization = 0;
156                 MonoDomain *last_domain = NULL;
157
158                 EnterCriticalSection (&type_initialization_section);
159                 /* double check... */
160                 if (vtable->initialized) {
161                         LeaveCriticalSection (&type_initialization_section);
162                         return;
163                 }
164                 lock = g_hash_table_lookup (type_initialization_hash, vtable);
165                 if (lock == NULL) {
166                         /* This thread will get to do the initialization */
167                         if (mono_domain_get () != domain) {
168                                 /* Transfer into the target domain */
169                                 last_domain = mono_domain_get ();
170                                 if (!mono_domain_set (domain, FALSE)) {
171                                         vtable->initialized = 1;
172                                         LeaveCriticalSection (&type_initialization_section);
173                                         mono_raise_exception (mono_get_exception_appdomain_unloaded ());
174                                 }
175                         }
176                         lock = g_malloc (sizeof(TypeInitializationLock));
177                         InitializeCriticalSection (&lock->initialization_section);
178                         lock->initializing_tid = tid;
179                         lock->waiting_count = 1;
180                         /* grab the vtable lock while this thread still owns type_initialization_section */
181                         EnterCriticalSection (&lock->initialization_section);
182                         g_hash_table_insert (type_initialization_hash, vtable, lock);
183                         do_initialization = 1;
184                 } else {
185                         gpointer blocked;
186
187                         if (lock->initializing_tid == tid) {
188                                 LeaveCriticalSection (&type_initialization_section);
189                                 return;
190                         }
191                         /* see if the thread doing the initialization is already blocked on this thread */
192                         blocked = GUINT_TO_POINTER (lock->initializing_tid);
193                         while ((blocked = g_hash_table_lookup (blocked_thread_hash, blocked))) {
194                                 if (blocked == GUINT_TO_POINTER (tid)) {
195                                         LeaveCriticalSection (&type_initialization_section);
196                                         return;
197                                 }
198                         }
199                         ++lock->waiting_count;
200                         /* record the fact that we are waiting on the initializing thread */
201                         g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), GUINT_TO_POINTER (lock->initializing_tid));
202                 }
203                 LeaveCriticalSection (&type_initialization_section);
204
205                 if (do_initialization) {
206                         mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
207                         if (last_domain)
208                                 mono_domain_set (last_domain, TRUE);
209                         LeaveCriticalSection (&lock->initialization_section);
210                 } else {
211                         /* this just blocks until the initializing thread is done */
212                         EnterCriticalSection (&lock->initialization_section);
213                         LeaveCriticalSection (&lock->initialization_section);
214                 }
215
216                 EnterCriticalSection (&type_initialization_section);
217                 if (lock->initializing_tid != tid)
218                         g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
219                 --lock->waiting_count;
220                 if (lock->waiting_count == 0) {
221                         DeleteCriticalSection (&lock->initialization_section);
222                         g_hash_table_remove (type_initialization_hash, vtable);
223                         g_free (lock);
224                 }
225                 vtable->initialized = 1;
226                 /* FIXME: if the cctor fails, the type must be marked as unusable */
227                 LeaveCriticalSection (&type_initialization_section);
228         } else {
229                 vtable->initialized = 1;
230                 return;
231         }
232
233         if (exc == NULL ||
234             (klass->image == mono_defaults.corlib &&            
235              !strcmp (klass->name_space, "System") &&
236              !strcmp (klass->name, "TypeInitializationException")))
237                 return; /* No static constructor found or avoid infinite loop */
238
239         if (klass->name_space && *klass->name_space)
240                 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
241         else
242                 full_name = g_strdup (klass->name);
243
244         exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
245         g_free (full_name);
246
247         mono_raise_exception (exc_to_throw);
248 }
249
250 static gpointer
251 default_trampoline (MonoMethod *method)
252 {
253         return method;
254 }
255
256 static gpointer
257 default_remoting_trampoline (MonoMethod *method)
258 {
259         g_error ("remoting not installed");
260         return NULL;
261 }
262
263 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
264 static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
265
266 void
267 mono_install_trampoline (MonoTrampoline func) 
268 {
269         arch_create_jit_trampoline = func? func: default_trampoline;
270 }
271
272 void
273 mono_install_remoting_trampoline (MonoTrampoline func) 
274 {
275         arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
276 }
277
278 static MonoCompileFunc default_mono_compile_method = NULL;
279
280 void        
281 mono_install_compile_method (MonoCompileFunc func)
282 {
283         default_mono_compile_method = func;
284 }
285
286 gpointer 
287 mono_compile_method (MonoMethod *method)
288 {
289         if (!default_mono_compile_method) {
290                 g_error ("compile method called on uninitialized runtime");
291                 return NULL;
292         }
293         return default_mono_compile_method (method);
294 }
295
296
297 #if 0 && HAVE_BOEHM_GC
298 static void
299 vtable_finalizer (void *obj, void *data) {
300         g_print ("%s finalized (%p)\n", (char*)data, obj);
301 }
302 #endif
303
304 #if CREATION_SPEEDUP
305
306 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
307
308 /*
309  * The vtables in the root appdomain are assumed to be reachable by other 
310  * roots, and we don't use typed allocation in the other domains.
311  */
312
313 #define GC_HEADER_BITMAP (1 << (G_STRUCT_OFFSET (MonoObject,synchronisation) / sizeof(gpointer)))
314
315 static void
316 mono_class_compute_gc_descriptor (MonoClass *class)
317 {
318         MonoClassField *field;
319         guint64 bitmap;
320         guint32 bm [2];
321         int i;
322         static gboolean gcj_inited = FALSE;
323
324         if (!gcj_inited) {
325                 gcj_inited = TRUE;
326
327                 GC_init_gcj_malloc (5, NULL);
328         }
329
330         if (!class->inited)
331                 mono_class_init (class);
332
333         if (class->gc_descr_inited)
334                 return;
335
336         class->gc_descr_inited = TRUE;
337         class->gc_descr = GC_NO_DESCRIPTOR;
338
339         if (class == mono_defaults.string_class) {
340                 bitmap = GC_HEADER_BITMAP;
341                 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 2);
342         }
343         else if (class->rank) {
344                 mono_class_compute_gc_descriptor (class->element_class);
345
346                 if (class->element_class->valuetype && (class->element_class->gc_descr != GC_NO_DESCRIPTOR) && (class->element_class->gc_bitmap == GC_HEADER_BITMAP)) {
347                         bitmap = GC_HEADER_BITMAP;
348                         if (class->rank > 1)
349                                 bitmap += 1 << (G_STRUCT_OFFSET (MonoArray,bounds) / sizeof(gpointer));
350                         class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 3);
351                 }
352         }
353         else {
354                 static int count = 0;
355                 MonoClass *p;
356                 guint32 pos;
357
358                 /* GC 6.1 has trouble handling 64 bit descriptors... */
359                 if ((class->instance_size / sizeof (gpointer)) > 30) {
360 /*                      printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer)); */
361                         return;
362                 }
363
364                 bitmap = GC_HEADER_BITMAP;
365
366                 count ++;
367
368 /*              if (count > 442) */
369 /*                      return;  */
370
371 /*              printf("KLASS: %s.\n", class->name); */
372
373                 for (p = class; p != NULL; p = p->parent) {
374                 for (i = 0; i < p->field.count; ++i) {
375                         field = &p->fields [i];
376                         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
377                                 continue;
378                         if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
379                                 return;
380
381                         pos = field->offset / sizeof (gpointer);
382                         
383                         if (field->type->byref)
384                                 return;
385
386                         switch (field->type->type) {
387                         case MONO_TYPE_BOOLEAN:
388                         case MONO_TYPE_I1:
389                         case MONO_TYPE_U1:
390                         case MONO_TYPE_I2:
391                         case MONO_TYPE_U2:
392                         case MONO_TYPE_CHAR:
393                         case MONO_TYPE_I4:
394                         case MONO_TYPE_U4:
395                         case MONO_TYPE_I8:
396                         case MONO_TYPE_U8:
397                         case MONO_TYPE_R4:
398                         case MONO_TYPE_R8:
399 /*                              printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap); */
400                                 break;
401                         case MONO_TYPE_I:
402                         case MONO_TYPE_STRING:
403                         case MONO_TYPE_SZARRAY:
404                         case MONO_TYPE_CLASS:
405                         case MONO_TYPE_OBJECT:
406                         case MONO_TYPE_ARRAY:
407                         case MONO_TYPE_PTR:
408                                 g_assert ((field->offset % sizeof(gpointer)) == 0);
409
410                                 bitmap |= ((guint64)1) << pos;
411 /*                              printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap); */
412                                 break;
413                         case MONO_TYPE_VALUETYPE: {
414                                 MonoClass *fclass = field->type->data.klass;
415                                 if (!fclass->enumtype) {
416                                         mono_class_compute_gc_descriptor (fclass);
417                                         bitmap |= (fclass->gc_bitmap >> (sizeof (MonoObject) / sizeof (gpointer))) << pos;
418                                 }
419                                 break;
420                         }
421                         default:
422                                 return;
423                         }
424                 }
425                 }
426
427 /*              printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap); */
428                 class->gc_bitmap = bitmap;
429                 /* Convert to the format expected by GC_make_descriptor */
430                 bm [0] = (guint32)bitmap;
431                 bm [1] = (guint32)(bitmap >> 32);
432                 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bm, class->instance_size / sizeof (gpointer));
433         }
434 }
435 #endif /* CREATION_SPEEDUP */
436
437 /**
438  * field_is_special_static:
439  *
440  * Returns SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
441  * SPECIAL_STATIC_NONE otherwise.
442  */
443 static gint32
444 field_is_special_static (MonoClass *fklass, MonoClassField *field)
445 {
446         MonoCustomAttrInfo *ainfo;
447         int i;
448         ainfo = mono_custom_attrs_from_field (fklass, field);
449         if (!ainfo)
450                 return FALSE;
451         for (i = 0; i < ainfo->num_attrs; ++i) {
452                 MonoClass *klass = ainfo->attrs [i].ctor->klass;
453                 if (klass->image == mono_defaults.corlib) {
454                         if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
455                                 mono_custom_attrs_free (ainfo);
456                                 return SPECIAL_STATIC_THREAD;
457                         }
458                         else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
459                                 mono_custom_attrs_free (ainfo);
460                                 return SPECIAL_STATIC_CONTEXT;
461                         }
462                 }
463         }
464         mono_custom_attrs_free (ainfo);
465         return SPECIAL_STATIC_NONE;
466 }
467
468 /**
469  * mono_class_vtable:
470  * @domain: the application domain
471  * @class: the class to initialize
472  *
473  * VTables are domain specific because we create domain specific code, and 
474  * they contain the domain specific static class data.
475  */
476 MonoVTable *
477 mono_class_vtable (MonoDomain *domain, MonoClass *class)
478 {
479         MonoVTable *vt = NULL;
480         MonoClassField *field;
481         const char *p;
482         char *t;
483         int i, len;
484         guint32 vtable_size;
485         guint32 cindex;
486         guint32 constant_cols [MONO_CONSTANT_SIZE];
487
488         g_assert (class);
489
490         vt = class->cached_vtable;
491         if (vt && vt->domain == domain)
492                 return vt;
493
494         mono_domain_lock (domain);
495         if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
496                 mono_domain_unlock (domain);
497                 return vt;
498         }
499         
500         if (!class->inited)
501                 mono_class_init (class);
502
503         mono_stats.used_class_count++;
504         mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
505
506         vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
507
508         vt = mono_mempool_alloc0 (domain->mp,  vtable_size);
509
510         vt->klass = class;
511         vt->domain = domain;
512
513 #if CREATION_SPEEDUP
514         mono_class_compute_gc_descriptor (class);
515         if (domain != mono_get_root_domain ())
516                 /*
517                  * We can't use typed allocation in the non-root domains, since the
518                  * collector needs the GC descriptor stored in the vtable even after
519                  * the mempool containing the vtable is destroyed when the domain is
520                  * unloaded. An alternative might be to allocate vtables in the GC
521                  * heap, but this does not seem to work (it leads to crashes inside
522                  * libgc). If that approach is tried, two gc descriptors need to be
523                  * allocated for each class: one for the root domain, and one for all
524                  * other domains. The second descriptor should contain a bit for the
525                  * vtable field in MonoObject, since we can no longer assume the 
526                  * vtable is reachable by other roots after the appdomain is unloaded.
527                  */
528                 vt->gc_descr = GC_NO_DESCRIPTOR;
529         else
530                 vt->gc_descr = class->gc_descr;
531 #endif
532
533         if (class->class_size) {
534 #if HAVE_BOEHM_GC
535                 vt->data = GC_MALLOC (class->class_size + 8);
536                 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
537                 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
538                 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
539 #else
540                 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
541                 
542 #endif
543                 mono_stats.class_static_data_size += class->class_size + 8;
544         }
545
546         cindex = -1;
547         for (i = class->field.first; i < class->field.last; ++i) {
548                 field = &class->fields [i - class->field.first];
549                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
550                         continue;
551                 if (mono_field_is_deleted (field))
552                         continue;
553                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
554                         gint32 special_static = field_is_special_static (class, field);
555                         if (special_static != SPECIAL_STATIC_NONE) {
556                                 guint32 size, align, offset;
557                                 size = mono_type_size (field->type, &align);
558                                 offset = mono_alloc_special_static_data (special_static, size, align);
559                                 if (!domain->special_static_fields)
560                                         domain->special_static_fields = g_hash_table_new (NULL, NULL);
561                                 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
562                                 continue;
563                         }
564                 }
565                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
566                         MonoClass *fklass = mono_class_from_mono_type (field->type);
567                         t = (char*)vt->data + field->offset;
568                         if (fklass->valuetype) {
569                                 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
570                         } else {
571                                 /* it's a pointer type: add check */
572                                 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
573                                 *t = *(char *)field->data;
574                         }
575                         continue;
576                 }
577                 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
578                         continue;
579
580                 if (!field->def_value) {
581                         cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1), cindex + 1);
582                         g_assert (cindex);
583
584                         mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
585                         field->def_value = g_new0 (MonoConstant, 1);
586                         field->def_value->type = constant_cols [MONO_CONSTANT_TYPE];
587                         field->def_value->value = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
588                 }
589
590                 p = field->def_value->value;
591                 len = mono_metadata_decode_blob_size (p, &p);
592                 t = (char*)vt->data + field->offset;
593                 /* should we check that the type matches? */
594                 switch (field->def_value->type) {
595                 case MONO_TYPE_BOOLEAN:
596                 case MONO_TYPE_U1:
597                 case MONO_TYPE_I1:
598                         *t = *p;
599                         break;
600                 case MONO_TYPE_CHAR:
601                 case MONO_TYPE_U2:
602                 case MONO_TYPE_I2: {
603                         guint16 *val = (guint16*)t;
604                         *val = read16 (p);
605                         break;
606                 }
607                 case MONO_TYPE_U4:
608                 case MONO_TYPE_I4: {
609                         guint32 *val = (guint32*)t;
610                         *val = read32 (p);
611                         break;
612                 }
613                 case MONO_TYPE_U8:
614                 case MONO_TYPE_I8: {
615                         guint64 *val = (guint64*)t;
616                         *val = read64 (p);
617                         break;
618                 }
619                 case MONO_TYPE_R4: {
620                         float *val = (float*)t;
621                         readr4 (p, val);
622                         break;
623                 }
624                 case MONO_TYPE_R8: {
625                         double *val = (double*)t;
626                         readr8 (p, val);
627                         break;
628                 }
629                 case MONO_TYPE_STRING: {
630                         gpointer *val = (gpointer*)t;
631 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
632                         gunichar2 *copy = g_malloc (len);
633                         int j;
634                         for (j = 0; j < len/2; j++) {
635                                 copy [j] = read16 (p);
636                                 p += 2;
637                         }
638                         *val = mono_string_new_utf16 (domain, copy, len/2);
639                         g_free (copy);
640 #else
641                         *val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
642 #endif
643                         break;
644                 }
645                 case MONO_TYPE_CLASS:
646                         /* nothing to do, we malloc0 the data and the value can be 0 only */
647                         break;
648                 default:
649                         g_warning ("type 0x%02x should not be in constant table", field->def_value->type);
650                 }
651         }
652
653         vt->max_interface_id = class->max_interface_id;
654         
655         vt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
656                 sizeof (gpointer) * (class->max_interface_id + 1));
657
658         /* initialize interface offsets */
659         for (i = 0; i <= class->max_interface_id; ++i) {
660                 int slot = class->interface_offsets [i];
661                 if (slot >= 0)
662                         vt->interface_offsets [i] = &(vt->vtable [slot]);
663         }
664
665         /* 
666          * arch_create_jit_trampoline () can recursively call this function again
667          * because it compiles icall methods right away.
668          */
669         mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
670         if (!class->cached_vtable)
671                 class->cached_vtable = vt;
672
673         /* initialize vtable */
674         for (i = 0; i < class->vtable_size; ++i) {
675                 MonoMethod *cm;
676                
677                 if ((cm = class->vtable [i]))
678                         vt->vtable [i] = arch_create_jit_trampoline (cm);
679         }
680
681         mono_domain_unlock (domain);
682
683         /* make sure the the parent is initialized */
684         if (class->parent)
685                 mono_class_vtable (domain, class->parent);
686
687         vt->type = mono_type_get_object (domain, &class->byval_arg);
688         if (class->contextbound)
689                 vt->remote = 1;
690         else
691                 vt->remote = 0;
692
693         return vt;
694 }
695
696 /**
697  * mono_class_proxy_vtable:
698  * @domain: the application domain
699  * @remove_class: the remote class
700  *
701  * Creates a vtable for transparent proxies. It is basically
702  * a copy of the real vtable of the class wrapped in @remote_class,
703  * but all function pointers invoke the remoting functions, and
704  * vtable->klass points to the transparent proxy class, and not to @class.
705  */
706 static MonoVTable *
707 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class)
708 {
709         MonoVTable *vt, *pvt;
710         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
711         MonoClass *k;
712         MonoClass *class = remote_class->proxy_class;
713
714         vt = mono_class_vtable (domain, class);
715         max_interface_id = vt->max_interface_id;
716
717         /* Calculate vtable space for extra interfaces */
718         for (j = 0; j < remote_class->interface_count; j++) {
719                 MonoClass* iclass = remote_class->interfaces[j];
720                 int method_count = iclass->method.count;
721         
722                 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
723                         continue;       /* interface implemented by the class */
724
725                 for (i = 0; i < iclass->interface_count; i++)
726                         method_count += iclass->interfaces[i]->method.count;
727
728                 extra_interface_vtsize += method_count * sizeof (gpointer);
729                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
730         }
731
732         vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
733
734         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
735
736         pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
737         memcpy (pvt, vt, vtsize);
738
739         pvt->klass = mono_defaults.transparent_proxy_class;
740
741         /* initialize vtable */
742         for (i = 0; i < class->vtable_size; ++i) {
743                 MonoMethod *cm;
744                     
745                 if ((cm = class->vtable [i]))
746                         pvt->vtable [i] = arch_create_remoting_trampoline (cm);
747         }
748
749         if (class->flags & TYPE_ATTRIBUTE_ABSTRACT)
750         {
751                 /* create trampolines for abstract methods */
752                 for (k = class; k; k = k->parent) {
753                         for (i = 0; i < k->method.count; i++) {
754                                 int slot = k->methods [i]->slot;
755                                 if (!pvt->vtable [slot]) 
756                                         pvt->vtable [slot] = arch_create_remoting_trampoline (k->methods[i]);
757                         }
758                 }
759         }
760
761         pvt->max_interface_id = max_interface_id;
762         pvt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
763                         sizeof (gpointer) * (max_interface_id + 1));
764
765         /* initialize interface offsets */
766         for (i = 0; i <= class->max_interface_id; ++i) {
767                 int slot = class->interface_offsets [i];
768                 if (slot >= 0)
769                         pvt->interface_offsets [i] = &(pvt->vtable [slot]);
770         }
771
772         if (remote_class->interface_count > 0)
773         {
774                 int slot = class->vtable_size;
775                 MonoClass* interf;
776                 MonoClass* iclass;
777                 int n;
778
779                 /* Create trampolines for the methods of the interfaces */
780                 for (n = 0; n < remote_class->interface_count; n++) 
781                 {
782                         iclass = remote_class->interfaces[n];
783                         if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
784                                 continue;       /* interface implemented by the class */
785                 
786                         i = -1;
787                         interf = iclass;
788                         do {
789                                 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
790         
791                                 for (j = 0; j < interf->method.count; ++j) {
792                                         MonoMethod *cm = interf->methods [j];
793                                         pvt->vtable [slot + j] = arch_create_remoting_trampoline (cm);
794                                 }
795                                 slot += interf->method.count;
796                                 if (++i < iclass->interface_count) interf = iclass->interfaces[i];
797                                 else interf = NULL;
798                                 
799                         } while (interf);
800                 }
801         }
802
803         return pvt;
804 }
805
806 /**
807  * mono_remote_class:
808  * @domain: the application domain
809  * @class_name: name of the remote class
810  *
811  * Creates and initializes a MonoRemoteClass object for a remote type. 
812  * 
813  */
814 MonoRemoteClass*
815 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
816 {
817         MonoRemoteClass *rc;
818
819         mono_domain_lock (domain);
820         rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class_name);
821
822         if (rc) {
823                 mono_domain_unlock (domain);
824                 return rc;
825         }
826
827         rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
828         rc->vtable = NULL;
829         rc->interface_count = 0;
830         rc->interfaces = NULL;
831         rc->proxy_class = mono_defaults.marshalbyrefobject_class;
832         rc->proxy_class_name = mono_string_to_utf8 (class_name);
833
834         mono_g_hash_table_insert (domain->proxy_vtable_hash, class_name, rc);
835         mono_upgrade_remote_class (domain, rc, proxy_class);
836
837         if (rc->vtable == NULL)
838                 rc->vtable = mono_class_proxy_vtable (domain, rc);
839
840         mono_domain_unlock (domain);
841
842         return rc;
843 }
844
845 static void
846 extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
847 {
848         /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
849
850         int current_size = ((remote_class->interface_count / 5) + 1) * 5;
851         remote_class->interface_count += amount;
852
853         if (remote_class->interface_count > current_size || remote_class->interfaces == NULL) 
854         {
855                 int new_size = ((remote_class->interface_count / 5) + 1) * 5;
856                 MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
857         
858                 if (remote_class->interfaces != NULL)
859                         memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
860                 
861                 remote_class->interfaces = new_array;
862         }
863 }
864
865
866 /**
867  * mono_upgrade_remote_class:
868  * @domain: the application domain
869  * @remote_class: the remote class
870  * @klass: class to which the remote class can be casted.
871  *
872  * Updates the vtable of the remote class by adding the necessary method slots
873  * and interface offsets so it can be safely casted to klass. klass can be a
874  * class or an interface.
875  */
876 void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
877 {
878         gboolean redo_vtable;
879
880         mono_domain_lock (domain);
881
882         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
883                 int i;
884                 redo_vtable = TRUE;
885                 for (i = 0; i < remote_class->interface_count; i++)
886                         if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
887                                 
888                 if (redo_vtable) {
889                         extend_interface_array (domain, remote_class, 1);
890                         remote_class->interfaces [remote_class->interface_count-1] = klass;
891                 }
892         }
893         else {
894                 redo_vtable = (remote_class->proxy_class != klass);
895                 remote_class->proxy_class = klass;
896         }
897
898         if (redo_vtable)
899                 remote_class->vtable = mono_class_proxy_vtable (domain, remote_class);
900 /*
901         int n;
902         printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
903         
904         for (n=0; n<remote_class->interface_count; n++)
905                 printf ("  I:%s\n", remote_class->interfaces[n]->name);
906 */
907
908         mono_domain_unlock (domain);
909 }
910
911 /**
912  * mono_object_get_virtual_method:
913  *
914  * Retrieve the MonoMethod that would be called on obj if obj is passed as
915  * the instance of a callvirt of method.
916  */
917 MonoMethod*
918 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) {
919         MonoClass *klass;
920         MonoMethod **vtable;
921         gboolean is_proxy;
922         MonoMethod *res = NULL;
923
924         klass = mono_object_class (obj);
925         if (klass == mono_defaults.transparent_proxy_class) {
926                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
927                 is_proxy = TRUE;
928         } else {
929                 is_proxy = FALSE;
930         }
931
932         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
933                         return method;
934
935         vtable = klass->vtable;
936
937         /* check method->slot is a valid index: perform isinstance? */
938         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
939                 if (!is_proxy)
940                         res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
941         } else {
942                 if (method->slot != -1)
943                         res = vtable [method->slot];
944         }
945
946         if (is_proxy) {
947                 if (!res) res = method;   /* It may be an interface or abstract class method */
948                 res = mono_marshal_get_remoting_invoke (res);
949         }
950
951         g_assert (res);
952         
953         return res;
954 }
955
956 static MonoObject*
957 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
958 {
959         g_error ("runtime invoke called on uninitialized runtime");
960         return NULL;
961 }
962
963 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
964
965 /**
966  * mono_runtime_invoke:
967  *
968  * Invokes the method represented by `method' on the object `obj'.
969  *
970  * obj is the 'this' pointer, it should be NULL for static
971  * methods, a MonoObject* for object instances and a pointer to
972  * the value type for value types.
973  *
974  * The params array contains the arguments to the method with the
975  * same convention: MonoObject* pointers for object instances and
976  * pointers to the value type otherwise. 
977  * 
978  * From unmanaged code you'll usually use the
979  * mono_runtime_invoke() variant.
980  *
981  * Note that this function doesn't handle virtual methods for
982  * you, it will exec the exact method you pass: we still need to
983  * expose a function to lookup the derived class implementation
984  * of a virtual method (there are examples of this in the code,
985  * though).
986  * 
987  * You can pass NULL as the exc argument if you don't want to
988  * catch exceptions, otherwise, *exc will be set to the exception
989  * thrown, if any.  if an exception is thrown, you can't use the
990  * MonoObject* result from the function.
991  * 
992  * If the method returns a value type, it is boxed in an object
993  * reference.
994  */
995 MonoObject*
996 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
997 {
998         return default_mono_runtime_invoke (method, obj, params, exc);
999 }
1000
1001 static void
1002 set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
1003         int t;
1004         if (type->byref) {
1005                 gpointer *p = (gpointer*)dest;
1006                 *p = value;
1007                 return;
1008         }
1009         t = type->type;
1010 handle_enum:
1011         switch (t) {
1012         case MONO_TYPE_BOOLEAN:
1013         case MONO_TYPE_I1:
1014         case MONO_TYPE_U1: {
1015                 guint8 *p = (guint8*)dest;
1016                 *p = *(guint8*)value;
1017                 return;
1018         }
1019         case MONO_TYPE_I2:
1020         case MONO_TYPE_U2:
1021         case MONO_TYPE_CHAR: {
1022                 guint16 *p = (guint16*)dest;
1023                 *p = *(guint16*)value;
1024                 return;
1025         }
1026 #if SIZEOF_VOID_P == 4
1027         case MONO_TYPE_I:
1028         case MONO_TYPE_U:
1029 #endif
1030         case MONO_TYPE_I4:
1031         case MONO_TYPE_U4: {
1032                 gint32 *p = (gint32*)dest;
1033                 *p = *(gint32*)value;
1034                 return;
1035         }
1036 #if SIZEOF_VOID_P == 8
1037         case MONO_TYPE_I:
1038         case MONO_TYPE_U:
1039 #endif
1040         case MONO_TYPE_I8:
1041         case MONO_TYPE_U8: {
1042                 gint64 *p = (gint64*)dest;
1043                 *p = *(gint64*)value;
1044                 return;
1045         }
1046         case MONO_TYPE_R4: {
1047                 float *p = (float*)dest;
1048                 *p = *(float*)value;
1049                 return;
1050         }
1051         case MONO_TYPE_R8: {
1052                 double *p = (double*)dest;
1053                 *p = *(double*)value;
1054                 return;
1055         }
1056         case MONO_TYPE_STRING:
1057         case MONO_TYPE_SZARRAY:
1058         case MONO_TYPE_CLASS:
1059         case MONO_TYPE_OBJECT:
1060         case MONO_TYPE_ARRAY:
1061         case MONO_TYPE_PTR: {
1062                 gpointer *p = (gpointer*)dest;
1063                 *p = deref_pointer? *(gpointer*)value: value;
1064                 return;
1065         }
1066         case MONO_TYPE_VALUETYPE:
1067                 if (type->data.klass->enumtype) {
1068                         t = type->data.klass->enum_basetype->type;
1069                         goto handle_enum;
1070                 } else {
1071                         int size;
1072                         size = mono_class_value_size (type->data.klass, NULL);
1073                         memcpy (dest, value, size);
1074                 }
1075                 return;
1076         default:
1077                 g_warning ("got type %x", type->type);
1078                 g_assert_not_reached ();
1079         }
1080 }
1081
1082 void
1083 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1084 {
1085         void *dest;
1086
1087         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1088
1089         dest = (char*)obj + field->offset;
1090         set_value (field->type, dest, value, FALSE);
1091 }
1092
1093 void
1094 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1095 {
1096         void *dest;
1097
1098         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1099
1100         dest = (char*)vt->data + field->offset;
1101         set_value (field->type, dest, value, FALSE);
1102 }
1103
1104 void
1105 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1106 {
1107         void *src;
1108
1109         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1110
1111         src = (char*)obj + field->offset;
1112         set_value (field->type, value, src, TRUE);
1113 }
1114
1115 MonoObject *
1116 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1117 {       
1118         MonoObject *o;
1119         MonoClass *klass;
1120         MonoVTable *vtable = NULL;
1121         gchar *v;
1122         gboolean is_static = FALSE;
1123         gboolean is_ref = FALSE;
1124
1125         switch (field->type->type) {
1126         case MONO_TYPE_STRING:
1127         case MONO_TYPE_OBJECT:
1128         case MONO_TYPE_CLASS:
1129         case MONO_TYPE_ARRAY:
1130         case MONO_TYPE_SZARRAY:
1131                 is_ref = TRUE;
1132                 break;
1133         case MONO_TYPE_U1:
1134         case MONO_TYPE_I1:
1135         case MONO_TYPE_BOOLEAN:
1136         case MONO_TYPE_U2:
1137         case MONO_TYPE_I2:
1138         case MONO_TYPE_CHAR:
1139         case MONO_TYPE_U:
1140         case MONO_TYPE_I:
1141         case MONO_TYPE_U4:
1142         case MONO_TYPE_I4:
1143         case MONO_TYPE_R4:
1144         case MONO_TYPE_U8:
1145         case MONO_TYPE_I8:
1146         case MONO_TYPE_R8:
1147         case MONO_TYPE_VALUETYPE:
1148                 is_ref = field->type->byref;
1149                 break;
1150         default:
1151                 g_error ("type 0x%x not handled in "
1152                          "mono_field_get_value_object", field->type->type);
1153                 return NULL;
1154         }
1155
1156         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1157                 is_static = TRUE;
1158                 vtable = mono_class_vtable (domain, field->parent);
1159                 if (!vtable->initialized)
1160                         mono_runtime_class_init (vtable);
1161         }
1162         
1163         if (is_ref) {
1164                 if (is_static) {
1165                         mono_field_static_get_value (vtable, field, &o);
1166                 } else {
1167                         mono_field_get_value (obj, field, &o);
1168                 }
1169                 return o;
1170         }
1171
1172         /* boxed value type */
1173         klass = mono_class_from_mono_type (field->type);
1174         o = mono_object_new (domain, klass);
1175         v = ((gchar *) o) + sizeof (MonoObject);
1176         if (is_static) {
1177                 mono_field_static_get_value (vtable, field, v);
1178         } else {
1179                 mono_field_get_value (obj, field, v);
1180         }
1181
1182         return o;
1183 }
1184
1185
1186 void
1187 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1188 {
1189         void *src;
1190
1191         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1192
1193         src = (char*)vt->data + field->offset;
1194         set_value (field->type, value, src, TRUE);
1195 }
1196
1197 void
1198 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1199 {
1200         default_mono_runtime_invoke (prop->set, obj, params, exc);
1201 }
1202
1203 MonoObject*
1204 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1205 {
1206         return default_mono_runtime_invoke (prop->get, obj, params, exc);
1207 }
1208
1209
1210 MonoMethod *
1211 mono_get_delegate_invoke (MonoClass *klass)
1212 {
1213         MonoMethod *im;
1214         int i;
1215
1216         im = NULL;
1217
1218         for (i = 0; i < klass->method.count; ++i) {
1219                 if (klass->methods [i]->name[0] == 'I' && 
1220                     !strcmp ("Invoke", klass->methods [i]->name)) {
1221                         im = klass->methods [i];
1222                 }
1223         }
1224
1225         g_assert (im);
1226
1227         return im;
1228 }
1229
1230 MonoObject*
1231 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1232 {
1233         MonoMethod *im;
1234
1235         im = mono_get_delegate_invoke (delegate->vtable->klass);
1236         g_assert (im);
1237
1238         return mono_runtime_invoke (im, delegate, params, exc);
1239 }
1240
1241 static MonoArray* main_args;
1242
1243 MonoArray*
1244 mono_runtime_get_main_args (void)
1245 {
1246         return main_args;
1247 }
1248
1249 static void
1250 fire_process_exit_event (void)
1251 {
1252         MonoClassField *field;
1253         MonoDomain *domain = mono_domain_get ();
1254         gpointer pa [2];
1255         MonoObject *delegate, *exc;
1256         
1257         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1258         g_assert (field);
1259
1260         if (domain != mono_get_root_domain ())
1261                 return;
1262
1263         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1264         if (delegate == NULL)
1265                 return;
1266
1267         pa [0] = domain;
1268         pa [1] = NULL;
1269         mono_runtime_delegate_invoke (delegate, pa, &exc);
1270 }
1271
1272 /*
1273  * Execute a standard Main() method (argc/argv contains the
1274  * executable name). This method also sets the command line argument value
1275  * needed by System.Environment.
1276  */
1277 int
1278 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1279                        MonoObject **exc)
1280 {
1281         int i;
1282         MonoArray *args = NULL;
1283         MonoDomain *domain = mono_domain_get ();
1284         gchar *utf8_fullpath;
1285         int result;
1286
1287         main_thread = mono_thread_current ();
1288
1289         main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1290
1291         if (!g_path_is_absolute (argv [0])) {
1292                 gchar *basename = g_path_get_basename (argv [0]);
1293                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1294                                                     basename,
1295                                                     NULL);
1296
1297                 utf8_fullpath = mono_utf8_from_external (fullpath);
1298                 if(utf8_fullpath == NULL) {
1299                         /* Printing the arg text will cause glib to
1300                          * whinge about "Invalid UTF-8", but at least
1301                          * its relevant, and shows the problem text
1302                          * string.
1303                          */
1304                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1305                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1306                         exit (-1);
1307                 }
1308
1309                 g_free (fullpath);
1310                 g_free (basename);
1311         } else {
1312                 utf8_fullpath = mono_utf8_from_external (argv[0]);
1313                 if(utf8_fullpath == NULL) {
1314                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1315                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1316                         exit (-1);
1317                 }
1318         }
1319                 
1320         mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
1321         g_free (utf8_fullpath);
1322
1323         for (i = 1; i < argc; ++i) {
1324                 gchar *utf8_arg;
1325                 MonoString *arg;
1326
1327                 utf8_arg=mono_utf8_from_external (argv[i]);
1328                 if(utf8_arg==NULL) {
1329                         /* Ditto the comment about Invalid UTF-8 here */
1330                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1331                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1332                         exit (-1);
1333                 }
1334                 
1335                 arg = mono_string_new (domain, utf8_arg);
1336                 mono_array_set (main_args, gpointer, i, arg);
1337         }
1338         argc--;
1339         argv++;
1340         if (method->signature->param_count) {
1341                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1342                 for (i = 0; i < argc; ++i) {
1343                         /* The encodings should all work, given that
1344                          * we've checked all these args for the
1345                          * main_args array.
1346                          */
1347                         MonoString *arg = mono_string_new (domain, mono_utf8_from_external (argv [i]));
1348                         mono_array_set (args, gpointer, i, arg);
1349                 }
1350         } else {
1351                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1352         }
1353         
1354         mono_assembly_set_main (method->klass->image->assembly);
1355
1356         result = mono_runtime_exec_main (method, args, exc);
1357         fire_process_exit_event ();
1358         return result;
1359 }
1360
1361 /* Used in mono_unhandled_exception */
1362 static MonoObject *
1363 create_unhandled_exception_eventargs (MonoObject *exc)
1364 {
1365         MonoClass *klass;
1366         gpointer args [2];
1367         MonoMethod *method = NULL;
1368         MonoBoolean is_terminating = TRUE;
1369         MonoObject *obj;
1370         gint i;
1371
1372         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1373         g_assert (klass);
1374
1375         mono_class_init (klass);
1376
1377         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1378         for (i = 0; i < klass->method.count; ++i) {
1379                 method = klass->methods [i];
1380                 if (!strcmp (".ctor", method->name) &&
1381                     method->signature->param_count == 2 &&
1382                     method->flags & METHOD_ATTRIBUTE_PUBLIC)
1383                         break;
1384                 method = NULL;
1385         }
1386
1387         g_assert (method);
1388
1389         args [0] = exc;
1390         args [1] = &is_terminating;
1391
1392         obj = mono_object_new (mono_domain_get (), klass);
1393         mono_runtime_invoke (method, obj, args, NULL);
1394
1395         return obj;
1396 }
1397
1398 /*
1399  * We call this function when we detect an unhandled exception
1400  * in the default domain.
1401  * It invokes the * UnhandledException event in AppDomain or prints
1402  * a warning to the console 
1403  */
1404 void
1405 mono_unhandled_exception (MonoObject *exc)
1406 {
1407         MonoDomain *domain = mono_domain_get ();
1408         MonoClassField *field;
1409         MonoObject *delegate;
1410         
1411         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
1412                                              "UnhandledException");
1413         g_assert (field);
1414
1415         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1416                 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1417
1418                 /* set exitcode only in the main thread */
1419                 if (mono_thread_current () == main_thread)
1420                         mono_environment_exitcode_set (1);
1421                 if (domain != mono_get_root_domain () || !delegate) {
1422                         mono_print_unhandled_exception (exc);
1423                 } else {
1424                         MonoObject *e = NULL;
1425                         gpointer pa [2];
1426
1427                         pa [0] = domain->domain;
1428                         pa [1] = create_unhandled_exception_eventargs (exc);
1429                         mono_runtime_delegate_invoke (delegate, pa, &e);
1430                         
1431                         if (e) {
1432                                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1433                                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1434                                 g_free (msg);
1435                         }
1436                 }
1437         }
1438 }
1439
1440 /*
1441  * Launch a new thread to start all setup that requires managed code
1442  * to be executed.
1443  *
1444  * main_func is called back from the thread with main_args as the
1445  * parameter.  The callback function is expected to start Main()
1446  * eventually.  This function then waits for all managed threads to
1447  * finish.
1448  */
1449 void
1450 mono_runtime_exec_managed_code (MonoDomain *domain,
1451                                 MonoMainThreadFunc main_func,
1452                                 gpointer main_args)
1453 {
1454         mono_thread_create (domain, main_func, main_args);
1455
1456         mono_thread_manage ();
1457 }
1458
1459 /*
1460  * Execute a standard Main() method (args doesn't contain the
1461  * executable name).
1462  */
1463 int
1464 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1465 {
1466         MonoDomain *domain;
1467         gpointer pa [1];
1468         int rval;
1469
1470         g_assert (args);
1471
1472         pa [0] = args;
1473
1474         domain = mono_object_domain (args);
1475         if (!domain->entry_assembly) {
1476                 gchar *str;
1477                 gchar *config_suffix;
1478                 MonoAssembly *assembly;
1479
1480                 assembly = method->klass->image->assembly;
1481                 domain->entry_assembly = assembly;
1482                 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1483
1484                 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1485                 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1486                 g_free (config_suffix);
1487                 domain->setup->configuration_file = mono_string_new (domain, str);
1488                 g_free (str);
1489         }
1490
1491         /* FIXME: check signature of method */
1492         if (method->signature->ret->type == MONO_TYPE_I4) {
1493                 MonoObject *res;
1494                 res = mono_runtime_invoke (method, NULL, pa, exc);
1495                 if (!exc || !*exc)
1496                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1497                 else
1498                         rval = -1;
1499
1500                 mono_environment_exitcode_set (rval);
1501         } else {
1502                 mono_runtime_invoke (method, NULL, pa, exc);
1503                 if (!exc || !*exc)
1504                         rval = 0;
1505                 else {
1506                         /* If the return type of Main is void, only
1507                          * set the exitcode if an exception was thrown
1508                          * (we don't want to blow away an
1509                          * explicitly-set exit code)
1510                          */
1511                         rval = -1;
1512                         mono_environment_exitcode_set (rval);
1513                 }
1514         }
1515
1516         return rval;
1517 }
1518
1519 void
1520 mono_install_runtime_invoke (MonoInvokeFunc func)
1521 {
1522         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1523 }
1524
1525 /**
1526  * mono_runtime_invoke:
1527  *
1528  * Invokes the method represented by `method' on the object `obj'.
1529  *
1530  * obj is the 'this' pointer, it should be NULL for static
1531  * methods, a MonoObject* for object instances and a pointer to
1532  * the value type for value types.
1533  *
1534  * The params array contains the arguments to the method with the
1535  * same convention: MonoObject* pointers for object instances and
1536  * pointers to the value type otherwise. The _invoke_array
1537  * variant takes a C# object[] as the params argument (MonoArray
1538  * *params): in this case the value types are boxed inside the
1539  * respective reference representation.
1540  * 
1541  * From unmanaged code you'll usually use the
1542  * mono_runtime_invoke() variant.
1543  *
1544  * Note that this function doesn't handle virtual methods for
1545  * you, it will exec the exact method you pass: we still need to
1546  * expose a function to lookup the derived class implementation
1547  * of a virtual method (there are examples of this in the code,
1548  * though).
1549  * 
1550  * You can pass NULL as the exc argument if you don't want to
1551  * catch exceptions, otherwise, *exc will be set to the exception
1552  * thrown, if any.  if an exception is thrown, you can't use the
1553  * MonoObject* result from the function.
1554  * 
1555  * If the method returns a value type, it is boxed in an object
1556  * reference.
1557  */
1558 MonoObject*
1559 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1560                            MonoObject **exc)
1561 {
1562         MonoMethodSignature *sig = method->signature;
1563         gpointer *pa = NULL;
1564         int i;
1565                 
1566         if (NULL != params) {
1567                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1568                 for (i = 0; i < mono_array_length (params); i++) {
1569                         if (sig->params [i]->byref) {
1570                                 /* nothing to do */
1571                         }
1572
1573                         switch (sig->params [i]->type) {
1574                         case MONO_TYPE_U1:
1575                         case MONO_TYPE_I1:
1576                         case MONO_TYPE_BOOLEAN:
1577                         case MONO_TYPE_U2:
1578                         case MONO_TYPE_I2:
1579                         case MONO_TYPE_CHAR:
1580                         case MONO_TYPE_U:
1581                         case MONO_TYPE_I:
1582                         case MONO_TYPE_U4:
1583                         case MONO_TYPE_I4:
1584                         case MONO_TYPE_U8:
1585                         case MONO_TYPE_I8:
1586                         case MONO_TYPE_R4:
1587                         case MONO_TYPE_R8:
1588                         case MONO_TYPE_VALUETYPE:
1589                                 if (sig->params [i]->byref) {
1590                                         /* MS seems to create the objects if a null is passed in */
1591                                         if (! ((gpointer *)params->vector)[i])
1592                                                 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1593                                 }
1594                                 else
1595                                         g_assert (((gpointer*)params->vector) [i]);
1596                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1597                                 break;
1598                         case MONO_TYPE_STRING:
1599                         case MONO_TYPE_OBJECT:
1600                         case MONO_TYPE_CLASS:
1601                         case MONO_TYPE_ARRAY:
1602                         case MONO_TYPE_SZARRAY:
1603                                 if (sig->params [i]->byref)
1604                                         pa [i] = &(((gpointer *)params->vector)[i]);
1605                                 else
1606                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
1607                                 break;
1608                         default:
1609                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1610                         }
1611                 }
1612         }
1613
1614         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1615                 void *o = obj;
1616                 if (!obj) {
1617                         obj = mono_object_new (mono_domain_get (), method->klass);
1618                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1619                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1620                         }
1621                         if (method->klass->valuetype)
1622                                 o = mono_object_unbox (obj);
1623                         else
1624                                 o = obj;
1625                 }
1626                 mono_runtime_invoke (method, o, pa, exc);
1627                 return obj;
1628         } else {
1629                 /* obj must be already unboxed if needed */
1630                 return mono_runtime_invoke (method, obj, pa, exc);
1631         }
1632 }
1633
1634 static void
1635 out_of_memory (size_t size)
1636 {
1637         /* 
1638          * we could allocate at program startup some memory that we could release 
1639          * back to the system at this point if we're really low on memory (ie, size is
1640          * lower than the memory we set apart)
1641          */
1642         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1643 }
1644
1645 /**
1646  * mono_object_allocate:
1647  * @size: number of bytes to allocate
1648  *
1649  * This is a very simplistic routine until we have our GC-aware
1650  * memory allocator. 
1651  *
1652  * Returns: an allocated object of size @size, or NULL on failure.
1653  */
1654 static inline void *
1655 mono_object_allocate (size_t size)
1656 {
1657 #if HAVE_BOEHM_GC
1658         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1659         void *o = GC_MALLOC (size);
1660 #else
1661         void *o = calloc (1, size);
1662 #endif
1663         mono_stats.new_object_count++;
1664
1665         if (!o)
1666                 out_of_memory (size);
1667         return o;
1668 }
1669
1670 #if CREATION_SPEEDUP
1671 static inline void *
1672 mono_object_allocate_spec (size_t size, void *gcdescr)
1673 {
1674         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1675         void *o = GC_GCJ_MALLOC (size, gcdescr);
1676         mono_stats.new_object_count++;
1677
1678         if (!o)
1679                 out_of_memory (size);
1680         return o;
1681 }
1682 #endif
1683
1684 /**
1685  * mono_object_new:
1686  * @klass: the class of the object that we want to create
1687  *
1688  * Returns a newly created object whose definition is
1689  * looked up using @klass.   This will not invoke any constructors, 
1690  * so the consumer of this routine has to invoke any constructors on
1691  * its own to initialize the object.
1692  */
1693 MonoObject *
1694 mono_object_new (MonoDomain *domain, MonoClass *klass)
1695 {
1696         MONO_ARCH_SAVE_REGS;
1697         return mono_object_new_specific (mono_class_vtable (domain, klass));
1698 }
1699
1700 /**
1701  * mono_object_new_specific:
1702  * @vtable: the vtable of the object that we want to create
1703  *
1704  * Returns: A newly created object with class and domain specified
1705  * by @vtable
1706  */
1707 MonoObject *
1708 mono_object_new_specific (MonoVTable *vtable)
1709 {
1710         MonoObject *o;
1711
1712         MONO_ARCH_SAVE_REGS;
1713         
1714         if (vtable->remote)
1715         {
1716                 gpointer pa [1];
1717                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1718
1719                 if (im == NULL) {
1720                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1721                         int i;
1722
1723                         if (!klass->inited)
1724                                 mono_class_init (klass);
1725
1726                         for (i = 0; i < klass->method.count; ++i) {
1727                                 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1728                                         klass->methods [i]->signature->param_count == 1) {
1729                                         im = klass->methods [i];
1730                                         break;
1731                                 }
1732                         }
1733                         g_assert (im);
1734                         vtable->domain->create_proxy_for_type_method = im;
1735                 }
1736         
1737                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1738
1739                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
1740                 if (o != NULL) return o;
1741         }
1742
1743         return mono_object_new_alloc_specific (vtable);
1744 }
1745
1746 MonoObject *
1747 mono_object_new_fast (MonoVTable *vtable)
1748 {
1749         MonoObject *o;
1750         MONO_ARCH_SAVE_REGS;
1751
1752 #if CREATION_SPEEDUP
1753         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1754                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1755         } else {
1756 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1757                 o = mono_object_allocate (vtable->klass->instance_size);
1758                 o->vtable = vtable;
1759         }
1760 #else
1761         o = mono_object_allocate (vtable->klass->instance_size);
1762         o->vtable = vtable;
1763 #endif
1764         return o;
1765 }
1766
1767 MonoObject *
1768 mono_object_new_alloc_specific (MonoVTable *vtable)
1769 {
1770         MonoObject *o;
1771
1772 #if CREATION_SPEEDUP
1773         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1774                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1775         } else {
1776 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1777                 o = mono_object_allocate (vtable->klass->instance_size);
1778                 o->vtable = vtable;
1779         }
1780 #else
1781         o = mono_object_allocate (vtable->klass->instance_size);
1782         o->vtable = vtable;
1783 #endif
1784         if (vtable->klass->has_finalize)
1785                 mono_object_register_finalizer (o);
1786         
1787         mono_profiler_allocation (o, vtable->klass);
1788         return o;
1789 }
1790
1791 /**
1792  * mono_object_new_from_token:
1793  * @image: Context where the type_token is hosted
1794  * @token: a token of the type that we want to create
1795  *
1796  * Returns: A newly created object whose definition is
1797  * looked up using @token in the @image image
1798  */
1799 MonoObject *
1800 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
1801 {
1802         MonoClass *class;
1803
1804         class = mono_class_get (image, token);
1805
1806         return mono_object_new (domain, class);
1807 }
1808
1809
1810 /**
1811  * mono_object_clone:
1812  * @obj: the object to clone
1813  *
1814  * Returns: A newly created object who is a shallow copy of @obj
1815  */
1816 MonoObject *
1817 mono_object_clone (MonoObject *obj)
1818 {
1819         MonoObject *o;
1820         int size;
1821
1822         size = obj->vtable->klass->instance_size;
1823         o = mono_object_allocate (size);
1824         mono_profiler_allocation (o, obj->vtable->klass);
1825
1826         memcpy (o, obj, size);
1827
1828         if (obj->vtable->klass->has_finalize)
1829                 mono_object_register_finalizer (o);
1830         return o;
1831 }
1832
1833 /**
1834  * mono_array_clone:
1835  * @array: the array to clone
1836  *
1837  * Returns: A newly created array who is a shallow copy of @array
1838  */
1839 MonoArray*
1840 mono_array_clone (MonoArray *array)
1841 {
1842         MonoArray *o;
1843         int size, i;
1844         guint32 *sizes;
1845         MonoClass *klass = array->obj.vtable->klass;
1846
1847         MONO_ARCH_SAVE_REGS;
1848
1849         if (array->bounds == NULL) {
1850                 size = mono_array_length (array);
1851                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1852                                          klass, &size, NULL);
1853
1854                 size *= mono_array_element_size (klass);
1855                 memcpy (o, array, sizeof (MonoArray) + size);
1856
1857                 return o;
1858         }
1859         
1860         sizes = alloca (klass->rank * sizeof(guint32) * 2);
1861         size = mono_array_element_size (klass);
1862         for (i = 0; i < klass->rank; ++i) {
1863                 sizes [i] = array->bounds [i].length;
1864                 size *= array->bounds [i].length;
1865                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1866         }
1867         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
1868                                  klass, sizes, sizes + klass->rank);
1869         memcpy (o, array, sizeof(MonoArray) + size);
1870
1871         return o;
1872 }
1873
1874 /* helper macros to check for overflow when calculating the size of arrays */
1875 #define MYGUINT32_MAX 4294967295U
1876 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1877         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1878 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1879         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1880         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1881
1882 /*
1883  * mono_array_new_full:
1884  * @domain: domain where the object is created
1885  * @array_class: array class
1886  * @lengths: lengths for each dimension in the array
1887  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1888  *
1889  * This routine creates a new array objects with the given dimensions,
1890  * lower bounds and type.
1891  */
1892 MonoArray*
1893 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
1894                      guint32 *lengths, guint32 *lower_bounds)
1895 {
1896         guint32 byte_len, len;
1897         MonoObject *o;
1898         MonoArray *array;
1899         MonoArrayBounds *bounds;
1900         MonoVTable *vtable;
1901         int i;
1902
1903         if (!array_class->inited)
1904                 mono_class_init (array_class);
1905
1906         byte_len = mono_array_element_size (array_class);
1907         len = 1;
1908
1909         if (array_class->rank == 1 &&
1910             (lower_bounds == NULL || lower_bounds [0] == 0)) {
1911                 bounds = NULL;
1912                 len = lengths [0];
1913         } else {
1914         #if HAVE_BOEHM_GC
1915                 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1916         #else
1917                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1918         #endif
1919                 for (i = 0; i < array_class->rank; ++i) {
1920                         bounds [i].length = lengths [i];
1921                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1922                                 out_of_memory (MYGUINT32_MAX);
1923                         len *= lengths [i];
1924                 }
1925
1926                 if (lower_bounds)
1927                         for (i = 0; i < array_class->rank; ++i)
1928                                 bounds [i].lower_bound = lower_bounds [i];
1929         }
1930
1931         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1932                 out_of_memory (MYGUINT32_MAX);
1933         byte_len *= len;
1934         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1935                 out_of_memory (MYGUINT32_MAX);
1936         byte_len += sizeof (MonoArray);
1937         /* 
1938          * Following three lines almost taken from mono_object_new ():
1939          * they need to be kept in sync.
1940          */
1941         vtable = mono_class_vtable (domain, array_class);
1942 #if CREATION_SPEEDUP
1943         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1944                 o = mono_object_allocate_spec (byte_len, vtable);
1945         else {
1946                 o = mono_object_allocate (byte_len);
1947                 o->vtable = vtable;
1948         }
1949 #else
1950         o = mono_object_allocate (byte_len);
1951         o->vtable = vtable;
1952 #endif
1953
1954         array = (MonoArray*)o;
1955
1956         array->bounds = bounds;
1957         array->max_length = len;
1958
1959         mono_profiler_allocation (o, array_class);
1960
1961         return array;
1962 }
1963
1964 /*
1965  * mono_array_new:
1966  * @domain: domain where the object is created
1967  * @eclass: element class
1968  * @n: number of array elements
1969  *
1970  * This routine creates a new szarray with @n elements of type @eclass.
1971  */
1972 MonoArray *
1973 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1974 {
1975         MonoClass *ac;
1976
1977         MONO_ARCH_SAVE_REGS;
1978
1979         ac = mono_array_class_get (eclass, 1);
1980         g_assert (ac != NULL);
1981
1982         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1983 }
1984
1985 /*
1986  * mono_array_new_specific:
1987  * @vtable: a vtable in the appropriate domain for an initialized class
1988  * @n: number of array elements
1989  *
1990  * This routine is a fast alternative to mono_array_new() for code which
1991  * can be sure about the domain it operates in.
1992  */
1993 MonoArray *
1994 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1995 {
1996         MonoObject *o;
1997         MonoArray *ao;
1998         guint32 byte_len, elem_size;
1999
2000         MONO_ARCH_SAVE_REGS;
2001
2002         elem_size = mono_array_element_size (vtable->klass);
2003         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2004                 out_of_memory (MYGUINT32_MAX);
2005         byte_len = n * elem_size;
2006         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2007                 out_of_memory (MYGUINT32_MAX);
2008         byte_len += sizeof (MonoArray);
2009 #if CREATION_SPEEDUP
2010         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2011                 o = mono_object_allocate_spec (byte_len, vtable);
2012         } else {
2013 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2014                 o = mono_object_allocate (byte_len);
2015                 o->vtable = vtable;
2016         }
2017 #else
2018         o = mono_object_allocate (byte_len);
2019         o->vtable = vtable;
2020 #endif
2021
2022         ao = (MonoArray *)o;
2023         ao->bounds = NULL;
2024         ao->max_length = n;
2025         mono_profiler_allocation (o, vtable->klass);
2026
2027         return ao;
2028 }
2029
2030 /**
2031  * mono_string_new_utf16:
2032  * @text: a pointer to an utf16 string
2033  * @len: the length of the string
2034  *
2035  * Returns: A newly created string object which contains @text.
2036  */
2037 MonoString *
2038 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2039 {
2040         MonoString *s;
2041         
2042         s = mono_string_new_size (domain, len);
2043         g_assert (s != NULL);
2044
2045         memcpy (mono_string_chars (s), text, len * 2);
2046
2047         return s;
2048 }
2049
2050 /**
2051  * mono_string_new_size:
2052  * @text: a pointer to an utf16 string
2053  * @len: the length of the string
2054  *
2055  * Returns: A newly created string object of @len
2056  */
2057 MonoString *
2058 mono_string_new_size (MonoDomain *domain, gint32 len)
2059 {
2060         MonoString *s;
2061         MonoVTable *vtable;
2062         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2063
2064         /* overflow ? can't fit it, can't allocate it! */
2065         if (len > size)
2066                 out_of_memory (-1);
2067
2068         vtable = mono_class_vtable (domain, mono_defaults.string_class);
2069
2070 #if CREATION_SPEEDUP
2071         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2072                 s = mono_object_allocate_spec (size, vtable);
2073         else {
2074                 s = (MonoString*)mono_object_allocate (size);
2075                 s->object.vtable = vtable;
2076         }
2077 #else
2078         s = (MonoString*)mono_object_allocate (size);
2079         s->object.vtable = vtable;
2080 #endif
2081
2082         s->length = len;
2083         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2084
2085         return s;
2086 }
2087
2088 /*
2089  * mono_string_new_len:
2090  * @text: a pointer to an utf8 string
2091  * @length: number of bytes in @text to consider
2092  *
2093  * Returns: A newly created string object which contains @text.
2094  */
2095 MonoString*
2096 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2097 {
2098         GError *error = NULL;
2099         MonoString *o = NULL;
2100         guint16 *ut;
2101         glong items_written;
2102
2103         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2104
2105         if (!error)
2106                 o = mono_string_new_utf16 (domain, ut, items_written);
2107         else 
2108                 g_error_free (error);
2109
2110         g_free (ut);
2111
2112         return o;
2113 }
2114
2115 /**
2116  * mono_string_new:
2117  * @text: a pointer to an utf8 string
2118  *
2119  * Returns: A newly created string object which contains @text.
2120  */
2121 MonoString*
2122 mono_string_new (MonoDomain *domain, const char *text)
2123 {
2124         GError *error = NULL;
2125         MonoString *o = NULL;
2126         guint16 *ut;
2127         glong items_written;
2128         int l;
2129
2130         l = strlen (text);
2131         
2132         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2133
2134         if (!error)
2135                 o = mono_string_new_utf16 (domain, ut, items_written);
2136         else 
2137                 g_error_free (error);
2138
2139         g_free (ut);
2140
2141         return o;
2142 }
2143
2144 /*
2145  * mono_string_new_wrapper:
2146  * @text: pointer to utf8 characters.
2147  *
2148  * Helper function to create a string object from @text in the current domain.
2149  */
2150 MonoString*
2151 mono_string_new_wrapper (const char *text)
2152 {
2153         MonoDomain *domain = mono_domain_get ();
2154
2155         MONO_ARCH_SAVE_REGS;
2156
2157         if (text)
2158                 return mono_string_new (domain, text);
2159
2160         return NULL;
2161 }
2162
2163 /**
2164  * mono_value_box:
2165  * @class: the class of the value
2166  * @value: a pointer to the unboxed data
2167  *
2168  * Returns: A newly created object which contains @value.
2169  */
2170 MonoObject *
2171 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2172 {
2173         MonoObject *res;
2174         int size;
2175         MonoVTable *vtable;
2176
2177         g_assert (class->valuetype);
2178
2179         vtable = mono_class_vtable (domain, class);
2180         size = mono_class_instance_size (class);
2181         res = mono_object_allocate (size);
2182         res->vtable = vtable;
2183         mono_profiler_allocation (res, class);
2184
2185         size = size - sizeof (MonoObject);
2186
2187 #if NO_UNALIGNED_ACCESS
2188         memcpy ((char *)res + sizeof (MonoObject), value, size);
2189 #else
2190         switch (size) {
2191         case 1:
2192                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2193                 break;
2194         case 2:
2195                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2196                 break;
2197         case 4:
2198                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2199                 break;
2200         case 8:
2201                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2202                 break;
2203         default:
2204                 memcpy ((char *)res + sizeof (MonoObject), value, size);
2205         }
2206 #endif
2207         if (class->has_finalize)
2208                 mono_object_register_finalizer (res);
2209         return res;
2210 }
2211
2212 MonoDomain*
2213 mono_object_get_domain (MonoObject *obj)
2214 {
2215         return mono_object_domain (obj);
2216 }
2217
2218 MonoClass*
2219 mono_object_get_class (MonoObject *obj)
2220 {
2221         return mono_object_class (obj);
2222 }
2223
2224 gpointer
2225 mono_object_unbox (MonoObject *obj)
2226 {
2227         /* add assert for valuetypes? */
2228         g_assert (obj->vtable->klass->valuetype);
2229         return ((char*)obj) + sizeof (MonoObject);
2230 }
2231
2232 /**
2233  * mono_object_isinst:
2234  * @obj: an object
2235  * @klass: a pointer to a class 
2236  *
2237  * Returns: @obj if @obj is derived from @klass
2238  */
2239 MonoObject *
2240 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2241 {
2242         if (!klass->inited)
2243                 mono_class_init (klass);
2244
2245         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
2246                 return mono_object_isinst_mbyref (obj, klass);
2247
2248         if (!obj)
2249                 return NULL;
2250
2251         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2252 }
2253
2254 MonoObject *
2255 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2256 {
2257         MonoVTable *vt;
2258
2259         if (!obj)
2260                 return NULL;
2261
2262         vt = obj->vtable;
2263         
2264         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2265                 if ((klass->interface_id <= vt->max_interface_id) &&
2266                     (vt->interface_offsets [klass->interface_id] != 0))
2267                         return obj;
2268         }
2269         else {
2270                 MonoClass *oklass = vt->klass;
2271                 if ((oklass == mono_defaults.transparent_proxy_class))
2272                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2273         
2274                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2275                         return obj;
2276         }
2277
2278         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
2279         {
2280                 MonoDomain *domain = mono_domain_get ();
2281                 MonoObject *res;
2282                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2283                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2284                 MonoMethod *im = NULL;
2285                 gpointer pa [2];
2286                 int i;
2287         
2288                 for (i = 0; i < rpklass->method.count; ++i) {
2289                         if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2290                                 im = rpklass->methods [i];
2291                                 break;
2292                         }
2293                 }
2294         
2295                 im = mono_object_get_virtual_method (rp, im);
2296                 g_assert (im);
2297         
2298                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2299                 pa [1] = obj;
2300
2301                 res = mono_runtime_invoke (im, rp, pa, NULL);
2302         
2303                 if (*(MonoBoolean *) mono_object_unbox(res)) {
2304                         /* Update the vtable of the remote type, so it can safely cast to this new type */
2305                         mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2306                         obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2307                         return obj;
2308                 }
2309         }
2310
2311         return NULL;
2312 }
2313
2314 /**
2315  * mono_object_castclass_mbyref:
2316  * @obj: an object
2317  * @klass: a pointer to a class 
2318  *
2319  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2320  */
2321 MonoObject *
2322 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2323 {
2324         if (!obj) return NULL;
2325         if (mono_object_isinst_mbyref (obj, klass)) return obj;
2326                 
2327         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2328                                                         "System",
2329                                                         "InvalidCastException"));
2330         return NULL;
2331 }
2332
2333 typedef struct {
2334         MonoDomain *orig_domain;
2335         char *ins;
2336         MonoString *res;
2337 } LDStrInfo;
2338
2339 static void
2340 str_lookup (MonoDomain *domain, gpointer user_data)
2341 {
2342         LDStrInfo *info = user_data;
2343         if (info->res || domain == info->orig_domain)
2344                 return;
2345         mono_domain_lock (domain);
2346         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2347         mono_domain_unlock (domain);
2348 }
2349
2350 static MonoString*
2351 mono_string_is_interned_lookup (MonoString *str, int insert)
2352 {
2353         MonoGHashTable *ldstr_table;
2354         MonoString *res;
2355         MonoDomain *domain;
2356         char *ins = g_malloc (4 + str->length * 2);
2357         char *p;
2358         
2359         /* Encode the length */
2360         /* Same code as in mono_image_insert_string () */
2361         p = ins;
2362         mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2363
2364         /*
2365          * ins is stored in the hash table as a key and needs to have the same
2366          * representation as in the metadata: we swap the character bytes on big
2367          * endian boxes.
2368          */
2369 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2370         {
2371                 int i;
2372                 char *p2 = (char *)mono_string_chars (str);
2373                 for (i = 0; i < str->length; ++i) {
2374                         *p++ = p2 [1];
2375                         *p++ = p2 [0];
2376                         p2 += 2;
2377                 }
2378         }
2379 #else
2380         memcpy (p, mono_string_chars (str), str->length * 2);
2381 #endif
2382         domain = ((MonoObject *)str)->vtable->domain;
2383         ldstr_table = domain->ldstr_table;
2384         mono_domain_lock (domain);
2385         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2386                 mono_domain_unlock (domain);
2387                 g_free (ins);
2388                 return res;
2389         }
2390         if (insert) {
2391                 mono_g_hash_table_insert (ldstr_table, ins, str);
2392                 mono_domain_unlock (domain);
2393                 return str;
2394         } else {
2395                 LDStrInfo ldstr_info;
2396                 ldstr_info.orig_domain = domain;
2397                 ldstr_info.ins = ins;
2398                 ldstr_info.res = NULL;
2399
2400                 mono_domain_foreach (str_lookup, &ldstr_info);
2401                 if (ldstr_info.res) {
2402                         /* 
2403                          * the string was already interned in some other domain:
2404                          * intern it in the current one as well.
2405                          */
2406                         mono_g_hash_table_insert (ldstr_table, ins, str);
2407                         mono_domain_unlock (domain);
2408                         return str;
2409                 }
2410         }
2411         mono_domain_unlock (domain);
2412         g_free (ins);
2413         return NULL;
2414 }
2415
2416 MonoString*
2417 mono_string_is_interned (MonoString *o)
2418 {
2419         return mono_string_is_interned_lookup (o, FALSE);
2420 }
2421
2422 MonoString*
2423 mono_string_intern (MonoString *str)
2424 {
2425         return mono_string_is_interned_lookup (str, TRUE);
2426 }
2427
2428 /*
2429  * mono_ldstr:
2430  * @domain: the domain where the string will be used.
2431  * @image: a metadata context
2432  * @idx: index into the user string table.
2433  * 
2434  * Implementation for the ldstr opcode.
2435  */
2436 MonoString*
2437 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2438 {
2439         const char *str, *sig;
2440         MonoString *o;
2441         size_t len2;
2442
2443         MONO_ARCH_SAVE_REGS;
2444
2445         if (image->dynamic)
2446                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2447         else
2448                 sig = str = mono_metadata_user_string (image, idx);
2449
2450         mono_domain_lock (domain);
2451         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2452                 mono_domain_unlock (domain);
2453                 return o;
2454         }
2455         
2456         len2 = mono_metadata_decode_blob_size (str, &str);
2457         len2 >>= 1;
2458
2459         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2460 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2461         {
2462                 int i;
2463                 guint16 *p2 = (guint16*)mono_string_chars (o);
2464                 for (i = 0; i < len2; ++i) {
2465                         *p2 = GUINT16_FROM_LE (*p2);
2466                         ++p2;
2467                 }
2468         }
2469 #endif
2470         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2471         mono_domain_unlock (domain);
2472
2473         return o;
2474 }
2475
2476 /*
2477  * mono_string_to_utf8:
2478  * @s: a System.String
2479  *
2480  * Return the UTF8 representation for @s.
2481  * the resulting buffer nedds to be freed with g_free().
2482  */
2483 char *
2484 mono_string_to_utf8 (MonoString *s)
2485 {
2486         char *as;
2487         GError *error = NULL;
2488
2489         if (s == NULL)
2490                 return NULL;
2491
2492         if (!s->length)
2493                 return g_strdup ("");
2494
2495         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2496         if (error) {
2497                 g_warning (error->message);
2498                 g_error_free (error);
2499         }
2500
2501         return as;
2502 }
2503
2504 /*
2505  * mono_string_to_utf16:
2506  * @s: a MonoString
2507  *
2508  * Return an null-terminated array of the utf-16 chars
2509  * contained in @s. The result must be freed with g_free().
2510  * This is a temporary helper until our string implementation
2511  * is reworked to always include the null terminating char.
2512  */
2513 gunichar2 *
2514 mono_string_to_utf16 (MonoString *s)
2515 {
2516         char *as;
2517
2518         if (s == NULL)
2519                 return NULL;
2520
2521         as = g_malloc ((s->length * 2) + 2);
2522         as [(s->length * 2)] = '\0';
2523         as [(s->length * 2) + 1] = '\0';
2524
2525         if (!s->length) {
2526                 return (gunichar2 *)(as);
2527         }
2528         
2529         memcpy (as, mono_string_chars(s), s->length * 2);
2530         return (gunichar2 *)(as);
2531 }
2532
2533 /*
2534  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2535  */
2536 MonoString *
2537 mono_string_from_utf16 (gunichar2 *data)
2538 {
2539         MonoDomain *domain = mono_domain_get ();
2540         int len = 0;
2541
2542         if (!data)
2543                 return NULL;
2544
2545         while (data [len]) len++;
2546
2547         return mono_string_new_utf16 (domain, data, len);
2548 }
2549
2550 static void
2551 default_ex_handler (MonoException *ex)
2552 {
2553         MonoObject *o = (MonoObject*)ex;
2554         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2555         exit (1);
2556 }
2557
2558 static MonoExceptionFunc ex_handler = default_ex_handler;
2559
2560 void
2561 mono_install_handler        (MonoExceptionFunc func)
2562 {
2563         ex_handler = func? func: default_ex_handler;
2564 }
2565
2566 /*
2567  * mono_raise_exception:
2568  * @ex: exception object
2569  *
2570  * Signal the runtime that the exception @ex has been raised in unmanaged code.
2571  */
2572 void
2573 mono_raise_exception (MonoException *ex) 
2574 {
2575         /*
2576          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2577          * that will cause gcc to omit the function epilog, causing problems when
2578          * the JIT tries to walk the stack, since the return address on the stack
2579          * will point into the next function in the executable, not this one.
2580          */
2581
2582         ex_handler (ex);
2583 }
2584
2585 MonoWaitHandle *
2586 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2587 {
2588         MonoWaitHandle *res;
2589
2590         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2591
2592         res->handle = handle;
2593
2594         return res;
2595 }
2596
2597 MonoAsyncResult *
2598 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2599 {
2600         MonoAsyncResult *res;
2601
2602         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2603
2604         res->data = data;
2605         res->async_state = state;
2606         if (handle != NULL)
2607                 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2608
2609         res->sync_completed = FALSE;
2610         res->completed = FALSE;
2611
2612         return res;
2613 }
2614
2615 void
2616 mono_message_init (MonoDomain *domain,
2617                    MonoMethodMessage *this, 
2618                    MonoReflectionMethod *method,
2619                    MonoArray *out_args)
2620 {
2621         MonoMethodSignature *sig = method->method->signature;
2622         MonoString *name;
2623         int i, j;
2624         char **names;
2625         guint8 arg_type;
2626
2627         this->method = method;
2628
2629         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2630         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2631         this->async_result = NULL;
2632         this->call_type = CallType_Sync;
2633
2634         names = g_new (char *, sig->param_count);
2635         mono_method_get_param_names (method->method, (const char **) names);
2636         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2637         
2638         for (i = 0; i < sig->param_count; i++) {
2639                  name = mono_string_new (domain, names [i]);
2640                  mono_array_set (this->names, gpointer, i, name);       
2641         }
2642
2643         g_free (names);
2644         for (i = 0, j = 0; i < sig->param_count; i++) {
2645
2646                 if (sig->params [i]->byref) {
2647                         if (out_args) {
2648                                 gpointer arg = mono_array_get (out_args, gpointer, j);
2649                                 mono_array_set (this->args, gpointer, i, arg);
2650                                 j++;
2651                         }
2652                         arg_type = 2;
2653                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2654                                 arg_type |= 1;
2655                 } else {
2656                         arg_type = 1;
2657                 }
2658                 mono_array_set (this->arg_types, guint8, i, arg_type);
2659         }
2660 }
2661
2662 /**
2663  * mono_remoting_invoke:
2664  * @real_proxy: pointer to a RealProxy object
2665  * @msg: The MonoMethodMessage to execute
2666  * @exc: used to store exceptions
2667  * @out_args: used to store output arguments
2668  *
2669  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2670  * IMessage interface and it is not trivial to extract results from there. So
2671  * we call an helper method PrivateInvoke instead of calling
2672  * RealProxy::Invoke() directly.
2673  *
2674  * Returns: the result object.
2675  */
2676 MonoObject *
2677 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
2678                       MonoObject **exc, MonoArray **out_args)
2679 {
2680         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2681         gpointer pa [4];
2682
2683         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2684
2685         if (!im) {
2686                 MonoClass *klass;
2687                 int i;
2688
2689                 klass = mono_defaults.real_proxy_class; 
2690                        
2691                 for (i = 0; i < klass->method.count; ++i) {
2692                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2693                             klass->methods [i]->signature->param_count == 4) {
2694                                 im = klass->methods [i];
2695                                 break;
2696                         }
2697                 }
2698         
2699                 g_assert (im);
2700                 real_proxy->vtable->domain->private_invoke_method = im;
2701         }
2702
2703         pa [0] = real_proxy;
2704         pa [1] = msg;
2705         pa [2] = exc;
2706         pa [3] = out_args;
2707
2708         return mono_runtime_invoke (im, NULL, pa, exc);
2709 }
2710
2711 MonoObject *
2712 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
2713                      MonoObject **exc, MonoArray **out_args) 
2714 {
2715         MonoDomain *domain; 
2716         MonoMethod *method;
2717         MonoMethodSignature *sig;
2718         int i, j, outarg_count = 0;
2719
2720         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2721
2722                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2723                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2724                         target = tp->rp->unwrapped_server;
2725                 } else {
2726                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2727                 }
2728         }
2729
2730         domain = mono_domain_get (); 
2731         method = msg->method->method;
2732         sig = method->signature;
2733
2734         for (i = 0; i < sig->param_count; i++) {
2735                 if (sig->params [i]->byref) 
2736                         outarg_count++;
2737         }
2738
2739         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2740         *exc = NULL;
2741
2742         for (i = 0, j = 0; i < sig->param_count; i++) {
2743                 if (sig->params [i]->byref) {
2744                         gpointer arg;
2745                         arg = mono_array_get (msg->args, gpointer, i);
2746                         mono_array_set (*out_args, gpointer, j, arg);
2747                         j++;
2748                 }
2749         }
2750
2751         return mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
2752 }
2753
2754 void
2755 mono_print_unhandled_exception (MonoObject *exc)
2756 {
2757         char *message = (char *) "";
2758         MonoString *str; 
2759         MonoMethod *method;
2760         MonoClass *klass;
2761         gboolean free_message = FALSE;
2762         gint i;
2763
2764         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2765                 klass = exc->vtable->klass;
2766                 method = NULL;
2767                 while (klass && method == NULL) {
2768                         for (i = 0; i < klass->method.count; ++i) {
2769                                 method = klass->methods [i];
2770                                 if (!strcmp ("ToString", method->name) &&
2771                                     method->signature->param_count == 0 &&
2772                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2773                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2774                                         break;
2775                                 }
2776                                 method = NULL;
2777                         }
2778                         
2779                         if (method == NULL)
2780                                 klass = klass->parent;
2781                 }
2782
2783                 g_assert (method);
2784
2785                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2786                 if (str) {
2787                         message = mono_string_to_utf8 (str);
2788                         free_message = TRUE;
2789                 }
2790         }                               
2791
2792         /*
2793          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
2794          *         exc->vtable->klass->name, message);
2795          */
2796         g_printerr ("\nUnhandled Exception: %s\n", message);
2797         
2798         if (free_message)
2799                 g_free (message);
2800 }
2801
2802 /**
2803  * mono_delegate_ctor:
2804  * @this: pointer to an uninitialized delegate object
2805  * @target: target object
2806  * @addr: pointer to native code
2807  *
2808  * This is used to initialize a delegate. We also insert the method_info if
2809  * we find the info with mono_jit_info_table_find().
2810  */
2811 void
2812 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2813 {
2814         MonoDomain *domain = mono_domain_get ();
2815         MonoDelegate *delegate = (MonoDelegate *)this;
2816         MonoMethod *method = NULL;
2817         MonoClass *class;
2818         MonoJitInfo *ji;
2819
2820         g_assert (this);
2821         g_assert (addr);
2822
2823         class = this->vtable->klass;
2824
2825         if ((ji = mono_jit_info_table_find (domain, addr))) {
2826                 method = ji->method;
2827                 delegate->method_info = mono_method_get_object (domain, method, NULL);
2828         }
2829
2830         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2831                 g_assert (method);
2832                 method = mono_marshal_get_remoting_invoke (method);
2833                 delegate->method_ptr = mono_compile_method (method);
2834                 delegate->target = target;
2835         } else {
2836                 delegate->method_ptr = addr;
2837                 delegate->target = target;
2838         }
2839 }
2840
2841 /**
2842  * mono_method_call_message_new:
2843  *
2844  * Translates arguments pointers into a Message.
2845  */
2846 MonoMethodMessage *
2847 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
2848                               MonoDelegate **cb, MonoObject **state)
2849 {
2850         MonoDomain *domain = mono_domain_get ();
2851         MonoMethodSignature *sig = method->signature;
2852         MonoMethodMessage *msg;
2853         int i, count, type;
2854
2855         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
2856         
2857         if (invoke) {
2858                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2859                 count =  sig->param_count - 2;
2860         } else {
2861                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2862                 count =  sig->param_count;
2863         }
2864
2865         for (i = 0; i < count; i++) {
2866                 gpointer vpos;
2867                 MonoClass *class;
2868                 MonoObject *arg;
2869
2870                 if (sig->params [i]->byref)
2871                         vpos = *((gpointer *)params [i]);
2872                 else 
2873                         vpos = params [i];
2874
2875                 type = sig->params [i]->type;
2876                 class = mono_class_from_mono_type (sig->params [i]);
2877
2878                 if (class->valuetype)
2879                         arg = mono_value_box (domain, class, vpos);
2880                 else 
2881                         arg = *((MonoObject **)vpos);
2882                       
2883                 mono_array_set (msg->args, gpointer, i, arg);
2884         }
2885
2886         if (cb != NULL && state != NULL) {
2887                 *cb = *((MonoDelegate **)params [i]);
2888                 i++;
2889                 *state = *((MonoObject **)params [i]);
2890         }
2891
2892         return msg;
2893 }
2894
2895 /**
2896  * mono_method_return_message_restore:
2897  *
2898  * Restore results from message based processing back to arguments pointers
2899  */
2900 void
2901 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2902 {
2903         MonoMethodSignature *sig = method->signature;
2904         int i, j, type, size;
2905         for (i = 0, j = 0; i < sig->param_count; i++) {
2906                 MonoType *pt = sig->params [i];
2907
2908                 if (pt->byref) {
2909                         char *arg = mono_array_get (out_args, gpointer, j);
2910                         type = pt->type;
2911
2912                         switch (type) {
2913                         case MONO_TYPE_VOID:
2914                                 g_assert_not_reached ();
2915                                 break;
2916                         case MONO_TYPE_U1:
2917                         case MONO_TYPE_I1:
2918                         case MONO_TYPE_BOOLEAN:
2919                         case MONO_TYPE_U2:
2920                         case MONO_TYPE_I2:
2921                         case MONO_TYPE_CHAR:
2922                         case MONO_TYPE_U4:
2923                         case MONO_TYPE_I4:
2924                         case MONO_TYPE_I8:
2925                         case MONO_TYPE_U8:
2926                         case MONO_TYPE_R4:
2927                         case MONO_TYPE_R8:
2928                         case MONO_TYPE_VALUETYPE: {
2929                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2930                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
2931                                 break;
2932                         }
2933                         case MONO_TYPE_STRING:
2934                         case MONO_TYPE_CLASS: 
2935                         case MONO_TYPE_ARRAY:
2936                         case MONO_TYPE_SZARRAY:
2937                         case MONO_TYPE_OBJECT:
2938                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2939                                 break;
2940                         default:
2941                                 g_assert_not_reached ();
2942                         }
2943
2944                         j++;
2945                 }
2946         }
2947 }
2948
2949 /**
2950  * mono_load_remote_field:
2951  * @this: pointer to an object
2952  * @klass: klass of the object containing @field
2953  * @field: the field to load
2954  * @res: a storage to store the result
2955  *
2956  * This method is called by the runtime on attempts to load fields of
2957  * transparent proxy objects. @this points to such TP, @klass is the class of
2958  * the object containing @field. @res is a storage location which can be
2959  * used to store the result.
2960  *
2961  * Returns: an address pointing to the value of field.
2962  */
2963 gpointer
2964 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2965 {
2966         static MonoMethod *getter = NULL;
2967         MonoDomain *domain = mono_domain_get ();
2968         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2969         MonoClass *field_class;
2970         MonoMethodMessage *msg;
2971         MonoArray *out_args;
2972         MonoObject *exc;
2973         gpointer tmp;
2974
2975         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2976
2977         if (!res)
2978                 res = &tmp;
2979
2980         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2981                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2982                 return res;
2983         }
2984         
2985         if (!getter) {
2986                 int i;
2987
2988                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2989                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2990                
2991                         if (!strcmp (cm->name, "FieldGetter")) {
2992                                 getter = cm;
2993                                 break;
2994                         }
2995                 }
2996                 g_assert (getter);
2997         }
2998         
2999         field_class = mono_class_from_mono_type (field->type);
3000
3001         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3002         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3003         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3004
3005         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3006         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3007
3008         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3009
3010         if (exc) mono_raise_exception ((MonoException *)exc);
3011
3012         *res = mono_array_get (out_args, MonoObject *, 0);
3013
3014         if (field_class->valuetype) {
3015                 return ((char *)*res) + sizeof (MonoObject);
3016         } else
3017                 return res;
3018 }
3019
3020 MonoObject *
3021 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3022 {
3023         static MonoMethod *getter = NULL;
3024         MonoDomain *domain = mono_domain_get ();
3025         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3026         MonoClass *field_class;
3027         MonoMethodMessage *msg;
3028         MonoArray *out_args;
3029         MonoObject *exc, *res;
3030
3031         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3032
3033         field_class = mono_class_from_mono_type (field->type);
3034
3035         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3036                 gpointer val;
3037                 if (field_class->valuetype) {
3038                         res = mono_object_new (domain, field_class);
3039                         val = ((gchar *) res) + sizeof (MonoObject);
3040                 } else {
3041                         val = &res;
3042                 }
3043                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3044                 return res;
3045         }
3046
3047         if (!getter) {
3048                 int i;
3049
3050                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3051                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3052                
3053                         if (!strcmp (cm->name, "FieldGetter")) {
3054                                 getter = cm;
3055                                 break;
3056                         }
3057                 }
3058                 g_assert (getter);
3059         }
3060         
3061         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3062         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3063         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3064
3065         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3066         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3067
3068         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3069
3070         if (exc) mono_raise_exception ((MonoException *)exc);
3071
3072         res = mono_array_get (out_args, MonoObject *, 0);
3073
3074         return res;
3075 }
3076
3077 /**
3078  * mono_store_remote_field:
3079  * @this: pointer to an object
3080  * @klass: klass of the object containing @field
3081  * @field: the field to load
3082  * @val: the value/object to store
3083  *
3084  * This method is called by the runtime on attempts to store fields of
3085  * transparent proxy objects. @this points to such TP, @klass is the class of
3086  * the object containing @field. @val is the new value to store in @field.
3087  */
3088 void
3089 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3090 {
3091         static MonoMethod *setter = NULL;
3092         MonoDomain *domain = mono_domain_get ();
3093         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3094         MonoClass *field_class;
3095         MonoMethodMessage *msg;
3096         MonoArray *out_args;
3097         MonoObject *exc;
3098         MonoObject *arg;
3099
3100         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3101
3102         field_class = mono_class_from_mono_type (field->type);
3103
3104         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3105                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3106                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3107                 return;
3108         }
3109
3110         if (!setter) {
3111                 int i;
3112
3113                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3114                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3115                
3116                         if (!strcmp (cm->name, "FieldSetter")) {
3117                                 setter = cm;
3118                                 break;
3119                         }
3120                 }
3121                 g_assert (setter);
3122         }
3123
3124         if (field_class->valuetype)
3125                 arg = mono_value_box (domain, field_class, val);
3126         else 
3127                 arg = *((MonoObject **)val);
3128                 
3129
3130         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3131         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3132
3133         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3134         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3135         mono_array_set (msg->args, gpointer, 2, arg);
3136
3137         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3138
3139         if (exc) mono_raise_exception ((MonoException *)exc);
3140 }
3141
3142 void
3143 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3144 {
3145         static MonoMethod *setter = NULL;
3146         MonoDomain *domain = mono_domain_get ();
3147         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3148         MonoClass *field_class;
3149         MonoMethodMessage *msg;
3150         MonoArray *out_args;
3151         MonoObject *exc;
3152
3153         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3154
3155         field_class = mono_class_from_mono_type (field->type);
3156
3157         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3158                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3159                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3160                 return;
3161         }
3162
3163         if (!setter) {
3164                 int i;
3165
3166                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3167                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3168                
3169                         if (!strcmp (cm->name, "FieldSetter")) {
3170                                 setter = cm;
3171                                 break;
3172                         }
3173                 }
3174                 g_assert (setter);
3175         }
3176
3177         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3178         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3179
3180         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3181         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3182         mono_array_set (msg->args, gpointer, 2, arg);
3183
3184         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3185
3186         if (exc) mono_raise_exception ((MonoException *)exc);
3187 }
3188