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