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