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