2003-06-17 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <mono/metadata/mono-endian.h>
15 #include <mono/metadata/tabledefs.h>
16 #include <mono/metadata/tokentype.h>
17 #include <mono/metadata/loader.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/gc-internal.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/appdomain.h>
22 #include <mono/metadata/assembly.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/metadata/marshal.h>
25 #include "mono/metadata/debug-helpers.h"
26 #include "mono/metadata/marshal.h"
27 #include <mono/metadata/threads.h>
28 #include <mono/metadata/environment.h>
29 #include "mono/metadata/profiler-private.h"
30 #include <mono/os/gc_wrapper.h>
31
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                 /* set exitcode only in the main thread? */
969                 mono_environment_exitcode_set (1);
970                 if (domain != mono_root_domain || !delegate) {
971                         mono_print_unhandled_exception (exc);
972                 } else {
973                         MonoObject *e = NULL;
974                         gpointer pa [2];
975
976                         pa [0] = domain->domain;
977                         pa [1] = create_unhandled_exception_eventargs (exc);
978                         mono_runtime_delegate_invoke (delegate, pa, &e);
979                         
980                         if (e) {
981                                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
982                                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
983                                 g_free (msg);
984                         }
985                 }
986         }
987 }
988
989 /*
990  * Launch a new thread to start all setup that requires managed code
991  * to be executed.
992  *
993  * main_func is called back from the thread with main_args as the
994  * parameter.  The callback function is expected to start Main()
995  * eventually.  This function then waits for all managed threads to
996  * finish.
997  */
998 void
999 mono_runtime_exec_managed_code (MonoDomain *domain,
1000                                 MonoMainThreadFunc main_func,
1001                                 gpointer main_args)
1002 {
1003         mono_thread_create (domain, main_func, main_args);
1004
1005         mono_thread_manage ();
1006 }
1007
1008 /*
1009  * Execute a standard Main() method (args doesn't contain the
1010  * executable name).
1011  */
1012 int
1013 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1014 {
1015         MonoDomain *domain;
1016         gpointer pa [1];
1017         int rval;
1018
1019         g_assert (args);
1020
1021         pa [0] = args;
1022
1023         domain = mono_object_domain (args);
1024         if (!domain->entry_assembly) {
1025                 domain->entry_assembly = method->klass->image->assembly;
1026                 ves_icall_System_AppDomainSetup_InitAppDomainSetup (domain->setup);
1027         }
1028
1029         /* FIXME: check signature of method */
1030         if (method->signature->ret->type == MONO_TYPE_I4) {
1031                 MonoObject *res;
1032                 res = mono_runtime_invoke (method, NULL, pa, exc);
1033                 if (!exc || !*exc)
1034                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1035                 else
1036                         rval = -1;
1037
1038                 mono_environment_exitcode_set (rval);
1039         } else {
1040                 mono_runtime_invoke (method, NULL, pa, exc);
1041                 if (!exc || !*exc)
1042                         rval = 0;
1043                 else {
1044                         /* If the return type of Main is void, only
1045                          * set the exitcode if an exception was thrown
1046                          * (we don't want to blow away an
1047                          * explicitly-set exit code)
1048                          */
1049                         rval = -1;
1050                         mono_environment_exitcode_set (rval);
1051                 }
1052         }
1053
1054         return rval;
1055 }
1056
1057 void
1058 mono_install_runtime_invoke (MonoInvokeFunc func)
1059 {
1060         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1061 }
1062
1063 MonoObject*
1064 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1065                            MonoObject **exc)
1066 {
1067         MonoMethodSignature *sig = method->signature;
1068         gpointer *pa = NULL;
1069         int i;
1070                 
1071         if (NULL != params) {
1072                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1073                 for (i = 0; i < mono_array_length (params); i++) {
1074                         if (sig->params [i]->byref) {
1075                                 /* nothing to do */
1076                         }
1077
1078                         switch (sig->params [i]->type) {
1079                         case MONO_TYPE_U1:
1080                         case MONO_TYPE_I1:
1081                         case MONO_TYPE_BOOLEAN:
1082                         case MONO_TYPE_U2:
1083                         case MONO_TYPE_I2:
1084                         case MONO_TYPE_CHAR:
1085                         case MONO_TYPE_U:
1086                         case MONO_TYPE_I:
1087                         case MONO_TYPE_U4:
1088                         case MONO_TYPE_I4:
1089                         case MONO_TYPE_U8:
1090                         case MONO_TYPE_I8:
1091                         case MONO_TYPE_R4:
1092                         case MONO_TYPE_R8:
1093                         case MONO_TYPE_VALUETYPE:
1094                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1095                                 break;
1096                         case MONO_TYPE_STRING:
1097                         case MONO_TYPE_OBJECT:
1098                         case MONO_TYPE_CLASS:
1099                         case MONO_TYPE_ARRAY:
1100                         case MONO_TYPE_SZARRAY:
1101                                 if (sig->params [i]->byref)
1102                                         pa [i] = &(((gpointer *)params->vector)[i]);
1103                                 else
1104                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
1105                                 break;
1106                         default:
1107                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1108                         }
1109                 }
1110         }
1111
1112         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1113                 if (!obj) {
1114                         obj = mono_object_new (mono_domain_get (), method->klass);
1115                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1116                                 method = mono_marshal_get_remoting_invoke (method->klass->vtable [method->slot]);
1117                         }
1118                 }
1119                 mono_runtime_invoke (method, obj, pa, exc);
1120                 return obj;
1121         } else
1122                 return mono_runtime_invoke (method, obj, pa, exc);
1123 }
1124
1125 G_GNUC_NORETURN static void
1126 out_of_memory (size_t size)
1127 {
1128         /* 
1129          * we could allocate at program startup some memory that we could release 
1130          * back to the system at this point if we're really low on memory (ie, size is
1131          * lower than the memory we set apart)
1132          */
1133         MonoException * ex = mono_exception_from_name (mono_defaults.corlib, "System", "OutOfMemoryException");
1134         mono_raise_exception (ex);
1135 }
1136
1137 /**
1138  * mono_object_allocate:
1139  * @size: number of bytes to allocate
1140  *
1141  * This is a very simplistic routine until we have our GC-aware
1142  * memory allocator. 
1143  *
1144  * Returns: an allocated object of size @size, or NULL on failure.
1145  */
1146 static void *
1147 mono_object_allocate (size_t size)
1148 {
1149 #if HAVE_BOEHM_GC
1150         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1151         void *o = GC_MALLOC (size);
1152 #else
1153         void *o = calloc (1, size);
1154 #endif
1155         mono_stats.new_object_count++;
1156
1157         if (!o)
1158                 out_of_memory (size);
1159         return o;
1160 }
1161
1162 #if CREATION_SPEEDUP
1163 static void *
1164 mono_object_allocate_spec (size_t size, void *gcdescr)
1165 {
1166         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1167         void *o = GC_GCJ_MALLOC (size, gcdescr);
1168         mono_stats.new_object_count++;
1169
1170         if (!o)
1171                 out_of_memory (size);
1172         return o;
1173 }
1174 #endif
1175
1176 /**
1177  * mono_object_free:
1178  *
1179  * Frees the memory used by the object.  Debugging purposes
1180  * only, as we will have our GC system.
1181  */
1182 void
1183 mono_object_free (MonoObject *o)
1184 {
1185 #if HAVE_BOEHM_GC
1186         g_error ("mono_object_free called with boehm gc.");
1187 #else
1188         MonoClass *c = o->vtable->klass;
1189         
1190         memset (o, 0, c->instance_size);
1191         free (o);
1192 #endif
1193 }
1194
1195 /**
1196  * mono_object_new:
1197  * @klass: the class of the object that we want to create
1198  *
1199  * Returns: A newly created object whose definition is
1200  * looked up using @klass
1201  */
1202 MonoObject *
1203 mono_object_new (MonoDomain *domain, MonoClass *klass)
1204 {
1205         MONO_ARCH_SAVE_REGS;
1206         return mono_object_new_specific (mono_class_vtable (domain, klass));
1207 }
1208
1209 /**
1210  * mono_object_new_specific:
1211  * @vtable: the vtable of the object that we want to create
1212  *
1213  * Returns: A newly created object with class and domain specified
1214  * by @vtable
1215  */
1216 MonoObject *
1217 mono_object_new_specific (MonoVTable *vtable)
1218 {
1219         MonoObject *o;
1220
1221         MONO_ARCH_SAVE_REGS;
1222         
1223         if (vtable->remote)
1224         {
1225                 gpointer pa [1];
1226                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1227
1228                 if (im == NULL) {
1229                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1230                         int i;
1231
1232                         if (!klass->inited)
1233                                 mono_class_init (klass);
1234
1235                         for (i = 0; i < klass->method.count; ++i) {
1236                                 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1237                                         klass->methods [i]->signature->param_count == 1) {
1238                                         im = klass->methods [i];
1239                                         break;
1240                                 }
1241                         }
1242                         g_assert (im);
1243                         vtable->domain->create_proxy_for_type_method = im;
1244                 }
1245         
1246                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1247
1248                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
1249                 if (o != NULL) return o;
1250         }
1251
1252         return mono_object_new_alloc_specific (vtable);
1253 }
1254
1255 MonoObject *
1256 mono_object_new_alloc_specific (MonoVTable *vtable)
1257 {
1258         MonoObject *o;
1259
1260 #if CREATION_SPEEDUP
1261         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1262                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1263         } else {
1264 //              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1265                 o = mono_object_allocate (vtable->klass->instance_size);
1266                 o->vtable = vtable;
1267         }
1268 #else
1269         o = mono_object_allocate (vtable->klass->instance_size);
1270         o->vtable = vtable;
1271 #endif
1272         if (vtable->klass->has_finalize)
1273                 mono_object_register_finalizer (o);
1274         
1275         mono_profiler_allocation (o, vtable->klass);
1276         return o;
1277 }
1278
1279 /**
1280  * mono_object_new_from_token:
1281  * @image: Context where the type_token is hosted
1282  * @token: a token of the type that we want to create
1283  *
1284  * Returns: A newly created object whose definition is
1285  * looked up using @token in the @image image
1286  */
1287 MonoObject *
1288 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
1289 {
1290         MonoClass *class;
1291
1292         class = mono_class_get (image, token);
1293
1294         return mono_object_new (domain, class);
1295 }
1296
1297
1298 /**
1299  * mono_object_clone:
1300  * @obj: the object to clone
1301  *
1302  * Returns: A newly created object who is a shallow copy of @obj
1303  */
1304 MonoObject *
1305 mono_object_clone (MonoObject *obj)
1306 {
1307         MonoObject *o;
1308         int size;
1309
1310         size = obj->vtable->klass->instance_size;
1311         o = mono_object_allocate (size);
1312         mono_profiler_allocation (o, obj->vtable->klass);
1313
1314         memcpy (o, obj, size);
1315
1316         if (obj->vtable->klass->has_finalize)
1317                 mono_object_register_finalizer (o);
1318         return o;
1319 }
1320
1321 /**
1322  * mono_array_clone:
1323  * @array: the array to clone
1324  *
1325  * Returns: A newly created array who is a shallow copy of @array
1326  */
1327 MonoArray*
1328 mono_array_clone (MonoArray *array)
1329 {
1330         MonoArray *o;
1331         int size, i;
1332         guint32 *sizes;
1333         MonoClass *klass = array->obj.vtable->klass;
1334
1335         MONO_ARCH_SAVE_REGS;
1336
1337         if (array->bounds == NULL) {
1338                 size = mono_array_length (array);
1339                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1340                                          klass, &size, NULL);
1341
1342                 size *= mono_array_element_size (klass);
1343                 memcpy (o, array, sizeof (MonoArray) + size);
1344
1345                 return o;
1346         }
1347         
1348         sizes = alloca (klass->rank * sizeof(guint32) * 2);
1349         size = mono_array_element_size (klass);
1350         for (i = 0; i < klass->rank; ++i) {
1351                 sizes [i] = array->bounds [i].length;
1352                 size *= array->bounds [i].length;
1353                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1354         }
1355         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
1356                                  klass, sizes, sizes + klass->rank);
1357         memcpy (o, array, sizeof(MonoArray) + size);
1358
1359         return o;
1360 }
1361
1362 /*
1363  * mono_array_new_full:
1364  * @domain: domain where the object is created
1365  * @array_class: array class
1366  * @lengths: lengths for each dimension in the array
1367  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1368  *
1369  * This routine creates a new array objects with the given dimensions,
1370  * lower bounds and type.
1371  */
1372 MonoArray*
1373 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
1374                      guint32 *lengths, guint32 *lower_bounds)
1375 {
1376         guint32 byte_len, len;
1377         MonoObject *o;
1378         MonoArray *array;
1379         MonoArrayBounds *bounds;
1380         MonoVTable *vtable;
1381         int i;
1382
1383         if (!array_class->inited)
1384                 mono_class_init (array_class);
1385
1386         byte_len = mono_array_element_size (array_class);
1387         len = 1;
1388
1389         if (array_class->rank == 1 &&
1390             (lower_bounds == NULL || lower_bounds [0] == 0)) {
1391                 bounds = NULL;
1392                 len = lengths [0];
1393         } else {
1394         #if HAVE_BOEHM_GC
1395                 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1396         #else
1397                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1398         #endif
1399                 for (i = 0; i < array_class->rank; ++i) {
1400                         bounds [i].length = lengths [i];
1401                         len *= lengths [i];
1402                 }
1403
1404                 if (lower_bounds)
1405                         for (i = 0; i < array_class->rank; ++i)
1406                                 bounds [i].lower_bound = lower_bounds [i];
1407         }
1408
1409         byte_len *= len;
1410         /* 
1411          * Following three lines almost taken from mono_object_new ():
1412          * they need to be kept in sync.
1413          */
1414         vtable = mono_class_vtable (domain, array_class);
1415 #if CREATION_SPEEDUP
1416         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1417                 o = mono_object_allocate_spec (sizeof (MonoArray) + byte_len, vtable);
1418         else {
1419                 o = mono_object_allocate (sizeof (MonoArray) + byte_len);
1420                 o->vtable = vtable;
1421         }
1422 #else
1423         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
1424         o->vtable = vtable;
1425 #endif
1426
1427         array = (MonoArray*)o;
1428
1429         array->bounds = bounds;
1430         array->max_length = len;
1431
1432         mono_profiler_allocation (o, array_class);
1433
1434         return array;
1435 }
1436
1437 /*
1438  * mono_array_new:
1439  * @domain: domain where the object is created
1440  * @eclass: element class
1441  * @n: number of array elements
1442  *
1443  * This routine creates a new szarray with @n elements of type @eclass.
1444  */
1445 MonoArray *
1446 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1447 {
1448         MonoClass *ac;
1449
1450         MONO_ARCH_SAVE_REGS;
1451
1452         ac = mono_array_class_get (&eclass->byval_arg, 1);
1453         g_assert (ac != NULL);
1454
1455         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1456 }
1457
1458 /*
1459  * mono_array_new_specific:
1460  * @vtable: a vtable in the appropriate domain for an initialized class
1461  * @n: number of array elements
1462  *
1463  * This routine is a fast alternative to mono_array_new() for code which
1464  * can be sure about the domain it operates in.
1465  */
1466 MonoArray *
1467 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1468 {
1469         MonoObject *o;
1470         MonoArray *ao;
1471         gsize byte_len;
1472
1473         MONO_ARCH_SAVE_REGS;
1474
1475         byte_len = n * mono_array_element_size (vtable->klass);
1476 #if CREATION_SPEEDUP
1477         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1478                 o = mono_object_allocate_spec (sizeof (MonoArray) + byte_len, vtable);
1479         } else {
1480 //              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1481                 o = mono_object_allocate (sizeof (MonoArray) + byte_len);
1482                 o->vtable = vtable;
1483         }
1484 #else
1485         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
1486         o->vtable = vtable;
1487 #endif
1488
1489         ao = (MonoArray *)o;
1490         ao->bounds = NULL;
1491         ao->max_length = n;
1492         mono_profiler_allocation (o, vtable->klass);
1493
1494         return ao;
1495 }
1496
1497 /**
1498  * mono_string_new_utf16:
1499  * @text: a pointer to an utf16 string
1500  * @len: the length of the string
1501  *
1502  * Returns: A newly created string object which contains @text.
1503  */
1504 MonoString *
1505 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
1506 {
1507         MonoString *s;
1508         
1509         s = mono_string_new_size (domain, len);
1510         g_assert (s != NULL);
1511
1512         memcpy (mono_string_chars (s), text, len * 2);
1513
1514         return s;
1515 }
1516
1517 /**
1518  * mono_string_new_size:
1519  * @text: a pointer to an utf16 string
1520  * @len: the length of the string
1521  *
1522  * Returns: A newly created string object of @len
1523  */
1524 MonoString *
1525 mono_string_new_size (MonoDomain *domain, gint32 len)
1526 {
1527         MonoString *s;
1528         MonoVTable *vtable;
1529
1530         vtable = mono_class_vtable (domain, mono_defaults.string_class);
1531
1532 #if CREATION_SPEEDUP
1533         s = mono_object_allocate_spec (sizeof (MonoString) + ((len + 1) * 2), vtable);
1534 #else
1535         s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
1536         s->object.vtable = vtable;
1537 #endif
1538
1539         s->length = len;
1540         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
1541
1542         return s;
1543 }
1544
1545 /*
1546  * mono_string_new_len:
1547  * @text: a pointer to an utf8 string
1548  * @length: number of bytes in @text to consider
1549  *
1550  * Returns: A newly created string object which contains @text.
1551  */
1552 MonoString*
1553 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
1554 {
1555         GError *error = NULL;
1556         MonoString *o = NULL;
1557         guint16 *ut;
1558         glong items_written;
1559
1560         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
1561
1562         if (!error)
1563                 o = mono_string_new_utf16 (domain, ut, items_written);
1564         else 
1565                 g_error_free (error);
1566
1567         g_free (ut);
1568
1569         return o;
1570 }
1571
1572 /**
1573  * mono_string_new:
1574  * @text: a pointer to an utf8 string
1575  *
1576  * Returns: A newly created string object which contains @text.
1577  */
1578 MonoString*
1579 mono_string_new (MonoDomain *domain, const char *text)
1580 {
1581         GError *error = NULL;
1582         MonoString *o = NULL;
1583         guint16 *ut;
1584         glong items_written;
1585         int l;
1586
1587         l = strlen (text);
1588         
1589         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
1590
1591         if (!error)
1592                 o = mono_string_new_utf16 (domain, ut, items_written);
1593         else 
1594                 g_error_free (error);
1595
1596         g_free (ut);
1597
1598         return o;
1599 }
1600
1601 /*
1602  * mono_string_new_wrapper:
1603  * @text: pointer to utf8 characters.
1604  *
1605  * Helper function to create a string object from @text in the current domain.
1606  */
1607 MonoString*
1608 mono_string_new_wrapper (const char *text)
1609 {
1610         MonoDomain *domain = mono_domain_get ();
1611
1612         MONO_ARCH_SAVE_REGS;
1613
1614         if (text)
1615                 return mono_string_new (domain, text);
1616
1617         return NULL;
1618 }
1619
1620 /**
1621  * mono_value_box:
1622  * @class: the class of the value
1623  * @value: a pointer to the unboxed data
1624  *
1625  * Returns: A newly created object which contains @value.
1626  */
1627 MonoObject *
1628 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
1629 {
1630         MonoObject *res;
1631         int size;
1632         MonoVTable *vtable;
1633
1634         g_assert (class->valuetype);
1635
1636         vtable = mono_class_vtable (domain, class);
1637         size = mono_class_instance_size (class);
1638         res = mono_object_allocate (size);
1639         res->vtable = vtable;
1640         mono_profiler_allocation (res, class);
1641
1642         size = size - sizeof (MonoObject);
1643
1644 #if NO_UNALIGNED_ACCESS
1645         memcpy ((char *)res + sizeof (MonoObject), value, size);
1646 #else
1647         switch (size) {
1648         case 1:
1649                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
1650                 break;
1651         case 2:
1652                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
1653                 break;
1654         case 4:
1655                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
1656                 break;
1657         case 8:
1658                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
1659                 break;
1660         default:
1661                 memcpy ((char *)res + sizeof (MonoObject), value, size);
1662         }
1663 #endif
1664         if (class->has_finalize)
1665                 mono_object_register_finalizer (res);
1666         return res;
1667 }
1668
1669 gpointer
1670 mono_object_unbox (MonoObject *obj)
1671 {
1672         /* add assert for valuetypes? */
1673         return ((char*)obj) + sizeof (MonoObject);
1674 }
1675
1676 /**
1677  * mono_object_isinst:
1678  * @obj: an object
1679  * @klass: a pointer to a class 
1680  *
1681  * Returns: @obj if @obj is derived from @klass
1682  */
1683 MonoObject *
1684 mono_object_isinst (MonoObject *obj, MonoClass *klass)
1685 {
1686         MonoVTable *vt;
1687         MonoClass *oklass;
1688
1689         if (!obj)
1690                 return NULL;
1691
1692         vt = obj->vtable;
1693         oklass = vt->klass;
1694
1695         if (!klass->inited)
1696                 mono_class_init (klass);
1697
1698         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1699                 if ((klass->interface_id <= vt->max_interface_id) &&
1700                     vt->interface_offsets [klass->interface_id])
1701                         return obj;
1702         } else {
1703                 if (oklass == mono_defaults.transparent_proxy_class) {
1704                         /* fixme: add check for IRemotingTypeInfo */
1705                         oklass = ((MonoTransparentProxy *)obj)->klass;
1706                 }
1707                 if (klass->rank) {
1708                         if (oklass->rank == klass->rank && mono_class_has_parent (oklass->cast_class, klass->cast_class))
1709                                 return obj;
1710                         
1711                 } else if (mono_class_has_parent (oklass, klass))
1712                         return obj;
1713         }
1714
1715         return NULL;
1716 }
1717
1718 typedef struct {
1719         MonoDomain *orig_domain;
1720         char *ins;
1721         MonoString *res;
1722 } LDStrInfo;
1723
1724 static void
1725 str_lookup (MonoDomain *domain, gpointer user_data)
1726 {
1727         LDStrInfo *info = user_data;
1728         if (info->res || domain == info->orig_domain)
1729                 return;
1730         mono_domain_lock (domain);
1731         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
1732         mono_domain_unlock (domain);
1733 }
1734
1735 static MonoString*
1736 mono_string_is_interned_lookup (MonoString *str, int insert)
1737 {
1738         MonoGHashTable *ldstr_table;
1739         MonoString *res;
1740         MonoDomain *domain;
1741         char *ins = g_malloc (4 + str->length * 2);
1742         char *p;
1743         int bloblen;
1744         
1745         /* Encode the length */
1746         p = ins;
1747         mono_metadata_encode_value (2 * str->length, p, &p);
1748         bloblen = p - ins;
1749         p = ins;
1750         mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
1751         bloblen = (p - ins) + 2 * str->length;
1752         /*
1753          * ins is stored in the hash table as a key and needs to have the same
1754          * representation as in the metadata: we swap the character bytes on big
1755          * endian boxes.
1756          */
1757 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1758         {
1759                 int i;
1760                 char *p2 = mono_string_chars (str);
1761                 for (i = 0; i < str->length; ++i) {
1762                         *p++ = p2 [1];
1763                         *p++ = p2 [0];
1764                         p2 += 2;
1765                 }
1766         }
1767 #else
1768         memcpy (p, mono_string_chars (str), str->length * 2);
1769 #endif
1770         domain = ((MonoObject *)str)->vtable->domain;
1771         ldstr_table = domain->ldstr_table;
1772         mono_domain_lock (domain);
1773         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
1774                 mono_domain_unlock (domain);
1775                 g_free (ins);
1776                 return res;
1777         }
1778         if (insert) {
1779                 mono_g_hash_table_insert (ldstr_table, ins, str);
1780                 mono_domain_unlock (domain);
1781                 return str;
1782         } else {
1783                 LDStrInfo ldstr_info;
1784                 ldstr_info.orig_domain = domain;
1785                 ldstr_info.ins = ins;
1786                 ldstr_info.res = NULL;
1787
1788                 mono_domain_foreach (str_lookup, &ldstr_info);
1789                 if (ldstr_info.res) {
1790                         /* 
1791                          * the string was already interned in some other domain:
1792                          * intern it in the current one as well.
1793                          */
1794                         mono_g_hash_table_insert (ldstr_table, ins, str);
1795                         mono_domain_unlock (domain);
1796                         return str;
1797                 }
1798         }
1799         mono_domain_unlock (domain);
1800         g_free (ins);
1801         return NULL;
1802 }
1803
1804 MonoString*
1805 mono_string_is_interned (MonoString *o)
1806 {
1807         return mono_string_is_interned_lookup (o, FALSE);
1808 }
1809
1810 MonoString*
1811 mono_string_intern (MonoString *str)
1812 {
1813         return mono_string_is_interned_lookup (str, TRUE);
1814 }
1815
1816 /*
1817  * mono_ldstr:
1818  * @domain: the domain where the string will be used.
1819  * @image: a metadata context
1820  * @idx: index into the user string table.
1821  * 
1822  * Implementation for the ldstr opcode.
1823  */
1824 MonoString*
1825 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1826 {
1827         const char *str, *sig;
1828         MonoString *o;
1829         size_t len2;
1830
1831         MONO_ARCH_SAVE_REGS;
1832
1833         if (image->assembly->dynamic)
1834                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
1835         else
1836                 sig = str = mono_metadata_user_string (image, idx);
1837
1838         mono_domain_lock (domain);
1839         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
1840                 mono_domain_unlock (domain);
1841                 return o;
1842         }
1843         
1844         len2 = mono_metadata_decode_blob_size (str, &str);
1845         len2 >>= 1;
1846
1847         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
1848 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1849         {
1850                 int i;
1851                 guint16 *p2 = (guint16*)mono_string_chars (o);
1852                 for (i = 0; i < len2; ++i) {
1853                         *p2 = GUINT16_FROM_LE (*p2);
1854                         ++p2;
1855                 }
1856         }
1857 #endif
1858         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
1859         mono_domain_unlock (domain);
1860
1861         return o;
1862 }
1863
1864 /*
1865  * mono_string_to_utf8:
1866  * @s: a System.String
1867  *
1868  * Return the UTF8 representation for @s.
1869  * the resulting buffer nedds to be freed with g_free().
1870  */
1871 char *
1872 mono_string_to_utf8 (MonoString *s)
1873 {
1874         char *as;
1875         GError *error = NULL;
1876
1877         if (s == NULL)
1878                 return NULL;
1879
1880         if (!s->length)
1881                 return g_strdup ("");
1882
1883         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
1884         if (error) {
1885                 g_warning (error->message);
1886                 g_error_free (error);
1887         }
1888
1889         return as;
1890 }
1891
1892 /*
1893  * mono_string_to_utf16:
1894  * @s: a MonoString
1895  *
1896  * Return an null-terminated array of the utf-16 chars
1897  * contained in @s. The result must be freed with g_free().
1898  * This is a temporary helper until our string implementation
1899  * is reworked to always include the null terminating char.
1900  */
1901 gunichar2 *
1902 mono_string_to_utf16 (MonoString *s)
1903 {
1904         char *as;
1905
1906         if (s == NULL)
1907                 return NULL;
1908
1909         as = g_malloc ((s->length * 2) + 2);
1910         as [(s->length * 2)] = '\0';
1911         as [(s->length * 2) + 1] = '\0';
1912
1913         if (!s->length) {
1914                 return (gunichar2 *)(as);
1915         }
1916         
1917         memcpy (as, mono_string_chars(s), s->length * 2);
1918         return (gunichar2 *)(as);
1919 }
1920
1921 /*
1922  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
1923  */
1924 MonoString *
1925 mono_string_from_utf16 (gunichar2 *data)
1926 {
1927         MonoDomain *domain = mono_domain_get ();
1928         int len = 0;
1929
1930         if (!data)
1931                 return NULL;
1932
1933         while (data [len]) len++;
1934
1935         return mono_string_new_utf16 (domain, data, len);
1936 }
1937
1938 static void
1939 default_ex_handler (MonoException *ex)
1940 {
1941         MonoObject *o = (MonoObject*)ex;
1942         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
1943 }
1944
1945 static MonoExceptionFunc ex_handler = default_ex_handler;
1946
1947 void
1948 mono_install_handler        (MonoExceptionFunc func)
1949 {
1950         ex_handler = func? func: default_ex_handler;
1951 }
1952
1953 /*
1954  * mono_raise_exception:
1955  * @ex: exception object
1956  *
1957  * Signal the runtime that the exception @ex has been raised in unmanaged code.
1958  */
1959 void
1960 mono_raise_exception (MonoException *ex) 
1961 {
1962         ex_handler (ex);
1963 }
1964
1965 MonoWaitHandle *
1966 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
1967 {
1968         MonoWaitHandle *res;
1969
1970         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
1971
1972         res->handle = handle;
1973
1974         return res;
1975 }
1976
1977 MonoAsyncResult *
1978 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
1979 {
1980         MonoAsyncResult *res;
1981
1982         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
1983
1984         res->data = data;
1985         res->async_state = state;
1986         res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
1987         res->sync_completed = FALSE;
1988         res->completed = FALSE;
1989
1990         return res;
1991 }
1992
1993 void
1994 mono_message_init (MonoDomain *domain,
1995                    MonoMethodMessage *this, 
1996                    MonoReflectionMethod *method,
1997                    MonoArray *out_args)
1998 {
1999         MonoMethodSignature *sig = method->method->signature;
2000         MonoString *name;
2001         int i, j;
2002         char **names;
2003         guint8 arg_type;
2004
2005         this->method = method;
2006
2007         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2008         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2009
2010         names = g_new (char *, sig->param_count);
2011         mono_method_get_param_names (method->method, (const char **) names);
2012         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2013         
2014         for (i = 0; i < sig->param_count; i++) {
2015                  name = mono_string_new (domain, names [i]);
2016                  mono_array_set (this->names, gpointer, i, name);       
2017         }
2018
2019         g_free (names);
2020         
2021         for (i = 0, j = 0; i < sig->param_count; i++) {
2022
2023                 if (sig->params [i]->byref) {
2024                         if (out_args) {
2025                                 gpointer arg = mono_array_get (out_args, gpointer, j);
2026                                 mono_array_set (this->args, gpointer, i, arg);
2027                                 j++;
2028                         }
2029                         arg_type = 2;
2030                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN)
2031                                 arg_type |= 1;
2032                 } else {
2033                         arg_type = 1;
2034                 }
2035
2036                 mono_array_set (this->arg_types, guint8, i, arg_type);
2037         }
2038 }
2039
2040 /**
2041  * mono_remoting_invoke:
2042  * @real_proxy: pointer to a RealProxy object
2043  * @msg: The MonoMethodMessage to execute
2044  * @exc: used to store exceptions
2045  * @out_args: used to store output arguments
2046  *
2047  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2048  * IMessage interface and it is not trivial to extract results from there. So
2049  * we call an helper method PrivateInvoke instead of calling
2050  * RealProxy::Invoke() directly.
2051  *
2052  * Returns: the result object.
2053  */
2054 MonoObject *
2055 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
2056                       MonoObject **exc, MonoArray **out_args)
2057 {
2058         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2059         gpointer pa [4];
2060
2061         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2062
2063         if (!im) {
2064                 MonoClass *klass;
2065                 int i;
2066
2067                 klass = mono_defaults.real_proxy_class; 
2068                        
2069                 for (i = 0; i < klass->method.count; ++i) {
2070                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2071                             klass->methods [i]->signature->param_count == 4) {
2072                                 im = klass->methods [i];
2073                                 break;
2074                         }
2075                 }
2076         
2077                 g_assert (im);
2078                 real_proxy->vtable->domain->private_invoke_method = im;
2079         }
2080
2081         pa [0] = real_proxy;
2082         pa [1] = msg;
2083         pa [2] = exc;
2084         pa [3] = out_args;
2085
2086         return mono_runtime_invoke (im, NULL, pa, exc);
2087 }
2088
2089 MonoObject *
2090 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
2091                      MonoObject **exc, MonoArray **out_args) 
2092 {
2093         MonoDomain *domain; 
2094         MonoMethod *method;
2095         MonoMethodSignature *sig;
2096         int i, j, outarg_count = 0;
2097
2098         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2099
2100                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2101                 if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2102                         target = tp->rp->unwrapped_server;
2103                 } else {
2104                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2105                 }
2106         }
2107
2108         domain = mono_domain_get (); 
2109         method = msg->method->method;
2110         sig = method->signature;
2111
2112         for (i = 0; i < sig->param_count; i++) {
2113                 if (sig->params [i]->byref) 
2114                         outarg_count++;
2115         }
2116
2117         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2118         *exc = NULL;
2119
2120         for (i = 0, j = 0; i < sig->param_count; i++) {
2121                 if (sig->params [i]->byref) {
2122                         gpointer arg;
2123                         arg = mono_array_get (msg->args, gpointer, i);
2124                         mono_array_set (*out_args, gpointer, j, arg);
2125                         j++;
2126                 }
2127         }
2128
2129         return mono_runtime_invoke_array (method, target, msg->args, exc);
2130 }
2131
2132 void
2133 mono_print_unhandled_exception (MonoObject *exc)
2134 {
2135         char *message = (char *) "";
2136         MonoString *str; 
2137         MonoMethod *method;
2138         MonoClass *klass;
2139         gboolean free_message = FALSE;
2140         gint i;
2141
2142         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2143                 klass = exc->vtable->klass;
2144                 method = NULL;
2145                 while (klass && method == NULL) {
2146                         for (i = 0; i < klass->method.count; ++i) {
2147                                 method = klass->methods [i];
2148                                 if (!strcmp ("ToString", method->name) &&
2149                                     method->signature->param_count == 0 &&
2150                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2151                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2152                                         break;
2153                                 }
2154                                 method = NULL;
2155                         }
2156                         
2157                         if (method == NULL)
2158                                 klass = klass->parent;
2159                 }
2160
2161                 g_assert (method);
2162
2163                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2164                 if (str) {
2165                         message = mono_string_to_utf8 (str);
2166                         free_message = TRUE;
2167                 }
2168         }                               
2169
2170         /*
2171          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
2172          *         exc->vtable->klass->name, message);
2173          */
2174         g_printerr ("\nUnhandled Exception: %s\n", message);
2175         
2176         if (free_message)
2177                 g_free (message);
2178 }
2179
2180 /**
2181  * mono_delegate_ctor:
2182  * @this: pointer to an uninitialized delegate object
2183  * @target: target object
2184  * @addr: pointer to native code
2185  *
2186  * This is used to initialize a delegate. We also insert the method_info if
2187  * we find the info with mono_jit_info_table_find().
2188  */
2189 void
2190 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2191 {
2192         MonoDomain *domain = mono_domain_get ();
2193         MonoDelegate *delegate = (MonoDelegate *)this;
2194         MonoMethod *method = NULL;
2195         MonoClass *class;
2196         MonoJitInfo *ji;
2197
2198         g_assert (this);
2199         g_assert (addr);
2200
2201         class = this->vtable->klass;
2202
2203         if ((ji = mono_jit_info_table_find (domain, addr))) {
2204                 method = ji->method;
2205                 delegate->method_info = mono_method_get_object (domain, method, NULL);
2206         }
2207
2208         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2209                 g_assert (method);
2210                 method = mono_marshal_get_remoting_invoke (method);
2211                 delegate->method_ptr = mono_compile_method (method);
2212                 delegate->target = target;
2213         } else {
2214                 delegate->method_ptr = addr;
2215                 delegate->target = target;
2216         }
2217 }
2218
2219 /**
2220  * mono_method_call_message_new:
2221  *
2222  * Translates arguments pointers into a Message.
2223  */
2224 MonoMethodMessage *
2225 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
2226                               MonoDelegate **cb, MonoObject **state)
2227 {
2228         MonoDomain *domain = mono_domain_get ();
2229         MonoMethodSignature *sig = method->signature;
2230         MonoMethodMessage *msg;
2231         int i, count, type;
2232
2233         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
2234         
2235         if (invoke) {
2236                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2237                 count =  sig->param_count - 2;
2238         } else {
2239                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2240                 count =  sig->param_count;
2241         }
2242
2243         for (i = 0; i < count; i++) {
2244                 gpointer vpos;
2245                 MonoClass *class;
2246                 MonoObject *arg;
2247
2248                 if (sig->params [i]->byref)
2249                         vpos = *((gpointer *)params [i]);
2250                 else 
2251                         vpos = params [i];
2252
2253                 type = sig->params [i]->type;
2254                 class = mono_class_from_mono_type (sig->params [i]);
2255
2256                 if (class->valuetype)
2257                         arg = mono_value_box (domain, class, vpos);
2258                 else 
2259                         arg = *((MonoObject **)vpos);
2260                       
2261                 mono_array_set (msg->args, gpointer, i, arg);
2262         }
2263
2264         if (invoke) {
2265                 *cb = *((MonoDelegate **)params [i]);
2266                 i++;
2267                 *state = *((MonoObject **)params [i]);
2268         }
2269
2270         return msg;
2271 }
2272
2273 /**
2274  * mono_method_return_message_restore:
2275  *
2276  * Restore results from message based processing back to arguments pointers
2277  */
2278 void
2279 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2280 {
2281         MonoMethodSignature *sig = method->signature;
2282         int i, j, type, size;
2283         
2284         for (i = 0, j = 0; i < sig->param_count; i++) {
2285                 MonoType *pt = sig->params [i];
2286
2287                 size = mono_type_stack_size (pt, NULL);
2288
2289                 if (pt->byref) {
2290                         char *arg = mono_array_get (out_args, gpointer, j);
2291                         type = pt->type;
2292                         
2293                         switch (type) {
2294                         case MONO_TYPE_VOID:
2295                                 g_assert_not_reached ();
2296                                 break;
2297                         case MONO_TYPE_U1:
2298                         case MONO_TYPE_I1:
2299                         case MONO_TYPE_BOOLEAN:
2300                         case MONO_TYPE_U2:
2301                         case MONO_TYPE_I2:
2302                         case MONO_TYPE_CHAR:
2303                         case MONO_TYPE_U4:
2304                         case MONO_TYPE_I4:
2305                         case MONO_TYPE_I8:
2306                         case MONO_TYPE_U8:
2307                         case MONO_TYPE_R4:
2308                         case MONO_TYPE_R8:
2309                         case MONO_TYPE_VALUETYPE: {
2310                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
2311                                 break;
2312                         }
2313                         case MONO_TYPE_STRING:
2314                         case MONO_TYPE_CLASS: 
2315                         case MONO_TYPE_ARRAY:
2316                         case MONO_TYPE_SZARRAY:
2317                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2318                                 break;
2319                         default:
2320                                 g_assert_not_reached ();
2321                         }
2322
2323                         j++;
2324                 }
2325         }
2326 }
2327
2328 /**
2329  * mono_load_remote_field:
2330  * @this: pointer to an object
2331  * @klass: klass of the object containing @field
2332  * @field: the field to load
2333  * @res: a storage to store the result
2334  *
2335  * This method is called by the runtime on attempts to load fields of
2336  * transparent proxy objects. @this points to such TP, @klass is the class of
2337  * the object containing @field. @res is a storage location which can be
2338  * used to store the result.
2339  *
2340  * Returns: an address pointing to the value of field.
2341  */
2342 gpointer
2343 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2344 {
2345         static MonoMethod *getter = NULL;
2346         MonoDomain *domain = mono_domain_get ();
2347         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2348         MonoClass *field_class;
2349         MonoMethodMessage *msg;
2350         MonoArray *out_args;
2351         MonoObject *exc;
2352         gpointer tmp;
2353
2354         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2355
2356         if (!res)
2357                 res = &tmp;
2358
2359         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2360                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2361                 return res;
2362         }
2363         
2364         if (!getter) {
2365                 int i;
2366
2367                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2368                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2369                
2370                         if (!strcmp (cm->name, "FieldGetter")) {
2371                                 getter = cm;
2372                                 break;
2373                         }
2374                 }
2375                 g_assert (getter);
2376         }
2377         
2378         field_class = mono_class_from_mono_type (field->type);
2379
2380         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2381         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2382         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2383
2384         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2385         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2386
2387         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2388
2389         *res = mono_array_get (out_args, MonoObject *, 0);
2390
2391         if (field_class->valuetype) {
2392                 return ((char *)*res) + sizeof (MonoObject);
2393         } else
2394                 return res;
2395 }
2396
2397 MonoObject *
2398 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
2399 {
2400         static MonoMethod *getter = NULL;
2401         MonoDomain *domain = mono_domain_get ();
2402         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2403         MonoClass *field_class;
2404         MonoMethodMessage *msg;
2405         MonoArray *out_args;
2406         MonoObject *exc, *res;
2407
2408         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2409
2410         field_class = mono_class_from_mono_type (field->type);
2411
2412         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2413                 gpointer val;
2414                 if (field_class->valuetype) {
2415                         res = mono_object_new (domain, field_class);
2416                         val = ((gchar *) res) + sizeof (MonoObject);
2417                 } else {
2418                         val = &res;
2419                 }
2420                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
2421                 return res;
2422         }
2423
2424         if (!getter) {
2425                 int i;
2426
2427                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2428                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2429                
2430                         if (!strcmp (cm->name, "FieldGetter")) {
2431                                 getter = cm;
2432                                 break;
2433                         }
2434                 }
2435                 g_assert (getter);
2436         }
2437         
2438         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2439         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2440         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2441
2442         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2443         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2444
2445         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2446
2447         res = mono_array_get (out_args, MonoObject *, 0);
2448
2449         return res;
2450 }
2451
2452 /**
2453  * mono_store_remote_field:
2454  * @this: pointer to an object
2455  * @klass: klass of the object containing @field
2456  * @field: the field to load
2457  * @val: the value/object to store
2458  *
2459  * This method is called by the runtime on attempts to store fields of
2460  * transparent proxy objects. @this points to such TP, @klass is the class of
2461  * the object containing @field. @val is the new value to store in @field.
2462  */
2463 void
2464 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
2465 {
2466         static MonoMethod *setter = NULL;
2467         MonoDomain *domain = mono_domain_get ();
2468         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2469         MonoClass *field_class;
2470         MonoMethodMessage *msg;
2471         MonoArray *out_args;
2472         MonoObject *exc;
2473         MonoObject *arg;
2474
2475         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2476
2477         field_class = mono_class_from_mono_type (field->type);
2478
2479         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2480                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
2481                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
2482                 return;
2483         }
2484
2485         if (!setter) {
2486                 int i;
2487
2488                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2489                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2490                
2491                         if (!strcmp (cm->name, "FieldSetter")) {
2492                                 setter = cm;
2493                                 break;
2494                         }
2495                 }
2496                 g_assert (setter);
2497         }
2498
2499         if (field_class->valuetype)
2500                 arg = mono_value_box (domain, field_class, val);
2501         else 
2502                 arg = *((MonoObject **)val);
2503                 
2504
2505         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2506         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
2507
2508         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2509         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2510         mono_array_set (msg->args, gpointer, 2, arg);
2511
2512         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2513 }
2514
2515 void
2516 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
2517 {
2518         static MonoMethod *setter = NULL;
2519         MonoDomain *domain = mono_domain_get ();
2520         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2521         MonoClass *field_class;
2522         MonoMethodMessage *msg;
2523         MonoArray *out_args;
2524         MonoObject *exc;
2525
2526         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2527
2528         field_class = mono_class_from_mono_type (field->type);
2529
2530         if (tp->klass->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2531                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
2532                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
2533                 return;
2534         }
2535
2536         if (!setter) {
2537                 int i;
2538
2539                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2540                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2541                
2542                         if (!strcmp (cm->name, "FieldSetter")) {
2543                                 setter = cm;
2544                                 break;
2545                         }
2546                 }
2547                 g_assert (setter);
2548         }
2549
2550         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2551         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
2552
2553         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2554         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2555         mono_array_set (msg->args, gpointer, 2, arg);
2556
2557         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2558 }
2559