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