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