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