This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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                                 /* MS seems to create the objects if a null is passed in */
1590                                 if (! ((gpointer *)params->vector)[i])
1591                                         ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1592                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1593                                 break;
1594                         case MONO_TYPE_STRING:
1595                         case MONO_TYPE_OBJECT:
1596                         case MONO_TYPE_CLASS:
1597                         case MONO_TYPE_ARRAY:
1598                         case MONO_TYPE_SZARRAY:
1599                                 if (sig->params [i]->byref)
1600                                         pa [i] = &(((gpointer *)params->vector)[i]);
1601                                 else
1602                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
1603                                 break;
1604                         default:
1605                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1606                         }
1607                 }
1608         }
1609
1610         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1611                 void *o = obj;
1612                 if (!obj) {
1613                         obj = mono_object_new (mono_domain_get (), method->klass);
1614                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1615                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1616                         }
1617                         if (method->klass->valuetype)
1618                                 o = mono_object_unbox (obj);
1619                         else
1620                                 o = obj;
1621                 }
1622                 mono_runtime_invoke (method, o, pa, exc);
1623                 return obj;
1624         } else {
1625                 /* obj must be already unboxed if needed */
1626                 return mono_runtime_invoke (method, obj, pa, exc);
1627         }
1628 }
1629
1630 static void
1631 out_of_memory (size_t size)
1632 {
1633         /* 
1634          * we could allocate at program startup some memory that we could release 
1635          * back to the system at this point if we're really low on memory (ie, size is
1636          * lower than the memory we set apart)
1637          */
1638         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1639 }
1640
1641 /**
1642  * mono_object_allocate:
1643  * @size: number of bytes to allocate
1644  *
1645  * This is a very simplistic routine until we have our GC-aware
1646  * memory allocator. 
1647  *
1648  * Returns: an allocated object of size @size, or NULL on failure.
1649  */
1650 static inline void *
1651 mono_object_allocate (size_t size)
1652 {
1653 #if HAVE_BOEHM_GC
1654         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1655         void *o = GC_MALLOC (size);
1656 #else
1657         void *o = calloc (1, size);
1658 #endif
1659         mono_stats.new_object_count++;
1660
1661         if (!o)
1662                 out_of_memory (size);
1663         return o;
1664 }
1665
1666 #if CREATION_SPEEDUP
1667 static inline void *
1668 mono_object_allocate_spec (size_t size, void *gcdescr)
1669 {
1670         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1671         void *o = GC_GCJ_MALLOC (size, gcdescr);
1672         mono_stats.new_object_count++;
1673
1674         if (!o)
1675                 out_of_memory (size);
1676         return o;
1677 }
1678 #endif
1679
1680 /**
1681  * mono_object_new:
1682  * @klass: the class of the object that we want to create
1683  *
1684  * Returns a newly created object whose definition is
1685  * looked up using @klass.   This will not invoke any constructors, 
1686  * so the consumer of this routine has to invoke any constructors on
1687  * its own to initialize the object.
1688  */
1689 MonoObject *
1690 mono_object_new (MonoDomain *domain, MonoClass *klass)
1691 {
1692         MONO_ARCH_SAVE_REGS;
1693         return mono_object_new_specific (mono_class_vtable (domain, klass));
1694 }
1695
1696 /**
1697  * mono_object_new_specific:
1698  * @vtable: the vtable of the object that we want to create
1699  *
1700  * Returns: A newly created object with class and domain specified
1701  * by @vtable
1702  */
1703 MonoObject *
1704 mono_object_new_specific (MonoVTable *vtable)
1705 {
1706         MonoObject *o;
1707
1708         MONO_ARCH_SAVE_REGS;
1709         
1710         if (vtable->remote)
1711         {
1712                 gpointer pa [1];
1713                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1714
1715                 if (im == NULL) {
1716                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1717                         int i;
1718
1719                         if (!klass->inited)
1720                                 mono_class_init (klass);
1721
1722                         for (i = 0; i < klass->method.count; ++i) {
1723                                 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1724                                         klass->methods [i]->signature->param_count == 1) {
1725                                         im = klass->methods [i];
1726                                         break;
1727                                 }
1728                         }
1729                         g_assert (im);
1730                         vtable->domain->create_proxy_for_type_method = im;
1731                 }
1732         
1733                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1734
1735                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
1736                 if (o != NULL) return o;
1737         }
1738
1739         return mono_object_new_alloc_specific (vtable);
1740 }
1741
1742 MonoObject *
1743 mono_object_new_fast (MonoVTable *vtable)
1744 {
1745         MonoObject *o;
1746         MONO_ARCH_SAVE_REGS;
1747
1748 #if CREATION_SPEEDUP
1749         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1750                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1751         } else {
1752 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1753                 o = mono_object_allocate (vtable->klass->instance_size);
1754                 o->vtable = vtable;
1755         }
1756 #else
1757         o = mono_object_allocate (vtable->klass->instance_size);
1758         o->vtable = vtable;
1759 #endif
1760         return o;
1761 }
1762
1763 MonoObject *
1764 mono_object_new_alloc_specific (MonoVTable *vtable)
1765 {
1766         MonoObject *o;
1767
1768 #if CREATION_SPEEDUP
1769         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1770                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1771         } else {
1772 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1773                 o = mono_object_allocate (vtable->klass->instance_size);
1774                 o->vtable = vtable;
1775         }
1776 #else
1777         o = mono_object_allocate (vtable->klass->instance_size);
1778         o->vtable = vtable;
1779 #endif
1780         if (vtable->klass->has_finalize)
1781                 mono_object_register_finalizer (o);
1782         
1783         mono_profiler_allocation (o, vtable->klass);
1784         return o;
1785 }
1786
1787 /**
1788  * mono_object_new_from_token:
1789  * @image: Context where the type_token is hosted
1790  * @token: a token of the type that we want to create
1791  *
1792  * Returns: A newly created object whose definition is
1793  * looked up using @token in the @image image
1794  */
1795 MonoObject *
1796 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
1797 {
1798         MonoClass *class;
1799
1800         class = mono_class_get (image, token);
1801
1802         return mono_object_new (domain, class);
1803 }
1804
1805
1806 /**
1807  * mono_object_clone:
1808  * @obj: the object to clone
1809  *
1810  * Returns: A newly created object who is a shallow copy of @obj
1811  */
1812 MonoObject *
1813 mono_object_clone (MonoObject *obj)
1814 {
1815         MonoObject *o;
1816         int size;
1817
1818         size = obj->vtable->klass->instance_size;
1819         o = mono_object_allocate (size);
1820         mono_profiler_allocation (o, obj->vtable->klass);
1821
1822         memcpy (o, obj, size);
1823
1824         if (obj->vtable->klass->has_finalize)
1825                 mono_object_register_finalizer (o);
1826         return o;
1827 }
1828
1829 /**
1830  * mono_array_clone:
1831  * @array: the array to clone
1832  *
1833  * Returns: A newly created array who is a shallow copy of @array
1834  */
1835 MonoArray*
1836 mono_array_clone (MonoArray *array)
1837 {
1838         MonoArray *o;
1839         int size, i;
1840         guint32 *sizes;
1841         MonoClass *klass = array->obj.vtable->klass;
1842
1843         MONO_ARCH_SAVE_REGS;
1844
1845         if (array->bounds == NULL) {
1846                 size = mono_array_length (array);
1847                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1848                                          klass, &size, NULL);
1849
1850                 size *= mono_array_element_size (klass);
1851                 memcpy (o, array, sizeof (MonoArray) + size);
1852
1853                 return o;
1854         }
1855         
1856         sizes = alloca (klass->rank * sizeof(guint32) * 2);
1857         size = mono_array_element_size (klass);
1858         for (i = 0; i < klass->rank; ++i) {
1859                 sizes [i] = array->bounds [i].length;
1860                 size *= array->bounds [i].length;
1861                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1862         }
1863         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
1864                                  klass, sizes, sizes + klass->rank);
1865         memcpy (o, array, sizeof(MonoArray) + size);
1866
1867         return o;
1868 }
1869
1870 /* helper macros to check for overflow when calculating the size of arrays */
1871 #define MYGUINT32_MAX 4294967295U
1872 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1873         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1874 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1875         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1876         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1877
1878 /*
1879  * mono_array_new_full:
1880  * @domain: domain where the object is created
1881  * @array_class: array class
1882  * @lengths: lengths for each dimension in the array
1883  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1884  *
1885  * This routine creates a new array objects with the given dimensions,
1886  * lower bounds and type.
1887  */
1888 MonoArray*
1889 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
1890                      guint32 *lengths, guint32 *lower_bounds)
1891 {
1892         guint32 byte_len, len;
1893         MonoObject *o;
1894         MonoArray *array;
1895         MonoArrayBounds *bounds;
1896         MonoVTable *vtable;
1897         int i;
1898
1899         if (!array_class->inited)
1900                 mono_class_init (array_class);
1901
1902         byte_len = mono_array_element_size (array_class);
1903         len = 1;
1904
1905         if (array_class->rank == 1 &&
1906             (lower_bounds == NULL || lower_bounds [0] == 0)) {
1907                 bounds = NULL;
1908                 len = lengths [0];
1909         } else {
1910         #if HAVE_BOEHM_GC
1911                 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1912         #else
1913                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1914         #endif
1915                 for (i = 0; i < array_class->rank; ++i) {
1916                         bounds [i].length = lengths [i];
1917                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1918                                 out_of_memory (MYGUINT32_MAX);
1919                         len *= lengths [i];
1920                 }
1921
1922                 if (lower_bounds)
1923                         for (i = 0; i < array_class->rank; ++i)
1924                                 bounds [i].lower_bound = lower_bounds [i];
1925         }
1926
1927         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1928                 out_of_memory (MYGUINT32_MAX);
1929         byte_len *= len;
1930         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1931                 out_of_memory (MYGUINT32_MAX);
1932         byte_len += sizeof (MonoArray);
1933         /* 
1934          * Following three lines almost taken from mono_object_new ():
1935          * they need to be kept in sync.
1936          */
1937         vtable = mono_class_vtable (domain, array_class);
1938 #if CREATION_SPEEDUP
1939         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1940                 o = mono_object_allocate_spec (byte_len, vtable);
1941         else {
1942                 o = mono_object_allocate (byte_len);
1943                 o->vtable = vtable;
1944         }
1945 #else
1946         o = mono_object_allocate (byte_len);
1947         o->vtable = vtable;
1948 #endif
1949
1950         array = (MonoArray*)o;
1951
1952         array->bounds = bounds;
1953         array->max_length = len;
1954
1955         mono_profiler_allocation (o, array_class);
1956
1957         return array;
1958 }
1959
1960 /*
1961  * mono_array_new:
1962  * @domain: domain where the object is created
1963  * @eclass: element class
1964  * @n: number of array elements
1965  *
1966  * This routine creates a new szarray with @n elements of type @eclass.
1967  */
1968 MonoArray *
1969 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1970 {
1971         MonoClass *ac;
1972
1973         MONO_ARCH_SAVE_REGS;
1974
1975         ac = mono_array_class_get (eclass, 1);
1976         g_assert (ac != NULL);
1977
1978         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1979 }
1980
1981 /*
1982  * mono_array_new_specific:
1983  * @vtable: a vtable in the appropriate domain for an initialized class
1984  * @n: number of array elements
1985  *
1986  * This routine is a fast alternative to mono_array_new() for code which
1987  * can be sure about the domain it operates in.
1988  */
1989 MonoArray *
1990 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1991 {
1992         MonoObject *o;
1993         MonoArray *ao;
1994         guint32 byte_len, elem_size;
1995
1996         MONO_ARCH_SAVE_REGS;
1997
1998         elem_size = mono_array_element_size (vtable->klass);
1999         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2000                 out_of_memory (MYGUINT32_MAX);
2001         byte_len = n * elem_size;
2002         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2003                 out_of_memory (MYGUINT32_MAX);
2004         byte_len += sizeof (MonoArray);
2005 #if CREATION_SPEEDUP
2006         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2007                 o = mono_object_allocate_spec (byte_len, vtable);
2008         } else {
2009 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2010                 o = mono_object_allocate (byte_len);
2011                 o->vtable = vtable;
2012         }
2013 #else
2014         o = mono_object_allocate (byte_len);
2015         o->vtable = vtable;
2016 #endif
2017
2018         ao = (MonoArray *)o;
2019         ao->bounds = NULL;
2020         ao->max_length = n;
2021         mono_profiler_allocation (o, vtable->klass);
2022
2023         return ao;
2024 }
2025
2026 /**
2027  * mono_string_new_utf16:
2028  * @text: a pointer to an utf16 string
2029  * @len: the length of the string
2030  *
2031  * Returns: A newly created string object which contains @text.
2032  */
2033 MonoString *
2034 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2035 {
2036         MonoString *s;
2037         
2038         s = mono_string_new_size (domain, len);
2039         g_assert (s != NULL);
2040
2041         memcpy (mono_string_chars (s), text, len * 2);
2042
2043         return s;
2044 }
2045
2046 /**
2047  * mono_string_new_size:
2048  * @text: a pointer to an utf16 string
2049  * @len: the length of the string
2050  *
2051  * Returns: A newly created string object of @len
2052  */
2053 MonoString *
2054 mono_string_new_size (MonoDomain *domain, gint32 len)
2055 {
2056         MonoString *s;
2057         MonoVTable *vtable;
2058         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2059
2060         /* overflow ? can't fit it, can't allocate it! */
2061         if (len > size)
2062                 out_of_memory (-1);
2063
2064         vtable = mono_class_vtable (domain, mono_defaults.string_class);
2065
2066 #if CREATION_SPEEDUP
2067         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2068                 s = mono_object_allocate_spec (size, vtable);
2069         else {
2070                 s = (MonoString*)mono_object_allocate (size);
2071                 s->object.vtable = vtable;
2072         }
2073 #else
2074         s = (MonoString*)mono_object_allocate (size);
2075         s->object.vtable = vtable;
2076 #endif
2077
2078         s->length = len;
2079         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2080
2081         return s;
2082 }
2083
2084 /*
2085  * mono_string_new_len:
2086  * @text: a pointer to an utf8 string
2087  * @length: number of bytes in @text to consider
2088  *
2089  * Returns: A newly created string object which contains @text.
2090  */
2091 MonoString*
2092 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2093 {
2094         GError *error = NULL;
2095         MonoString *o = NULL;
2096         guint16 *ut;
2097         glong items_written;
2098
2099         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2100
2101         if (!error)
2102                 o = mono_string_new_utf16 (domain, ut, items_written);
2103         else 
2104                 g_error_free (error);
2105
2106         g_free (ut);
2107
2108         return o;
2109 }
2110
2111 /**
2112  * mono_string_new:
2113  * @text: a pointer to an utf8 string
2114  *
2115  * Returns: A newly created string object which contains @text.
2116  */
2117 MonoString*
2118 mono_string_new (MonoDomain *domain, const char *text)
2119 {
2120         GError *error = NULL;
2121         MonoString *o = NULL;
2122         guint16 *ut;
2123         glong items_written;
2124         int l;
2125
2126         l = strlen (text);
2127         
2128         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2129
2130         if (!error)
2131                 o = mono_string_new_utf16 (domain, ut, items_written);
2132         else 
2133                 g_error_free (error);
2134
2135         g_free (ut);
2136
2137         return o;
2138 }
2139
2140 /*
2141  * mono_string_new_wrapper:
2142  * @text: pointer to utf8 characters.
2143  *
2144  * Helper function to create a string object from @text in the current domain.
2145  */
2146 MonoString*
2147 mono_string_new_wrapper (const char *text)
2148 {
2149         MonoDomain *domain = mono_domain_get ();
2150
2151         MONO_ARCH_SAVE_REGS;
2152
2153         if (text)
2154                 return mono_string_new (domain, text);
2155
2156         return NULL;
2157 }
2158
2159 /**
2160  * mono_value_box:
2161  * @class: the class of the value
2162  * @value: a pointer to the unboxed data
2163  *
2164  * Returns: A newly created object which contains @value.
2165  */
2166 MonoObject *
2167 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2168 {
2169         MonoObject *res;
2170         int size;
2171         MonoVTable *vtable;
2172
2173         g_assert (class->valuetype);
2174
2175         vtable = mono_class_vtable (domain, class);
2176         size = mono_class_instance_size (class);
2177         res = mono_object_allocate (size);
2178         res->vtable = vtable;
2179         mono_profiler_allocation (res, class);
2180
2181         size = size - sizeof (MonoObject);
2182
2183 #if NO_UNALIGNED_ACCESS
2184         memcpy ((char *)res + sizeof (MonoObject), value, size);
2185 #else
2186         switch (size) {
2187         case 1:
2188                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2189                 break;
2190         case 2:
2191                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2192                 break;
2193         case 4:
2194                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2195                 break;
2196         case 8:
2197                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2198                 break;
2199         default:
2200                 memcpy ((char *)res + sizeof (MonoObject), value, size);
2201         }
2202 #endif
2203         if (class->has_finalize)
2204                 mono_object_register_finalizer (res);
2205         return res;
2206 }
2207
2208 MonoDomain*
2209 mono_object_get_domain (MonoObject *obj)
2210 {
2211         return mono_object_domain (obj);
2212 }
2213
2214 MonoClass*
2215 mono_object_get_class (MonoObject *obj)
2216 {
2217         return mono_object_class (obj);
2218 }
2219
2220 gpointer
2221 mono_object_unbox (MonoObject *obj)
2222 {
2223         /* add assert for valuetypes? */
2224         g_assert (obj->vtable->klass->valuetype);
2225         return ((char*)obj) + sizeof (MonoObject);
2226 }
2227
2228 /**
2229  * mono_object_isinst:
2230  * @obj: an object
2231  * @klass: a pointer to a class 
2232  *
2233  * Returns: @obj if @obj is derived from @klass
2234  */
2235 MonoObject *
2236 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2237 {
2238         if (!klass->inited)
2239                 mono_class_init (klass);
2240
2241         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
2242                 return mono_object_isinst_mbyref (obj, klass);
2243
2244         if (!obj)
2245                 return NULL;
2246
2247         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2248 }
2249
2250 MonoObject *
2251 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2252 {
2253         MonoVTable *vt;
2254
2255         if (!obj)
2256                 return NULL;
2257
2258         vt = obj->vtable;
2259         
2260         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2261                 if ((klass->interface_id <= vt->max_interface_id) &&
2262                     (vt->interface_offsets [klass->interface_id] != 0))
2263                         return obj;
2264         }
2265         else {
2266                 MonoClass *oklass = vt->klass;
2267                 if ((oklass == mono_defaults.transparent_proxy_class))
2268                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2269         
2270                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2271                         return obj;
2272         }
2273
2274         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
2275         {
2276                 MonoDomain *domain = mono_domain_get ();
2277                 MonoObject *res;
2278                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2279                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2280                 MonoMethod *im = NULL;
2281                 gpointer pa [2];
2282                 int i;
2283         
2284                 for (i = 0; i < rpklass->method.count; ++i) {
2285                         if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2286                                 im = rpklass->methods [i];
2287                                 break;
2288                         }
2289                 }
2290         
2291                 im = mono_object_get_virtual_method (rp, im);
2292                 g_assert (im);
2293         
2294                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2295                 pa [1] = obj;
2296
2297                 res = mono_runtime_invoke (im, rp, pa, NULL);
2298         
2299                 if (*(MonoBoolean *) mono_object_unbox(res)) {
2300                         /* Update the vtable of the remote type, so it can safely cast to this new type */
2301                         mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2302                         obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2303                         return obj;
2304                 }
2305         }
2306
2307         return NULL;
2308 }
2309
2310 /**
2311  * mono_object_castclass_mbyref:
2312  * @obj: an object
2313  * @klass: a pointer to a class 
2314  *
2315  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2316  */
2317 MonoObject *
2318 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2319 {
2320         if (!obj) return NULL;
2321         if (mono_object_isinst_mbyref (obj, klass)) return obj;
2322                 
2323         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2324                                                         "System",
2325                                                         "InvalidCastException"));
2326         return NULL;
2327 }
2328
2329 typedef struct {
2330         MonoDomain *orig_domain;
2331         char *ins;
2332         MonoString *res;
2333 } LDStrInfo;
2334
2335 static void
2336 str_lookup (MonoDomain *domain, gpointer user_data)
2337 {
2338         LDStrInfo *info = user_data;
2339         if (info->res || domain == info->orig_domain)
2340                 return;
2341         mono_domain_lock (domain);
2342         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2343         mono_domain_unlock (domain);
2344 }
2345
2346 static MonoString*
2347 mono_string_is_interned_lookup (MonoString *str, int insert)
2348 {
2349         MonoGHashTable *ldstr_table;
2350         MonoString *res;
2351         MonoDomain *domain;
2352         char *ins = g_malloc (4 + str->length * 2);
2353         char *p;
2354         
2355         /* Encode the length */
2356         /* Same code as in mono_image_insert_string () */
2357         p = ins;
2358         mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2359
2360         /*
2361          * ins is stored in the hash table as a key and needs to have the same
2362          * representation as in the metadata: we swap the character bytes on big
2363          * endian boxes.
2364          */
2365 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2366         {
2367                 int i;
2368                 char *p2 = (char *)mono_string_chars (str);
2369                 for (i = 0; i < str->length; ++i) {
2370                         *p++ = p2 [1];
2371                         *p++ = p2 [0];
2372                         p2 += 2;
2373                 }
2374         }
2375 #else
2376         memcpy (p, mono_string_chars (str), str->length * 2);
2377 #endif
2378         domain = ((MonoObject *)str)->vtable->domain;
2379         ldstr_table = domain->ldstr_table;
2380         mono_domain_lock (domain);
2381         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2382                 mono_domain_unlock (domain);
2383                 g_free (ins);
2384                 return res;
2385         }
2386         if (insert) {
2387                 mono_g_hash_table_insert (ldstr_table, ins, str);
2388                 mono_domain_unlock (domain);
2389                 return str;
2390         } else {
2391                 LDStrInfo ldstr_info;
2392                 ldstr_info.orig_domain = domain;
2393                 ldstr_info.ins = ins;
2394                 ldstr_info.res = NULL;
2395
2396                 mono_domain_foreach (str_lookup, &ldstr_info);
2397                 if (ldstr_info.res) {
2398                         /* 
2399                          * the string was already interned in some other domain:
2400                          * intern it in the current one as well.
2401                          */
2402                         mono_g_hash_table_insert (ldstr_table, ins, str);
2403                         mono_domain_unlock (domain);
2404                         return str;
2405                 }
2406         }
2407         mono_domain_unlock (domain);
2408         g_free (ins);
2409         return NULL;
2410 }
2411
2412 MonoString*
2413 mono_string_is_interned (MonoString *o)
2414 {
2415         return mono_string_is_interned_lookup (o, FALSE);
2416 }
2417
2418 MonoString*
2419 mono_string_intern (MonoString *str)
2420 {
2421         return mono_string_is_interned_lookup (str, TRUE);
2422 }
2423
2424 /*
2425  * mono_ldstr:
2426  * @domain: the domain where the string will be used.
2427  * @image: a metadata context
2428  * @idx: index into the user string table.
2429  * 
2430  * Implementation for the ldstr opcode.
2431  */
2432 MonoString*
2433 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2434 {
2435         const char *str, *sig;
2436         MonoString *o;
2437         size_t len2;
2438
2439         MONO_ARCH_SAVE_REGS;
2440
2441         if (image->dynamic)
2442                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2443         else
2444                 sig = str = mono_metadata_user_string (image, idx);
2445
2446         mono_domain_lock (domain);
2447         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2448                 mono_domain_unlock (domain);
2449                 return o;
2450         }
2451         
2452         len2 = mono_metadata_decode_blob_size (str, &str);
2453         len2 >>= 1;
2454
2455         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2456 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2457         {
2458                 int i;
2459                 guint16 *p2 = (guint16*)mono_string_chars (o);
2460                 for (i = 0; i < len2; ++i) {
2461                         *p2 = GUINT16_FROM_LE (*p2);
2462                         ++p2;
2463                 }
2464         }
2465 #endif
2466         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2467         mono_domain_unlock (domain);
2468
2469         return o;
2470 }
2471
2472 /*
2473  * mono_string_to_utf8:
2474  * @s: a System.String
2475  *
2476  * Return the UTF8 representation for @s.
2477  * the resulting buffer nedds to be freed with g_free().
2478  */
2479 char *
2480 mono_string_to_utf8 (MonoString *s)
2481 {
2482         char *as;
2483         GError *error = NULL;
2484
2485         if (s == NULL)
2486                 return NULL;
2487
2488         if (!s->length)
2489                 return g_strdup ("");
2490
2491         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2492         if (error) {
2493                 g_warning (error->message);
2494                 g_error_free (error);
2495         }
2496
2497         return as;
2498 }
2499
2500 /*
2501  * mono_string_to_utf16:
2502  * @s: a MonoString
2503  *
2504  * Return an null-terminated array of the utf-16 chars
2505  * contained in @s. The result must be freed with g_free().
2506  * This is a temporary helper until our string implementation
2507  * is reworked to always include the null terminating char.
2508  */
2509 gunichar2 *
2510 mono_string_to_utf16 (MonoString *s)
2511 {
2512         char *as;
2513
2514         if (s == NULL)
2515                 return NULL;
2516
2517         as = g_malloc ((s->length * 2) + 2);
2518         as [(s->length * 2)] = '\0';
2519         as [(s->length * 2) + 1] = '\0';
2520
2521         if (!s->length) {
2522                 return (gunichar2 *)(as);
2523         }
2524         
2525         memcpy (as, mono_string_chars(s), s->length * 2);
2526         return (gunichar2 *)(as);
2527 }
2528
2529 /*
2530  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2531  */
2532 MonoString *
2533 mono_string_from_utf16 (gunichar2 *data)
2534 {
2535         MonoDomain *domain = mono_domain_get ();
2536         int len = 0;
2537
2538         if (!data)
2539                 return NULL;
2540
2541         while (data [len]) len++;
2542
2543         return mono_string_new_utf16 (domain, data, len);
2544 }
2545
2546 static void
2547 default_ex_handler (MonoException *ex)
2548 {
2549         MonoObject *o = (MonoObject*)ex;
2550         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2551         exit (1);
2552 }
2553
2554 static MonoExceptionFunc ex_handler = default_ex_handler;
2555
2556 void
2557 mono_install_handler        (MonoExceptionFunc func)
2558 {
2559         ex_handler = func? func: default_ex_handler;
2560 }
2561
2562 /*
2563  * mono_raise_exception:
2564  * @ex: exception object
2565  *
2566  * Signal the runtime that the exception @ex has been raised in unmanaged code.
2567  */
2568 void
2569 mono_raise_exception (MonoException *ex) 
2570 {
2571         /*
2572          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2573          * that will cause gcc to omit the function epilog, causing problems when
2574          * the JIT tries to walk the stack, since the return address on the stack
2575          * will point into the next function in the executable, not this one.
2576          */
2577
2578         ex_handler (ex);
2579 }
2580
2581 MonoWaitHandle *
2582 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2583 {
2584         MonoWaitHandle *res;
2585
2586         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2587
2588         res->handle = handle;
2589
2590         return res;
2591 }
2592
2593 MonoAsyncResult *
2594 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2595 {
2596         MonoAsyncResult *res;
2597
2598         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2599
2600         res->data = data;
2601         res->async_state = state;
2602         if (handle != NULL)
2603                 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2604
2605         res->sync_completed = FALSE;
2606         res->completed = FALSE;
2607
2608         return res;
2609 }
2610
2611 void
2612 mono_message_init (MonoDomain *domain,
2613                    MonoMethodMessage *this, 
2614                    MonoReflectionMethod *method,
2615                    MonoArray *out_args)
2616 {
2617         MonoMethodSignature *sig = method->method->signature;
2618         MonoString *name;
2619         int i, j;
2620         char **names;
2621         guint8 arg_type;
2622
2623         this->method = method;
2624
2625         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2626         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2627         this->async_result = NULL;
2628         this->call_type = CallType_Sync;
2629
2630         names = g_new (char *, sig->param_count);
2631         mono_method_get_param_names (method->method, (const char **) names);
2632         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2633         
2634         for (i = 0; i < sig->param_count; i++) {
2635                  name = mono_string_new (domain, names [i]);
2636                  mono_array_set (this->names, gpointer, i, name);       
2637         }
2638
2639         g_free (names);
2640         for (i = 0, j = 0; i < sig->param_count; i++) {
2641
2642                 if (sig->params [i]->byref) {
2643                         if (out_args) {
2644                                 gpointer arg = mono_array_get (out_args, gpointer, j);
2645                                 mono_array_set (this->args, gpointer, i, arg);
2646                                 j++;
2647                         }
2648                         arg_type = 2;
2649                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2650                                 arg_type |= 1;
2651                 } else {
2652                         arg_type = 1;
2653                 }
2654                 mono_array_set (this->arg_types, guint8, i, arg_type);
2655         }
2656 }
2657
2658 /**
2659  * mono_remoting_invoke:
2660  * @real_proxy: pointer to a RealProxy object
2661  * @msg: The MonoMethodMessage to execute
2662  * @exc: used to store exceptions
2663  * @out_args: used to store output arguments
2664  *
2665  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2666  * IMessage interface and it is not trivial to extract results from there. So
2667  * we call an helper method PrivateInvoke instead of calling
2668  * RealProxy::Invoke() directly.
2669  *
2670  * Returns: the result object.
2671  */
2672 MonoObject *
2673 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
2674                       MonoObject **exc, MonoArray **out_args)
2675 {
2676         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2677         gpointer pa [4];
2678
2679         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2680
2681         if (!im) {
2682                 MonoClass *klass;
2683                 int i;
2684
2685                 klass = mono_defaults.real_proxy_class; 
2686                        
2687                 for (i = 0; i < klass->method.count; ++i) {
2688                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2689                             klass->methods [i]->signature->param_count == 4) {
2690                                 im = klass->methods [i];
2691                                 break;
2692                         }
2693                 }
2694         
2695                 g_assert (im);
2696                 real_proxy->vtable->domain->private_invoke_method = im;
2697         }
2698
2699         pa [0] = real_proxy;
2700         pa [1] = msg;
2701         pa [2] = exc;
2702         pa [3] = out_args;
2703
2704         return mono_runtime_invoke (im, NULL, pa, exc);
2705 }
2706
2707 MonoObject *
2708 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
2709                      MonoObject **exc, MonoArray **out_args) 
2710 {
2711         MonoDomain *domain; 
2712         MonoMethod *method;
2713         MonoMethodSignature *sig;
2714         int i, j, outarg_count = 0;
2715
2716         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2717
2718                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2719                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2720                         target = tp->rp->unwrapped_server;
2721                 } else {
2722                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2723                 }
2724         }
2725
2726         domain = mono_domain_get (); 
2727         method = msg->method->method;
2728         sig = method->signature;
2729
2730         for (i = 0; i < sig->param_count; i++) {
2731                 if (sig->params [i]->byref) 
2732                         outarg_count++;
2733         }
2734
2735         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2736         *exc = NULL;
2737
2738         for (i = 0, j = 0; i < sig->param_count; i++) {
2739                 if (sig->params [i]->byref) {
2740                         gpointer arg;
2741                         arg = mono_array_get (msg->args, gpointer, i);
2742                         mono_array_set (*out_args, gpointer, j, arg);
2743                         j++;
2744                 }
2745         }
2746
2747         return mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
2748 }
2749
2750 void
2751 mono_print_unhandled_exception (MonoObject *exc)
2752 {
2753         char *message = (char *) "";
2754         MonoString *str; 
2755         MonoMethod *method;
2756         MonoClass *klass;
2757         gboolean free_message = FALSE;
2758         gint i;
2759
2760         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2761                 klass = exc->vtable->klass;
2762                 method = NULL;
2763                 while (klass && method == NULL) {
2764                         for (i = 0; i < klass->method.count; ++i) {
2765                                 method = klass->methods [i];
2766                                 if (!strcmp ("ToString", method->name) &&
2767                                     method->signature->param_count == 0 &&
2768                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2769                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2770                                         break;
2771                                 }
2772                                 method = NULL;
2773                         }
2774                         
2775                         if (method == NULL)
2776                                 klass = klass->parent;
2777                 }
2778
2779                 g_assert (method);
2780
2781                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2782                 if (str) {
2783                         message = mono_string_to_utf8 (str);
2784                         free_message = TRUE;
2785                 }
2786         }                               
2787
2788         /*
2789          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
2790          *         exc->vtable->klass->name, message);
2791          */
2792         g_printerr ("\nUnhandled Exception: %s\n", message);
2793         
2794         if (free_message)
2795                 g_free (message);
2796 }
2797
2798 /**
2799  * mono_delegate_ctor:
2800  * @this: pointer to an uninitialized delegate object
2801  * @target: target object
2802  * @addr: pointer to native code
2803  *
2804  * This is used to initialize a delegate. We also insert the method_info if
2805  * we find the info with mono_jit_info_table_find().
2806  */
2807 void
2808 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2809 {
2810         MonoDomain *domain = mono_domain_get ();
2811         MonoDelegate *delegate = (MonoDelegate *)this;
2812         MonoMethod *method = NULL;
2813         MonoClass *class;
2814         MonoJitInfo *ji;
2815
2816         g_assert (this);
2817         g_assert (addr);
2818
2819         class = this->vtable->klass;
2820
2821         if ((ji = mono_jit_info_table_find (domain, addr))) {
2822                 method = ji->method;
2823                 delegate->method_info = mono_method_get_object (domain, method, NULL);
2824         }
2825
2826         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2827                 g_assert (method);
2828                 method = mono_marshal_get_remoting_invoke (method);
2829                 delegate->method_ptr = mono_compile_method (method);
2830                 delegate->target = target;
2831         } else {
2832                 delegate->method_ptr = addr;
2833                 delegate->target = target;
2834         }
2835 }
2836
2837 /**
2838  * mono_method_call_message_new:
2839  *
2840  * Translates arguments pointers into a Message.
2841  */
2842 MonoMethodMessage *
2843 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
2844                               MonoDelegate **cb, MonoObject **state)
2845 {
2846         MonoDomain *domain = mono_domain_get ();
2847         MonoMethodSignature *sig = method->signature;
2848         MonoMethodMessage *msg;
2849         int i, count, type;
2850
2851         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
2852         
2853         if (invoke) {
2854                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2855                 count =  sig->param_count - 2;
2856         } else {
2857                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2858                 count =  sig->param_count;
2859         }
2860
2861         for (i = 0; i < count; i++) {
2862                 gpointer vpos;
2863                 MonoClass *class;
2864                 MonoObject *arg;
2865
2866                 if (sig->params [i]->byref)
2867                         vpos = *((gpointer *)params [i]);
2868                 else 
2869                         vpos = params [i];
2870
2871                 type = sig->params [i]->type;
2872                 class = mono_class_from_mono_type (sig->params [i]);
2873
2874                 if (class->valuetype)
2875                         arg = mono_value_box (domain, class, vpos);
2876                 else 
2877                         arg = *((MonoObject **)vpos);
2878                       
2879                 mono_array_set (msg->args, gpointer, i, arg);
2880         }
2881
2882         if (cb != NULL && state != NULL) {
2883                 *cb = *((MonoDelegate **)params [i]);
2884                 i++;
2885                 *state = *((MonoObject **)params [i]);
2886         }
2887
2888         return msg;
2889 }
2890
2891 /**
2892  * mono_method_return_message_restore:
2893  *
2894  * Restore results from message based processing back to arguments pointers
2895  */
2896 void
2897 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2898 {
2899         MonoMethodSignature *sig = method->signature;
2900         int i, j, type, size;
2901         for (i = 0, j = 0; i < sig->param_count; i++) {
2902                 MonoType *pt = sig->params [i];
2903
2904                 if (pt->byref) {
2905                         char *arg = mono_array_get (out_args, gpointer, j);
2906                         type = pt->type;
2907
2908                         switch (type) {
2909                         case MONO_TYPE_VOID:
2910                                 g_assert_not_reached ();
2911                                 break;
2912                         case MONO_TYPE_U1:
2913                         case MONO_TYPE_I1:
2914                         case MONO_TYPE_BOOLEAN:
2915                         case MONO_TYPE_U2:
2916                         case MONO_TYPE_I2:
2917                         case MONO_TYPE_CHAR:
2918                         case MONO_TYPE_U4:
2919                         case MONO_TYPE_I4:
2920                         case MONO_TYPE_I8:
2921                         case MONO_TYPE_U8:
2922                         case MONO_TYPE_R4:
2923                         case MONO_TYPE_R8:
2924                         case MONO_TYPE_VALUETYPE: {
2925                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2926                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
2927                                 break;
2928                         }
2929                         case MONO_TYPE_STRING:
2930                         case MONO_TYPE_CLASS: 
2931                         case MONO_TYPE_ARRAY:
2932                         case MONO_TYPE_SZARRAY:
2933                         case MONO_TYPE_OBJECT:
2934                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2935                                 break;
2936                         default:
2937                                 g_assert_not_reached ();
2938                         }
2939
2940                         j++;
2941                 }
2942         }
2943 }
2944
2945 /**
2946  * mono_load_remote_field:
2947  * @this: pointer to an object
2948  * @klass: klass of the object containing @field
2949  * @field: the field to load
2950  * @res: a storage to store the result
2951  *
2952  * This method is called by the runtime on attempts to load fields of
2953  * transparent proxy objects. @this points to such TP, @klass is the class of
2954  * the object containing @field. @res is a storage location which can be
2955  * used to store the result.
2956  *
2957  * Returns: an address pointing to the value of field.
2958  */
2959 gpointer
2960 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2961 {
2962         static MonoMethod *getter = NULL;
2963         MonoDomain *domain = mono_domain_get ();
2964         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2965         MonoClass *field_class;
2966         MonoMethodMessage *msg;
2967         MonoArray *out_args;
2968         MonoObject *exc;
2969         gpointer tmp;
2970
2971         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2972
2973         if (!res)
2974                 res = &tmp;
2975
2976         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2977                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2978                 return res;
2979         }
2980         
2981         if (!getter) {
2982                 int i;
2983
2984                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2985                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2986                
2987                         if (!strcmp (cm->name, "FieldGetter")) {
2988                                 getter = cm;
2989                                 break;
2990                         }
2991                 }
2992                 g_assert (getter);
2993         }
2994         
2995         field_class = mono_class_from_mono_type (field->type);
2996
2997         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2998         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2999         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3000
3001         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3002         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3003
3004         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3005
3006         if (exc) mono_raise_exception ((MonoException *)exc);
3007
3008         *res = mono_array_get (out_args, MonoObject *, 0);
3009
3010         if (field_class->valuetype) {
3011                 return ((char *)*res) + sizeof (MonoObject);
3012         } else
3013                 return res;
3014 }
3015
3016 MonoObject *
3017 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3018 {
3019         static MonoMethod *getter = NULL;
3020         MonoDomain *domain = mono_domain_get ();
3021         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3022         MonoClass *field_class;
3023         MonoMethodMessage *msg;
3024         MonoArray *out_args;
3025         MonoObject *exc, *res;
3026
3027         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3028
3029         field_class = mono_class_from_mono_type (field->type);
3030
3031         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3032                 gpointer val;
3033                 if (field_class->valuetype) {
3034                         res = mono_object_new (domain, field_class);
3035                         val = ((gchar *) res) + sizeof (MonoObject);
3036                 } else {
3037                         val = &res;
3038                 }
3039                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3040                 return res;
3041         }
3042
3043         if (!getter) {
3044                 int i;
3045
3046                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3047                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3048                
3049                         if (!strcmp (cm->name, "FieldGetter")) {
3050                                 getter = cm;
3051                                 break;
3052                         }
3053                 }
3054                 g_assert (getter);
3055         }
3056         
3057         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3058         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3059         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3060
3061         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3062         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3063
3064         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3065
3066         if (exc) mono_raise_exception ((MonoException *)exc);
3067
3068         res = mono_array_get (out_args, MonoObject *, 0);
3069
3070         return res;
3071 }
3072
3073 /**
3074  * mono_store_remote_field:
3075  * @this: pointer to an object
3076  * @klass: klass of the object containing @field
3077  * @field: the field to load
3078  * @val: the value/object to store
3079  *
3080  * This method is called by the runtime on attempts to store fields of
3081  * transparent proxy objects. @this points to such TP, @klass is the class of
3082  * the object containing @field. @val is the new value to store in @field.
3083  */
3084 void
3085 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3086 {
3087         static MonoMethod *setter = NULL;
3088         MonoDomain *domain = mono_domain_get ();
3089         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3090         MonoClass *field_class;
3091         MonoMethodMessage *msg;
3092         MonoArray *out_args;
3093         MonoObject *exc;
3094         MonoObject *arg;
3095
3096         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3097
3098         field_class = mono_class_from_mono_type (field->type);
3099
3100         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3101                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3102                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3103                 return;
3104         }
3105
3106         if (!setter) {
3107                 int i;
3108
3109                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3110                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3111                
3112                         if (!strcmp (cm->name, "FieldSetter")) {
3113                                 setter = cm;
3114                                 break;
3115                         }
3116                 }
3117                 g_assert (setter);
3118         }
3119
3120         if (field_class->valuetype)
3121                 arg = mono_value_box (domain, field_class, val);
3122         else 
3123                 arg = *((MonoObject **)val);
3124                 
3125
3126         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3127         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3128
3129         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3130         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3131         mono_array_set (msg->args, gpointer, 2, arg);
3132
3133         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3134
3135         if (exc) mono_raise_exception ((MonoException *)exc);
3136 }
3137
3138 void
3139 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3140 {
3141         static MonoMethod *setter = NULL;
3142         MonoDomain *domain = mono_domain_get ();
3143         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3144         MonoClass *field_class;
3145         MonoMethodMessage *msg;
3146         MonoArray *out_args;
3147         MonoObject *exc;
3148
3149         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3150
3151         field_class = mono_class_from_mono_type (field->type);
3152
3153         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3154                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3155                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3156                 return;
3157         }
3158
3159         if (!setter) {
3160                 int i;
3161
3162                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3163                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3164                
3165                         if (!strcmp (cm->name, "FieldSetter")) {
3166                                 setter = cm;
3167                                 break;
3168                         }
3169                 }
3170                 g_assert (setter);
3171         }
3172
3173         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3174         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3175
3176         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3177         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3178         mono_array_set (msg->args, gpointer, 2, arg);
3179
3180         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3181
3182         if (exc) mono_raise_exception ((MonoException *)exc);
3183 }
3184