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