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