2003-12-10 Bernie Solomon <bernard@ugsolutions.com>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
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;
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;
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 }
2008
2009 typedef struct {
2010         MonoDomain *orig_domain;
2011         char *ins;
2012         MonoString *res;
2013 } LDStrInfo;
2014
2015 static void
2016 str_lookup (MonoDomain *domain, gpointer user_data)
2017 {
2018         LDStrInfo *info = user_data;
2019         if (info->res || domain == info->orig_domain)
2020                 return;
2021         mono_domain_lock (domain);
2022         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2023         mono_domain_unlock (domain);
2024 }
2025
2026 static MonoString*
2027 mono_string_is_interned_lookup (MonoString *str, int insert)
2028 {
2029         MonoGHashTable *ldstr_table;
2030         MonoString *res;
2031         MonoDomain *domain;
2032         char *ins = g_malloc (4 + str->length * 2);
2033         char *p;
2034         int bloblen;
2035         
2036         /* Encode the length */
2037         p = ins;
2038         mono_metadata_encode_value (2 * str->length, p, &p);
2039         bloblen = p - ins;
2040         p = ins;
2041         mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
2042         bloblen = (p - ins) + 2 * str->length;
2043         /*
2044          * ins is stored in the hash table as a key and needs to have the same
2045          * representation as in the metadata: we swap the character bytes on big
2046          * endian boxes.
2047          */
2048 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2049         {
2050                 int i;
2051                 char *p2 = (char *)mono_string_chars (str);
2052                 for (i = 0; i < str->length; ++i) {
2053                         *p++ = p2 [1];
2054                         *p++ = p2 [0];
2055                         p2 += 2;
2056                 }
2057         }
2058 #else
2059         memcpy (p, mono_string_chars (str), str->length * 2);
2060 #endif
2061         domain = ((MonoObject *)str)->vtable->domain;
2062         ldstr_table = domain->ldstr_table;
2063         mono_domain_lock (domain);
2064         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2065                 mono_domain_unlock (domain);
2066                 g_free (ins);
2067                 return res;
2068         }
2069         if (insert) {
2070                 mono_g_hash_table_insert (ldstr_table, ins, str);
2071                 mono_domain_unlock (domain);
2072                 return str;
2073         } else {
2074                 LDStrInfo ldstr_info;
2075                 ldstr_info.orig_domain = domain;
2076                 ldstr_info.ins = ins;
2077                 ldstr_info.res = NULL;
2078
2079                 mono_domain_foreach (str_lookup, &ldstr_info);
2080                 if (ldstr_info.res) {
2081                         /* 
2082                          * the string was already interned in some other domain:
2083                          * intern it in the current one as well.
2084                          */
2085                         mono_g_hash_table_insert (ldstr_table, ins, str);
2086                         mono_domain_unlock (domain);
2087                         return str;
2088                 }
2089         }
2090         mono_domain_unlock (domain);
2091         g_free (ins);
2092         return NULL;
2093 }
2094
2095 MonoString*
2096 mono_string_is_interned (MonoString *o)
2097 {
2098         return mono_string_is_interned_lookup (o, FALSE);
2099 }
2100
2101 MonoString*
2102 mono_string_intern (MonoString *str)
2103 {
2104         return mono_string_is_interned_lookup (str, TRUE);
2105 }
2106
2107 /*
2108  * mono_ldstr:
2109  * @domain: the domain where the string will be used.
2110  * @image: a metadata context
2111  * @idx: index into the user string table.
2112  * 
2113  * Implementation for the ldstr opcode.
2114  */
2115 MonoString*
2116 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2117 {
2118         const char *str, *sig;
2119         MonoString *o;
2120         size_t len2;
2121
2122         MONO_ARCH_SAVE_REGS;
2123
2124         if (image->assembly->dynamic)
2125                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2126         else
2127                 sig = str = mono_metadata_user_string (image, idx);
2128
2129         mono_domain_lock (domain);
2130         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2131                 mono_domain_unlock (domain);
2132                 return o;
2133         }
2134         
2135         len2 = mono_metadata_decode_blob_size (str, &str);
2136         len2 >>= 1;
2137
2138         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2139 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2140         {
2141                 int i;
2142                 guint16 *p2 = (guint16*)mono_string_chars (o);
2143                 for (i = 0; i < len2; ++i) {
2144                         *p2 = GUINT16_FROM_LE (*p2);
2145                         ++p2;
2146                 }
2147         }
2148 #endif
2149         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2150         mono_domain_unlock (domain);
2151
2152         return o;
2153 }
2154
2155 /*
2156  * mono_string_to_utf8:
2157  * @s: a System.String
2158  *
2159  * Return the UTF8 representation for @s.
2160  * the resulting buffer nedds to be freed with g_free().
2161  */
2162 char *
2163 mono_string_to_utf8 (MonoString *s)
2164 {
2165         char *as;
2166         GError *error = NULL;
2167
2168         if (s == NULL)
2169                 return NULL;
2170
2171         if (!s->length)
2172                 return g_strdup ("");
2173
2174         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2175         if (error) {
2176                 g_warning (error->message);
2177                 g_error_free (error);
2178         }
2179
2180         return as;
2181 }
2182
2183 /*
2184  * mono_string_to_utf16:
2185  * @s: a MonoString
2186  *
2187  * Return an null-terminated array of the utf-16 chars
2188  * contained in @s. The result must be freed with g_free().
2189  * This is a temporary helper until our string implementation
2190  * is reworked to always include the null terminating char.
2191  */
2192 gunichar2 *
2193 mono_string_to_utf16 (MonoString *s)
2194 {
2195         char *as;
2196
2197         if (s == NULL)
2198                 return NULL;
2199
2200         as = g_malloc ((s->length * 2) + 2);
2201         as [(s->length * 2)] = '\0';
2202         as [(s->length * 2) + 1] = '\0';
2203
2204         if (!s->length) {
2205                 return (gunichar2 *)(as);
2206         }
2207         
2208         memcpy (as, mono_string_chars(s), s->length * 2);
2209         return (gunichar2 *)(as);
2210 }
2211
2212 /*
2213  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2214  */
2215 MonoString *
2216 mono_string_from_utf16 (gunichar2 *data)
2217 {
2218         MonoDomain *domain = mono_domain_get ();
2219         int len = 0;
2220
2221         if (!data)
2222                 return NULL;
2223
2224         while (data [len]) len++;
2225
2226         return mono_string_new_utf16 (domain, data, len);
2227 }
2228
2229 static void
2230 default_ex_handler (MonoException *ex)
2231 {
2232         MonoObject *o = (MonoObject*)ex;
2233         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2234         exit (1);
2235 }
2236
2237 static MonoExceptionFunc ex_handler = default_ex_handler;
2238
2239 void
2240 mono_install_handler        (MonoExceptionFunc func)
2241 {
2242         ex_handler = func? func: default_ex_handler;
2243 }
2244
2245 /*
2246  * mono_raise_exception:
2247  * @ex: exception object
2248  *
2249  * Signal the runtime that the exception @ex has been raised in unmanaged code.
2250  */
2251 void
2252 mono_raise_exception (MonoException *ex) 
2253 {
2254         /*
2255          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2256          * that will cause gcc to omit the function epilog, causing problems when
2257          * the JIT tries to walk the stack, since the return address on the stack
2258          * will point into the next function in the executable, not this one.
2259          */
2260
2261         ex_handler (ex);
2262 }
2263
2264 MonoWaitHandle *
2265 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2266 {
2267         MonoWaitHandle *res;
2268
2269         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2270
2271         res->handle = handle;
2272
2273         return res;
2274 }
2275
2276 MonoAsyncResult *
2277 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2278 {
2279         MonoAsyncResult *res;
2280
2281         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2282
2283         res->data = data;
2284         res->async_state = state;
2285         res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
2286         res->sync_completed = FALSE;
2287         res->completed = FALSE;
2288
2289         return res;
2290 }
2291
2292 void
2293 mono_message_init (MonoDomain *domain,
2294                    MonoMethodMessage *this, 
2295                    MonoReflectionMethod *method,
2296                    MonoArray *out_args)
2297 {
2298         MonoMethodSignature *sig = method->method->signature;
2299         MonoString *name;
2300         int i, j;
2301         char **names;
2302         guint8 arg_type;
2303
2304         this->method = method;
2305
2306         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2307         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2308         this->async_result = NULL;
2309         this->call_type = CallType_Sync;
2310
2311         names = g_new (char *, sig->param_count);
2312         mono_method_get_param_names (method->method, (const char **) names);
2313         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2314         
2315         for (i = 0; i < sig->param_count; i++) {
2316                  name = mono_string_new (domain, names [i]);
2317                  mono_array_set (this->names, gpointer, i, name);       
2318         }
2319
2320         g_free (names);
2321         for (i = 0, j = 0; i < sig->param_count; i++) {
2322
2323                 if (sig->params [i]->byref) {
2324                         if (out_args) {
2325                                 gpointer arg = mono_array_get (out_args, gpointer, j);
2326                                 mono_array_set (this->args, gpointer, i, arg);
2327                                 j++;
2328                         }
2329                         arg_type = 2;
2330                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2331                                 arg_type |= 1;
2332                 } else {
2333                         arg_type = 1;
2334                 }
2335                 mono_array_set (this->arg_types, guint8, i, arg_type);
2336         }
2337 }
2338
2339 /**
2340  * mono_remoting_invoke:
2341  * @real_proxy: pointer to a RealProxy object
2342  * @msg: The MonoMethodMessage to execute
2343  * @exc: used to store exceptions
2344  * @out_args: used to store output arguments
2345  *
2346  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2347  * IMessage interface and it is not trivial to extract results from there. So
2348  * we call an helper method PrivateInvoke instead of calling
2349  * RealProxy::Invoke() directly.
2350  *
2351  * Returns: the result object.
2352  */
2353 MonoObject *
2354 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
2355                       MonoObject **exc, MonoArray **out_args)
2356 {
2357         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2358         gpointer pa [4];
2359
2360         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2361
2362         if (!im) {
2363                 MonoClass *klass;
2364                 int i;
2365
2366                 klass = mono_defaults.real_proxy_class; 
2367                        
2368                 for (i = 0; i < klass->method.count; ++i) {
2369                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2370                             klass->methods [i]->signature->param_count == 4) {
2371                                 im = klass->methods [i];
2372                                 break;
2373                         }
2374                 }
2375         
2376                 g_assert (im);
2377                 real_proxy->vtable->domain->private_invoke_method = im;
2378         }
2379
2380         pa [0] = real_proxy;
2381         pa [1] = msg;
2382         pa [2] = exc;
2383         pa [3] = out_args;
2384
2385         return mono_runtime_invoke (im, NULL, pa, exc);
2386 }
2387
2388 MonoObject *
2389 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
2390                      MonoObject **exc, MonoArray **out_args) 
2391 {
2392         MonoDomain *domain; 
2393         MonoMethod *method;
2394         MonoMethodSignature *sig;
2395         int i, j, outarg_count = 0;
2396
2397         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2398
2399                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2400                 if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2401                         target = tp->rp->unwrapped_server;
2402                 } else {
2403                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2404                 }
2405         }
2406
2407         domain = mono_domain_get (); 
2408         method = msg->method->method;
2409         sig = method->signature;
2410
2411         for (i = 0; i < sig->param_count; i++) {
2412                 if (sig->params [i]->byref) 
2413                         outarg_count++;
2414         }
2415
2416         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2417         *exc = NULL;
2418
2419         for (i = 0, j = 0; i < sig->param_count; i++) {
2420                 if (sig->params [i]->byref) {
2421                         gpointer arg;
2422                         arg = mono_array_get (msg->args, gpointer, i);
2423                         mono_array_set (*out_args, gpointer, j, arg);
2424                         j++;
2425                 }
2426         }
2427
2428         return mono_runtime_invoke_array (method, target, msg->args, exc);
2429 }
2430
2431 void
2432 mono_print_unhandled_exception (MonoObject *exc)
2433 {
2434         char *message = (char *) "";
2435         MonoString *str; 
2436         MonoMethod *method;
2437         MonoClass *klass;
2438         gboolean free_message = FALSE;
2439         gint i;
2440
2441         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2442                 klass = exc->vtable->klass;
2443                 method = NULL;
2444                 while (klass && method == NULL) {
2445                         for (i = 0; i < klass->method.count; ++i) {
2446                                 method = klass->methods [i];
2447                                 if (!strcmp ("ToString", method->name) &&
2448                                     method->signature->param_count == 0 &&
2449                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2450                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2451                                         break;
2452                                 }
2453                                 method = NULL;
2454                         }
2455                         
2456                         if (method == NULL)
2457                                 klass = klass->parent;
2458                 }
2459
2460                 g_assert (method);
2461
2462                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2463                 if (str) {
2464                         message = mono_string_to_utf8 (str);
2465                         free_message = TRUE;
2466                 }
2467         }                               
2468
2469         /*
2470          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
2471          *         exc->vtable->klass->name, message);
2472          */
2473         g_printerr ("\nUnhandled Exception: %s\n", message);
2474         
2475         if (free_message)
2476                 g_free (message);
2477 }
2478
2479 /**
2480  * mono_delegate_ctor:
2481  * @this: pointer to an uninitialized delegate object
2482  * @target: target object
2483  * @addr: pointer to native code
2484  *
2485  * This is used to initialize a delegate. We also insert the method_info if
2486  * we find the info with mono_jit_info_table_find().
2487  */
2488 void
2489 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2490 {
2491         MonoDomain *domain = mono_domain_get ();
2492         MonoDelegate *delegate = (MonoDelegate *)this;
2493         MonoMethod *method = NULL;
2494         MonoClass *class;
2495         MonoJitInfo *ji;
2496
2497         g_assert (this);
2498         g_assert (addr);
2499
2500         class = this->vtable->klass;
2501
2502         if ((ji = mono_jit_info_table_find (domain, addr))) {
2503                 method = ji->method;
2504                 delegate->method_info = mono_method_get_object (domain, method, NULL);
2505         }
2506
2507         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2508                 g_assert (method);
2509                 method = mono_marshal_get_remoting_invoke (method);
2510                 delegate->method_ptr = mono_compile_method (method);
2511                 delegate->target = target;
2512         } else {
2513                 delegate->method_ptr = addr;
2514                 delegate->target = target;
2515         }
2516 }
2517
2518 /**
2519  * mono_method_call_message_new:
2520  *
2521  * Translates arguments pointers into a Message.
2522  */
2523 MonoMethodMessage *
2524 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
2525                               MonoDelegate **cb, MonoObject **state)
2526 {
2527         MonoDomain *domain = mono_domain_get ();
2528         MonoMethodSignature *sig = method->signature;
2529         MonoMethodMessage *msg;
2530         int i, count, type;
2531
2532         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
2533         
2534         if (invoke) {
2535                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2536                 count =  sig->param_count - 2;
2537         } else {
2538                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2539                 count =  sig->param_count;
2540         }
2541
2542         for (i = 0; i < count; i++) {
2543                 gpointer vpos;
2544                 MonoClass *class;
2545                 MonoObject *arg;
2546
2547                 if (sig->params [i]->byref)
2548                         vpos = *((gpointer *)params [i]);
2549                 else 
2550                         vpos = params [i];
2551
2552                 type = sig->params [i]->type;
2553                 class = mono_class_from_mono_type (sig->params [i]);
2554
2555                 if (class->valuetype)
2556                         arg = mono_value_box (domain, class, vpos);
2557                 else 
2558                         arg = *((MonoObject **)vpos);
2559                       
2560                 mono_array_set (msg->args, gpointer, i, arg);
2561         }
2562
2563         if (cb != NULL && state != NULL) {
2564                 *cb = *((MonoDelegate **)params [i]);
2565                 i++;
2566                 *state = *((MonoObject **)params [i]);
2567         }
2568
2569         return msg;
2570 }
2571
2572 /**
2573  * mono_method_return_message_restore:
2574  *
2575  * Restore results from message based processing back to arguments pointers
2576  */
2577 void
2578 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2579 {
2580         MonoMethodSignature *sig = method->signature;
2581         int i, j, type, size;
2582         for (i = 0, j = 0; i < sig->param_count; i++) {
2583                 MonoType *pt = sig->params [i];
2584
2585                 if (pt->byref) {
2586                         char *arg = mono_array_get (out_args, gpointer, j);
2587                         type = pt->type;
2588
2589                         switch (type) {
2590                         case MONO_TYPE_VOID:
2591                                 g_assert_not_reached ();
2592                                 break;
2593                         case MONO_TYPE_U1:
2594                         case MONO_TYPE_I1:
2595                         case MONO_TYPE_BOOLEAN:
2596                         case MONO_TYPE_U2:
2597                         case MONO_TYPE_I2:
2598                         case MONO_TYPE_CHAR:
2599                         case MONO_TYPE_U4:
2600                         case MONO_TYPE_I4:
2601                         case MONO_TYPE_I8:
2602                         case MONO_TYPE_U8:
2603                         case MONO_TYPE_R4:
2604                         case MONO_TYPE_R8:
2605                         case MONO_TYPE_VALUETYPE: {
2606                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2607                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
2608                                 break;
2609                         }
2610                         case MONO_TYPE_STRING:
2611                         case MONO_TYPE_CLASS: 
2612                         case MONO_TYPE_ARRAY:
2613                         case MONO_TYPE_SZARRAY:
2614                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2615                                 break;
2616                         default:
2617                                 g_assert_not_reached ();
2618                         }
2619
2620                         j++;
2621                 }
2622         }
2623 }
2624
2625 /**
2626  * mono_load_remote_field:
2627  * @this: pointer to an object
2628  * @klass: klass of the object containing @field
2629  * @field: the field to load
2630  * @res: a storage to store the result
2631  *
2632  * This method is called by the runtime on attempts to load fields of
2633  * transparent proxy objects. @this points to such TP, @klass is the class of
2634  * the object containing @field. @res is a storage location which can be
2635  * used to store the result.
2636  *
2637  * Returns: an address pointing to the value of field.
2638  */
2639 gpointer
2640 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2641 {
2642         static MonoMethod *getter = NULL;
2643         MonoDomain *domain = mono_domain_get ();
2644         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2645         MonoClass *field_class;
2646         MonoMethodMessage *msg;
2647         MonoArray *out_args;
2648         MonoObject *exc;
2649         gpointer tmp;
2650
2651         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2652
2653         if (!res)
2654                 res = &tmp;
2655
2656         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2657                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2658                 return res;
2659         }
2660         
2661         if (!getter) {
2662                 int i;
2663
2664                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2665                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2666                
2667                         if (!strcmp (cm->name, "FieldGetter")) {
2668                                 getter = cm;
2669                                 break;
2670                         }
2671                 }
2672                 g_assert (getter);
2673         }
2674         
2675         field_class = mono_class_from_mono_type (field->type);
2676
2677         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2678         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2679         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2680
2681         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2682         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2683
2684         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2685
2686         if (exc) mono_raise_exception ((MonoException *)exc);
2687
2688         *res = mono_array_get (out_args, MonoObject *, 0);
2689
2690         if (field_class->valuetype) {
2691                 return ((char *)*res) + sizeof (MonoObject);
2692         } else
2693                 return res;
2694 }
2695
2696 MonoObject *
2697 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
2698 {
2699         static MonoMethod *getter = NULL;
2700         MonoDomain *domain = mono_domain_get ();
2701         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2702         MonoClass *field_class;
2703         MonoMethodMessage *msg;
2704         MonoArray *out_args;
2705         MonoObject *exc, *res;
2706
2707         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2708
2709         field_class = mono_class_from_mono_type (field->type);
2710
2711         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2712                 gpointer val;
2713                 if (field_class->valuetype) {
2714                         res = mono_object_new (domain, field_class);
2715                         val = ((gchar *) res) + sizeof (MonoObject);
2716                 } else {
2717                         val = &res;
2718                 }
2719                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
2720                 return res;
2721         }
2722
2723         if (!getter) {
2724                 int i;
2725
2726                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2727                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2728                
2729                         if (!strcmp (cm->name, "FieldGetter")) {
2730                                 getter = cm;
2731                                 break;
2732                         }
2733                 }
2734                 g_assert (getter);
2735         }
2736         
2737         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2738         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2739         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2740
2741         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2742         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2743
2744         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2745
2746         if (exc) mono_raise_exception ((MonoException *)exc);
2747
2748         res = mono_array_get (out_args, MonoObject *, 0);
2749
2750         return res;
2751 }
2752
2753 /**
2754  * mono_store_remote_field:
2755  * @this: pointer to an object
2756  * @klass: klass of the object containing @field
2757  * @field: the field to load
2758  * @val: the value/object to store
2759  *
2760  * This method is called by the runtime on attempts to store fields of
2761  * transparent proxy objects. @this points to such TP, @klass is the class of
2762  * the object containing @field. @val is the new value to store in @field.
2763  */
2764 void
2765 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
2766 {
2767         static MonoMethod *setter = NULL;
2768         MonoDomain *domain = mono_domain_get ();
2769         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2770         MonoClass *field_class;
2771         MonoMethodMessage *msg;
2772         MonoArray *out_args;
2773         MonoObject *exc;
2774         MonoObject *arg;
2775
2776         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2777
2778         field_class = mono_class_from_mono_type (field->type);
2779
2780         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2781                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
2782                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
2783                 return;
2784         }
2785
2786         if (!setter) {
2787                 int i;
2788
2789                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2790                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2791                
2792                         if (!strcmp (cm->name, "FieldSetter")) {
2793                                 setter = cm;
2794                                 break;
2795                         }
2796                 }
2797                 g_assert (setter);
2798         }
2799
2800         if (field_class->valuetype)
2801                 arg = mono_value_box (domain, field_class, val);
2802         else 
2803                 arg = *((MonoObject **)val);
2804                 
2805
2806         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2807         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
2808
2809         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2810         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2811         mono_array_set (msg->args, gpointer, 2, arg);
2812
2813         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2814
2815         if (exc) mono_raise_exception ((MonoException *)exc);
2816 }
2817
2818 void
2819 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
2820 {
2821         static MonoMethod *setter = NULL;
2822         MonoDomain *domain = mono_domain_get ();
2823         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2824         MonoClass *field_class;
2825         MonoMethodMessage *msg;
2826         MonoArray *out_args;
2827         MonoObject *exc;
2828
2829         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2830
2831         field_class = mono_class_from_mono_type (field->type);
2832
2833         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2834                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
2835                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
2836                 return;
2837         }
2838
2839         if (!setter) {
2840                 int i;
2841
2842                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2843                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2844                
2845                         if (!strcmp (cm->name, "FieldSetter")) {
2846                                 setter = cm;
2847                                 break;
2848                         }
2849                 }
2850                 g_assert (setter);
2851         }
2852
2853         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2854         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
2855
2856         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2857         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2858         mono_array_set (msg->args, gpointer, 2, arg);
2859
2860         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2861
2862         if (exc) mono_raise_exception ((MonoException *)exc);
2863 }
2864