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