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