Mon Aug 26 16:47:37 CEST 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <mono/metadata/mono-endian.h>
15 #include <mono/metadata/tabledefs.h>
16 #include <mono/metadata/tokentype.h>
17 #include <mono/metadata/loader.h>
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/gc.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/assembly.h>
22 #include <mono/metadata/threadpool.h>
23 #include <mono/metadata/marshal.h>
24 #include "mono/metadata/debug-helpers.h"
25 #include "mono/metadata/marshal.h"
26 #if HAVE_BOEHM_GC
27 #include <gc/gc.h>
28 #endif
29
30 /* 
31  * enable to get a good speedup: we still need to figure out
32  * how the sync structure is freed.
33  */
34 #define CREATION_SPEEDUP 0
35
36 void
37 mono_runtime_object_init (MonoObject *this)
38 {
39         int i;
40         MonoMethod *method = NULL;
41         MonoClass *klass = this->vtable->klass;
42
43         for (i = 0; i < klass->method.count; ++i) {
44                 if (!strcmp (".ctor", klass->methods [i]->name) &&
45                     klass->methods [i]->signature->param_count == 0) {
46                         method = klass->methods [i];
47                         break;
48                 }
49         }
50
51         g_assert (method);
52
53         mono_runtime_invoke (method, this, NULL, NULL);
54 }
55
56 /*
57  * runtime_class_init:
58  * @klass: klass that needs to be initialized
59  *
60  * This routine calls the class constructor for @class.
61  */
62 void
63 mono_runtime_class_init (MonoClass *klass)
64 {
65         int i;
66
67         for (i = 0; i < klass->method.count; ++i) {
68                 MonoMethod *method = klass->methods [i];
69                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
70                     (strcmp (".cctor", method->name) == 0)) {
71                         mono_runtime_invoke (method, NULL, NULL, NULL);
72                         return;
73                 }
74         }
75
76         /* No class constructor found */
77 }
78
79 static gpointer
80 default_trampoline (MonoMethod *method)
81 {
82         return method;
83 }
84
85 static gpointer
86 default_remoting_trampoline (MonoMethod *method)
87 {
88         g_error ("remoting not installed");
89         return NULL;
90 }
91
92 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
93 static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
94
95 void
96 mono_install_trampoline (MonoTrampoline func) 
97 {
98         arch_create_jit_trampoline = func? func: default_trampoline;
99 }
100
101 void
102 mono_install_remoting_trampoline (MonoTrampoline func) 
103 {
104         arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
105 }
106
107 static MonoCompileFunc default_mono_compile_method = NULL;
108
109 void        
110 mono_install_compile_method (MonoCompileFunc func)
111 {
112         default_mono_compile_method = func;
113 }
114
115 gpointer 
116 mono_compile_method (MonoMethod *method)
117 {
118         if (!default_mono_compile_method) {
119                 g_error ("compile method called on uninitialized runtime");
120                 return NULL;
121         }
122         return default_mono_compile_method (method);
123 }
124
125
126 #if 0 && HAVE_BOEHM_GC
127 static void
128 vtable_finalizer (void *obj, void *data) {
129         g_print ("%s finalized (%p)\n", (char*)data, obj);
130 }
131 #endif
132
133 /**
134  * mono_class_vtable:
135  * @domain: the application domain
136  * @class: the class to initialize
137  *
138  * VTables are domain specific because we create domain specific code, and 
139  * they contain the domain specific static class data.
140  */
141 MonoVTable *
142 mono_class_vtable (MonoDomain *domain, MonoClass *class)
143 {
144         MonoClass *k;
145         MonoVTable *vt;
146         MonoClassField *field;
147         guint32 cindex;
148         guint32 cols [MONO_CONSTANT_SIZE];
149         const char *p;
150         char *t;
151         int i, len;
152
153         g_assert (class);
154
155         vt = class->cached_vtable;
156         if (vt && vt->domain == domain)
157                 return vt;
158
159         /* can interfaces have static fields? */
160         if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
161                 g_assert_not_reached ();
162
163         mono_domain_lock (domain);
164         if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
165                 mono_domain_unlock (domain);
166                 return vt;
167         }
168         
169         if (!class->inited)
170                 mono_class_init (class);
171
172         mono_stats.used_class_count++;
173         mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
174
175         vt = mono_mempool_alloc0 (domain->mp,  sizeof (MonoVTable) + 
176                                   class->vtable_size * sizeof (gpointer));
177         vt->klass = class;
178         vt->domain = domain;
179
180         if (class->class_size) {
181 #if HAVE_BOEHM_GC
182                 vt->data = GC_malloc (class->class_size + 8);
183                 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
184                 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
185                 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
186 #else
187                 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
188                 
189 #endif
190                 mono_stats.class_static_data_size += class->class_size + 8;
191         }
192
193         for (i = class->field.first; i < class->field.last; ++i) {
194                 field = &class->fields [i - class->field.first];
195                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
196                         continue;
197                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
198                         MonoClass *fklass = mono_class_from_mono_type (field->type);
199                         t = (char*)vt->data + field->offset;
200                         g_assert (fklass->valuetype);
201                         memcpy (t, field->data, mono_class_value_size (fklass, NULL));
202                         continue;
203                 }
204                 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
205                         continue;
206                 cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1));
207                 if (!cindex) {
208                         g_warning ("constant for field %s not found", field->name);
209                         continue;
210                 }
211                 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, cols, MONO_CONSTANT_SIZE);
212                 p = mono_metadata_blob_heap (class->image, cols [MONO_CONSTANT_VALUE]);
213                 len = mono_metadata_decode_blob_size (p, &p);
214                 t = (char*)vt->data + field->offset;
215                 /* should we check that the type matches? */
216                 switch (cols [MONO_CONSTANT_TYPE]) {
217                 case MONO_TYPE_BOOLEAN:
218                 case MONO_TYPE_U1:
219                 case MONO_TYPE_I1:
220                         *t = *p;
221                         break;
222                 case MONO_TYPE_CHAR:
223                 case MONO_TYPE_U2:
224                 case MONO_TYPE_I2: {
225                         guint16 *val = (guint16*)t;
226                         *val = read16 (p);
227                         break;
228                 }
229                 case MONO_TYPE_U4:
230                 case MONO_TYPE_I4: {
231                         guint32 *val = (guint32*)t;
232                         *val = read32 (p);
233                         break;
234                 }
235                 case MONO_TYPE_U8:
236                 case MONO_TYPE_I8: {
237                         guint64 *val = (guint64*)t;
238                         *val = read64 (p);
239                         break;
240                 }
241                 case MONO_TYPE_R4: {
242                         float *val = (float*)t;
243                         readr4 (p, val);
244                         break;
245                 }
246                 case MONO_TYPE_R8: {
247                         double *val = (double*)t;
248                         readr8 (p, val);
249                         break;
250                 }
251                 case MONO_TYPE_STRING: {
252                         gpointer *val = (gpointer*)t;
253 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
254                         gunichar2 *copy = g_malloc (len);
255                         int j;
256                         for (j = 0; j < len/2; j++) {
257                                 copy [j] = read16 (p);
258                                 p += 2;
259                         }
260                         *val = mono_string_new_utf16 (domain, copy, len/2);
261                         g_free (copy);
262 #else
263                         *val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
264 #endif
265                         break;
266                 }
267                 case MONO_TYPE_CLASS:
268                         /* nothing to do, we malloc0 the data and the value can be 0 only */
269                         break;
270                 default:
271                         g_warning ("type 0x%02x should not be in constant table", cols [MONO_CONSTANT_TYPE]);
272                 }
273         }
274
275         vt->max_interface_id = class->max_interface_id;
276         
277         vt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
278                 sizeof (gpointer) * (class->max_interface_id + 1));
279
280         /* initialize interface offsets */
281         for (k = class; k ; k = k->parent) {
282                 for (i = 0; i < k->interface_count; i++) {
283                         int slot;
284                         MonoClass *ic = k->interfaces [i];
285                         slot = class->interface_offsets [ic->interface_id];
286                         vt->interface_offsets [ic->interface_id] = &vt->vtable [slot];
287                 }
288         }
289
290         /* initialize vtable */
291         for (i = 0; i < class->vtable_size; ++i) {
292                 MonoMethod *cm;
293                
294                 if ((cm = class->vtable [i]))
295                         vt->vtable [i] = arch_create_jit_trampoline (cm);
296         }
297
298         mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
299         if (!class->cached_vtable)
300                 class->cached_vtable = vt;
301
302         mono_domain_unlock (domain);
303
304         /* make sure the the parent is initialized */
305         if (class->parent)
306                 mono_class_vtable (domain, class->parent);
307
308         mono_runtime_class_init (class);
309         
310         return vt;
311 }
312
313 /**
314  * mono_class_proxy_vtable:
315  * @domain: the application domain
316  * @class: the class to proxy
317  *
318  * Creates a vtable for transparent proxies. It is basically
319  * a copy of the real vtable of @class, but all function pointers invoke
320  * the remoting functions, and vtable->klass points to the 
321  * transparent proxy class, and not to @class.
322  */
323 MonoVTable *
324 mono_class_proxy_vtable (MonoDomain *domain, MonoClass *class)
325 {
326         MonoVTable *vt, *pvt;
327         int i, vtsize;
328
329         if ((pvt = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class)))
330                 return pvt;
331
332         vt = mono_class_vtable (domain, class);
333         vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
334
335         mono_stats.class_vtable_size += vtsize;
336
337         pvt = mono_mempool_alloc (domain->mp, vtsize);
338         memcpy (pvt, vt, vtsize);
339
340         pvt->klass = mono_defaults.transparent_proxy_class;
341
342         /* initialize vtable */
343         for (i = 0; i < class->vtable_size; ++i) {
344                 MonoMethod *cm;
345                
346                 if ((cm = class->vtable [i]))
347                         pvt->vtable [i] = arch_create_remoting_trampoline (cm);
348         }
349
350         mono_g_hash_table_insert (domain->proxy_vtable_hash, class, pvt);
351
352         return pvt;
353 }
354
355 static MonoInvokeFunc default_mono_runtime_invoke = NULL;
356
357 MonoObject*
358 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
359 {
360         if (!default_mono_runtime_invoke) {
361                 g_error ("runtime invoke called on uninitialized runtime");
362                 return NULL;
363         }
364
365         return default_mono_runtime_invoke (method, obj, params, exc);
366 }
367
368 static void
369 set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
370         int t;
371         if (type->byref) {
372                 gpointer *p = (gpointer*)dest;
373                 *p = value;
374                 return;
375         }
376         t = type->type;
377 handle_enum:
378         switch (t) {
379         case MONO_TYPE_BOOLEAN:
380         case MONO_TYPE_I1:
381         case MONO_TYPE_U1: {
382                 guint8 *p = (guint8*)dest;
383                 *p = *(guint8*)value;
384                 return;
385         }
386         case MONO_TYPE_I2:
387         case MONO_TYPE_U2:
388         case MONO_TYPE_CHAR: {
389                 guint16 *p = (guint16*)dest;
390                 *p = *(guint16*)value;
391                 return;
392         }
393 #if SIZEOF_VOID_P == 4
394         case MONO_TYPE_I:
395         case MONO_TYPE_U:
396 #endif
397         case MONO_TYPE_I4:
398         case MONO_TYPE_U4: {
399                 gint32 *p = (gint32*)dest;
400                 *p = *(gint32*)value;
401                 return;
402         }
403 #if SIZEOF_VOID_P == 8
404         case MONO_TYPE_I:
405         case MONO_TYPE_U:
406 #endif
407         case MONO_TYPE_I8:
408         case MONO_TYPE_U8: {
409                 gint64 *p = (gint64*)dest;
410                 *p = *(gint64*)value;
411                 return;
412         }
413         case MONO_TYPE_R4: {
414                 float *p = (float*)dest;
415                 *p = *(float*)value;
416                 return;
417         }
418         case MONO_TYPE_R8: {
419                 double *p = (double*)dest;
420                 *p = *(double*)value;
421                 return;
422         }
423         case MONO_TYPE_STRING:
424         case MONO_TYPE_SZARRAY:
425         case MONO_TYPE_CLASS:
426         case MONO_TYPE_OBJECT:
427         case MONO_TYPE_ARRAY:
428         case MONO_TYPE_PTR: {
429                 gpointer *p = (gpointer*)dest;
430                 *p = deref_pointer? *(gpointer*)value: value;
431                 return;
432         }
433         case MONO_TYPE_VALUETYPE:
434                 if (type->data.klass->enumtype) {
435                         t = type->data.klass->enum_basetype->type;
436                         goto handle_enum;
437                 } else {
438                         int size;
439                         size = mono_class_value_size (type->data.klass, NULL);
440                         memcpy (dest, value, size);
441                 }
442                 return;
443         default:
444                 g_warning ("got type %x", type->type);
445                 g_assert_not_reached ();
446         }
447 }
448
449 void
450 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
451 {
452         void *dest;
453
454         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
455
456         dest = (char*)obj + field->offset;
457         set_value (field->type, dest, value, FALSE);
458 }
459
460 void
461 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
462 {
463         void *dest;
464
465         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
466
467         dest = (char*)vt->data + field->offset;
468         set_value (field->type, dest, value, FALSE);
469 }
470
471 void
472 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
473 {
474         void *src;
475
476         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
477
478         src = (char*)obj + field->offset;
479         set_value (field->type, value, src, TRUE);
480 }
481
482 void
483 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
484 {
485         void *src;
486
487         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
488
489         src = (char*)vt->data + field->offset;
490         set_value (field->type, value, src, TRUE);
491 }
492
493 void
494 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
495 {
496         default_mono_runtime_invoke (prop->set, obj, params, exc);
497 }
498
499 MonoObject*
500 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
501 {
502         return default_mono_runtime_invoke (prop->get, obj, params, exc);
503 }
504
505
506 MonoMethod *
507 mono_get_delegate_invoke (MonoClass *klass)
508 {
509         MonoMethod *im;
510         int i;
511
512         im = NULL;
513
514         for (i = 0; i < klass->method.count; ++i) {
515                 if (klass->methods [i]->name[0] == 'I' && 
516                     !strcmp ("Invoke", klass->methods [i]->name)) {
517                         im = klass->methods [i];
518                 }
519         }
520
521         g_assert (im);
522
523         return im;
524 }
525
526 MonoObject*
527 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
528 {
529         MonoMethod *im;
530
531         im = mono_get_delegate_invoke (delegate->vtable->klass);
532         g_assert (im);
533
534         return mono_runtime_invoke (im, delegate, params, exc);
535 }
536
537 static MonoArray* main_args;
538
539 MonoArray*
540 mono_runtime_get_main_args (void)
541 {
542         return main_args;
543 }
544
545 MonoMethod *mono_start_method = NULL;
546
547 /*
548  * Execute a standard Main() method (argc/argv contains the
549  * executable name). This method also sets the command line argument value
550  * needed by System.Environment.
551  */
552 int
553 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
554                        MonoObject **exc)
555 {
556         int i;
557         MonoArray *args = NULL;
558         MonoDomain *domain = mono_domain_get ();
559
560         main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
561         for (i = 0; i < argc; ++i) {
562                 MonoString *arg = mono_string_new (domain, argv [i]);
563                 mono_array_set (main_args, gpointer, i, arg);
564         }
565         argc--;
566         argv++;
567         if (method->signature->param_count) {
568                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
569                 for (i = 0; i < argc; ++i) {
570                         MonoString *arg = mono_string_new (domain, argv [i]);
571                         mono_array_set (args, gpointer, i, arg);
572                 }
573         } else {
574                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
575         }
576         
577         mono_assembly_set_main (method->klass->image->assembly);
578
579         mono_start_method = mono_marshal_get_runtime_invoke (method);
580         
581         return mono_runtime_exec_main (method, args, exc);
582 }
583
584 /*
585  * We call this function when we dectect an unhandled exception. It invokes the
586  * UnhandledException event in AppDomain or print a warning to the console 
587  */
588 void
589 mono_unhandled_exception (MonoObject *exc)
590 {
591         MonoDomain *domain = mono_domain_get ();
592         MonoClassField *field;
593         MonoObject *delegate;
594         
595         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
596                                              "UnhandledException");
597         g_assert (field);
598
599         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
600                 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
601
602                 if (!delegate) {
603                         mono_print_unhandled_exception (exc);
604                 } else {
605                         MonoObject *e = NULL;
606                         gpointer pa [2];
607
608                         /* fixme: pass useful arguments */
609                         pa [0] = NULL;
610                         pa [1] = NULL;
611                         mono_runtime_delegate_invoke (delegate, pa, &e);
612                         
613                         if (e)
614                                 g_warning ("exception inside UnhandledException handler!");
615                 }
616         }
617 }
618
619 /*
620  * Execute a standard Main() method (args doesn't contain the
621  * executable name).
622  */
623 int
624 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
625 {
626         MonoDomain *domain;
627         gpointer pa [1];
628         int rval;
629
630         g_assert (args);
631
632         pa [0] = args;
633
634         domain = mono_object_domain (args);
635         if (!domain->entry_assembly)
636                 domain->entry_assembly = method->klass->image->assembly;
637
638         /* FIXME: check signature of method */
639         if (method->signature->ret->type == MONO_TYPE_I4) {
640                 MonoObject *res;
641                 res = mono_runtime_invoke (method, NULL, pa, exc);
642                 if (!exc || !*exc)
643                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
644                 else
645                         rval = -1;
646         } else {
647                 mono_runtime_invoke (method, NULL, pa, exc);
648                 if (!exc || !*exc)
649                         rval = 0;
650                 else
651                         rval = -1;
652         }
653
654         return rval;
655 }
656
657 void
658 mono_install_runtime_invoke (MonoInvokeFunc func)
659 {
660         default_mono_runtime_invoke = func;
661 }
662
663 MonoObject*
664 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
665                            MonoObject **exc)
666 {
667         MonoMethodSignature *sig = method->signature;
668         gpointer *pa = NULL;
669         int i;
670                 
671         if (NULL != params) {
672                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
673                 for (i = 0; i < mono_array_length (params); i++) {
674                         if (sig->params [i]->byref) {
675                                 /* nothing to do */
676                         }
677
678                         switch (sig->params [i]->type) {
679                         case MONO_TYPE_U1:
680                         case MONO_TYPE_I1:
681                         case MONO_TYPE_BOOLEAN:
682                         case MONO_TYPE_U2:
683                         case MONO_TYPE_I2:
684                         case MONO_TYPE_CHAR:
685                         case MONO_TYPE_U:
686                         case MONO_TYPE_I:
687                         case MONO_TYPE_U4:
688                         case MONO_TYPE_I4:
689                         case MONO_TYPE_U8:
690                         case MONO_TYPE_I8:
691                         case MONO_TYPE_VALUETYPE:
692                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
693                                 break;
694                         case MONO_TYPE_STRING:
695                         case MONO_TYPE_OBJECT:
696                         case MONO_TYPE_CLASS:
697                         case MONO_TYPE_ARRAY:
698                         case MONO_TYPE_SZARRAY:
699                                 pa [i] = (char *)(((gpointer *)params->vector)[i]);
700                                 break;
701                         default:
702                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
703                         }
704                 }
705         }
706
707         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
708                 obj = mono_object_new (mono_domain_get (), method->klass);
709                 mono_runtime_invoke (method, obj, pa, exc);
710                 return obj;
711         } else
712                 return mono_runtime_invoke (method, obj, pa, exc);
713 }
714
715 /**
716  * mono_object_allocate:
717  * @size: number of bytes to allocate
718  *
719  * This is a very simplistic routine until we have our GC-aware
720  * memory allocator. 
721  *
722  * Returns: an allocated object of size @size, or NULL on failure.
723  */
724 void *
725 mono_object_allocate (size_t size)
726 {
727 #if HAVE_BOEHM_GC
728         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
729         void *o = GC_malloc (size);
730 #else
731         void *o = calloc (1, size);
732 #endif
733
734         mono_stats.new_object_count++;
735
736         return o;
737 }
738
739 /**
740  * mono_object_free:
741  *
742  * Frees the memory used by the object.  Debugging purposes
743  * only, as we will have our GC system.
744  */
745 void
746 mono_object_free (MonoObject *o)
747 {
748 #if HAVE_BOEHM_GC
749         g_error ("mono_object_free called with boehm gc.");
750 #else
751         MonoClass *c = o->vtable->klass;
752         
753         memset (o, 0, c->instance_size);
754         free (o);
755 #endif
756 }
757
758 /**
759  * mono_object_new:
760  * @klass: the class of the object that we want to create
761  *
762  * Returns: A newly created object whose definition is
763  * looked up using @klass
764  */
765 MonoObject *
766 mono_object_new (MonoDomain *domain, MonoClass *klass)
767 {
768         return mono_object_new_specific (mono_class_vtable (domain, klass));
769 }
770
771 /**
772  * mono_object_new_specific:
773  * @vtable: the vtable of the object that we want to create
774  *
775  * Returns: A newly created object with class and domain specified
776  * by @vtable
777  */
778 MonoObject *
779 mono_object_new_specific (MonoVTable *vtable)
780 {
781         MonoObject *o;
782
783         o = mono_object_allocate (vtable->klass->instance_size);
784         o->vtable = vtable;
785         if (vtable->klass->has_finalize)
786                 mono_object_register_finalizer (o);
787         
788         return o;
789 }
790
791 /**
792  * mono_object_new_from_token:
793  * @image: Context where the type_token is hosted
794  * @token: a token of the type that we want to create
795  *
796  * Returns: A newly created object whose definition is
797  * looked up using @token in the @image image
798  */
799 MonoObject *
800 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
801 {
802         MonoClass *class;
803
804         class = mono_class_get (image, token);
805
806         return mono_object_new (domain, class);
807 }
808
809
810 /**
811  * mono_object_clone:
812  * @obj: the object to clone
813  *
814  * Returns: A newly created object who is a shallow copy of @obj
815  */
816 MonoObject *
817 mono_object_clone (MonoObject *obj)
818 {
819         MonoObject *o;
820         int size;
821
822         size = obj->vtable->klass->instance_size;
823         o = mono_object_allocate (size);
824
825         memcpy (o, obj, size);
826
827         if (obj->vtable->klass->has_finalize)
828                 mono_object_register_finalizer (o);
829         return o;
830 }
831
832 /**
833  * mono_array_clone:
834  * @array: the array to clone
835  *
836  * Returns: A newly created array who is a shallow copy of @array
837  */
838 MonoArray*
839 mono_array_clone (MonoArray *array)
840 {
841         MonoArray *o;
842         int size, i;
843         guint32 *sizes;
844         MonoClass *klass = array->obj.vtable->klass;
845
846         if (array->bounds == NULL) {
847                 size = mono_array_length (array);
848                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
849                                          klass, &size, NULL);
850
851                 size *= mono_array_element_size (klass);
852                 memcpy (o, array, sizeof (MonoArray) + size);
853
854                 return o;
855         }
856         
857         sizes = alloca (klass->rank * sizeof(guint32) * 2);
858         size = mono_array_element_size (klass);
859         for (i = 0; i < klass->rank; ++i) {
860                 sizes [i] = array->bounds [i].length;
861                 size *= array->bounds [i].length;
862                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
863         }
864         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
865                                  klass, sizes, sizes + klass->rank);
866         memcpy (o, array, sizeof(MonoArray) + size);
867
868         return o;
869 }
870
871 /*
872  * mono_array_new_full:
873  * @domain: domain where the object is created
874  * @array_class: array class
875  * @lengths: lengths for each dimension in the array
876  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
877  *
878  * This routine creates a new array objects with the given dimensions,
879  * lower bounds and type.
880  */
881 MonoArray*
882 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
883                      guint32 *lengths, guint32 *lower_bounds)
884 {
885         guint32 byte_len, len;
886         MonoObject *o;
887         MonoArray *array;
888         MonoArrayBounds *bounds;
889         int i;
890
891         if (!array_class->inited)
892                 mono_class_init (array_class);
893
894         byte_len = mono_array_element_size (array_class);
895         len = 1;
896
897         if (array_class->rank == 1 &&
898             (lower_bounds == NULL || lower_bounds [0] == 0)) {
899                 bounds = NULL;
900                 len = lengths [0];
901         } else {
902         #if HAVE_BOEHM_GC
903                 bounds = GC_malloc (sizeof (MonoArrayBounds) * array_class->rank);
904         #else
905                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
906         #endif
907                 for (i = 0; i < array_class->rank; ++i) {
908                         bounds [i].length = lengths [i];
909                         len *= lengths [i];
910                 }
911
912                 if (lower_bounds)
913                         for (i = 0; i < array_class->rank; ++i)
914                                 bounds [i].lower_bound = lower_bounds [i];
915         }
916
917         byte_len *= len;
918         /* 
919          * Following three lines almost taken from mono_object_new ():
920          * they need to be kept in sync.
921          */
922         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
923         if (!o)
924                 G_BREAKPOINT ();
925         o->vtable = mono_class_vtable (domain, array_class);
926
927         array = (MonoArray*)o;
928
929         array->bounds = bounds;
930         array->max_length = len;
931
932         return array;
933 }
934
935 /*
936  * mono_array_new:
937  * @domain: domain where the object is created
938  * @eclass: element class
939  * @n: number of array elements
940  *
941  * This routine creates a new szarray with @n elements of type @eclass.
942  */
943 MonoArray *
944 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
945 {
946         MonoClass *ac;
947
948         ac = mono_array_class_get (&eclass->byval_arg, 1);
949         g_assert (ac != NULL);
950
951         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
952 }
953
954 /*
955  * mono_array_new_specific:
956  * @vtable: a vtable in the appropriate domain for an initialized class
957  * @n: number of array elements
958  *
959  * This routine is a fast alternative to mono_array_new() for code which
960  * can be sure about the domain it operates in.
961  */
962 MonoArray *
963 mono_array_new_specific (MonoVTable *vtable, guint32 n)
964 {
965         MonoObject *o;
966         MonoArray *ao;
967         gsize byte_len;
968
969         byte_len = n * mono_array_element_size (vtable->klass);
970 #if CREATION_SPEEDUP
971         if (vtable->klass->element_class->byval_arg.type >= MONO_TYPE_BOOLEAN && vtable->klass->element_class->byval_arg.type <= MONO_TYPE_R4) {
972                 o = GC_malloc_atomic (sizeof (MonoArray) + byte_len);
973                 o->synchronisation = 0;
974                 memset (((MonoArray*)o)->vector, 0, byte_len);
975         } else {
976                 o = mono_object_allocate (sizeof (MonoArray) + byte_len);
977         }
978 #else
979         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
980 #endif
981         if (!o)
982                 G_BREAKPOINT ();
983         o->vtable = vtable;
984
985         ao = (MonoArray *)o;
986         ao->bounds = NULL;
987         ao->max_length = n;
988
989         return ao;
990 }
991
992 /**
993  * mono_string_new_utf16:
994  * @text: a pointer to an utf16 string
995  * @len: the length of the string
996  *
997  * Returns: A newly created string object which contains @text.
998  */
999 MonoString *
1000 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
1001 {
1002         MonoString *s;
1003         
1004         s = mono_string_new_size (domain, len);
1005         g_assert (s != NULL);
1006
1007         memcpy (mono_string_chars (s), text, len * 2);
1008
1009         return s;
1010 }
1011
1012 /**
1013  * mono_string_new_size:
1014  * @text: a pointer to an utf16 string
1015  * @len: the length of the string
1016  *
1017  * Returns: A newly created string object of @len
1018  */
1019 MonoString *
1020 mono_string_new_size (MonoDomain *domain, gint32 len)
1021 {
1022         MonoString *s;
1023
1024 #if CREATION_SPEEDUP
1025         s = GC_malloc_atomic (sizeof (MonoString) + ((len + 1) * 2));
1026         s->object.synchronisation = 0;
1027         mono_string_chars (s) [len] = 0;
1028 #else
1029         s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
1030 #endif
1031         if (!s)
1032                 G_BREAKPOINT ();
1033
1034         s->object.vtable = mono_class_vtable (domain, mono_defaults.string_class);
1035         s->length = len;
1036
1037         return s;
1038 }
1039
1040 /*
1041  * mono_string_new_len:
1042  * @text: a pointer to an utf8 string
1043  * @length: number of bytes in @text to consider
1044  *
1045  * Returns: A newly created string object which contains @text.
1046  */
1047 MonoString*
1048 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
1049 {
1050         GError *error = NULL;
1051         MonoString *o = NULL;
1052         guint16 *ut;
1053         glong items_written;
1054
1055         
1056         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
1057
1058         if (!error)
1059                 o = mono_string_new_utf16 (domain, ut, items_written);
1060         else 
1061                 g_error_free (error);
1062
1063         g_free (ut);
1064
1065         return o;
1066 }
1067
1068 /**
1069  * mono_string_new:
1070  * @text: a pointer to an utf8 string
1071  *
1072  * Returns: A newly created string object which contains @text.
1073  */
1074 MonoString*
1075 mono_string_new (MonoDomain *domain, const char *text)
1076 {
1077         GError *error = NULL;
1078         MonoString *o = NULL;
1079         guint16 *ut;
1080         glong items_written;
1081         int l;
1082
1083         l = strlen (text);
1084         
1085         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
1086
1087         if (!error)
1088                 o = mono_string_new_utf16 (domain, ut, items_written);
1089         else 
1090                 g_error_free (error);
1091
1092         g_free (ut);
1093
1094         return o;
1095 }
1096
1097 /*
1098  * mono_string_new_wrapper:
1099  * @text: pointer to utf8 characters.
1100  *
1101  * Helper function to create a string object from @text in the current domain.
1102  */
1103 MonoString*
1104 mono_string_new_wrapper (const char *text)
1105 {
1106         MonoDomain *domain = mono_domain_get ();
1107
1108         if (text)
1109                 return mono_string_new (domain, text);
1110
1111         return NULL;
1112 }
1113
1114 /**
1115  * mono_value_box:
1116  * @class: the class of the value
1117  * @value: a pointer to the unboxed data
1118  *
1119  * Returns: A newly created object which contains @value.
1120  */
1121 MonoObject *
1122 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
1123 {
1124         MonoObject *res;
1125         int size;
1126
1127         g_assert (class->valuetype);
1128
1129         size = mono_class_instance_size (class);
1130         res = mono_object_allocate (size);
1131         res->vtable = mono_class_vtable (domain, class);
1132
1133         size = size - sizeof (MonoObject);
1134
1135 #if NO_UNALIGNED_ACCESS
1136         memcpy ((char *)res + sizeof (MonoObject), value, size);
1137 #else
1138         switch (size) {
1139         case 1:
1140                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
1141                 break;
1142         case 2:
1143                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
1144                 break;
1145         case 4:
1146                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
1147                 break;
1148         case 8:
1149                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
1150                 break;
1151         default:
1152                 memcpy ((char *)res + sizeof (MonoObject), value, size);
1153         }
1154 #endif
1155         if (class->has_finalize)
1156                 mono_object_register_finalizer (res);
1157         return res;
1158 }
1159
1160 /**
1161  * mono_object_isinst:
1162  * @obj: an object
1163  * @klass: a pointer to a class 
1164  *
1165  * Returns: @obj if @obj is derived from @klass
1166  */
1167 MonoObject *
1168 mono_object_isinst (MonoObject *obj, MonoClass *klass)
1169 {
1170         MonoVTable *vt;
1171         MonoClass *oklass;
1172
1173         if (!obj)
1174                 return NULL;
1175
1176         vt = obj->vtable;
1177         oklass = vt->klass;
1178
1179         if (!klass->inited)
1180                 mono_class_init (klass);
1181
1182         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1183                 if ((klass->interface_id <= oklass->max_interface_id) &&
1184                     vt->interface_offsets [klass->interface_id])
1185                         return obj;
1186         } else {
1187                 if (oklass == mono_defaults.transparent_proxy_class) {
1188                         /* fixme: add check for IRemotingTypeInfo */
1189                         oklass = ((MonoTransparentProxy *)obj)->klass;
1190                 }
1191                 if (klass->rank) {
1192                         if (oklass->rank == klass->rank && 
1193                             (oklass->element_class->baseval - klass->element_class->baseval) <= 
1194                             klass->element_class->diffval)
1195                                 return obj;
1196                         
1197                 } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
1198                         return obj;
1199         }
1200
1201         return NULL;
1202 }
1203
1204 static MonoString*
1205 mono_string_is_interned_lookup (MonoString *str, int insert)
1206 {
1207         MonoGHashTable *ldstr_table;
1208         MonoString *res;
1209         MonoDomain *domain;
1210         char *ins = g_malloc (4 + str->length * 2);
1211         char *p;
1212         int bloblen;
1213         
1214         /* Encode the length */
1215         p = ins;
1216         mono_metadata_encode_value (2 * str->length, p, &p);
1217         bloblen = p - ins;
1218         p = ins;
1219         mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
1220         bloblen = (p - ins) + 2 * str->length;
1221         /*
1222          * ins is stored in the hash table as a key and needs to have the same
1223          * representation as in the metadata: we swap the character bytes on big
1224          * endian boxes.
1225          */
1226 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1227         {
1228                 int i;
1229                 char *p2 = mono_string_chars (str);
1230                 for (i = 0; i < str->length; ++i) {
1231                         *p++ = p2 [1];
1232                         *p++ = p2 [0];
1233                         p2 += 2;
1234                 }
1235         }
1236 #else
1237         memcpy (p, mono_string_chars (str), str->length * 2);
1238 #endif
1239         domain = ((MonoObject *)str)->vtable->domain;
1240         ldstr_table = domain->ldstr_table;
1241         mono_domain_lock (domain);
1242         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
1243                 mono_domain_unlock (domain);
1244                 g_free (ins);
1245                 return res;
1246         }
1247         if (insert) {
1248                 mono_g_hash_table_insert (ldstr_table, ins, str);
1249                 mono_domain_unlock (domain);
1250                 return str;
1251         }
1252         mono_domain_unlock (domain);
1253         g_free (ins);
1254         return NULL;
1255 }
1256
1257 MonoString*
1258 mono_string_is_interned (MonoString *o)
1259 {
1260         return mono_string_is_interned_lookup (o, FALSE);
1261 }
1262
1263 MonoString*
1264 mono_string_intern (MonoString *str)
1265 {
1266         return mono_string_is_interned_lookup (str, TRUE);
1267 }
1268
1269 /*
1270  * mono_ldstr:
1271  * @domain: the domain where the string will be used.
1272  * @image: a metadata context
1273  * @idx: index into the user string table.
1274  * 
1275  * Implementation for the ldstr opcode.
1276  */
1277 MonoString*
1278 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
1279 {
1280         const char *str, *sig;
1281         MonoString *o;
1282         size_t len2;
1283                 
1284         sig = str = mono_metadata_user_string (image, idx);
1285
1286         mono_domain_lock (domain);
1287         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
1288                 mono_domain_unlock (domain);
1289                 return o;
1290         }
1291         
1292         len2 = mono_metadata_decode_blob_size (str, &str);
1293         len2 >>= 1;
1294
1295         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
1296 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
1297         {
1298                 int i;
1299                 guint16 *p2 = (guint16*)mono_string_chars (o);
1300                 for (i = 0; i < len2; ++i) {
1301                         *p2 = GUINT16_FROM_LE (*p2);
1302                         ++p2;
1303                 }
1304         }
1305 #endif
1306         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
1307         mono_domain_unlock (domain);
1308
1309         return o;
1310 }
1311
1312 /*
1313  * mono_string_to_utf8:
1314  * @s: a System.String
1315  *
1316  * Return the UTF8 representation for @s.
1317  * the resulting buffer nedds to be freed with g_free().
1318  */
1319 char *
1320 mono_string_to_utf8 (MonoString *s)
1321 {
1322         char *as;
1323         GError *error = NULL;
1324
1325         if (s == NULL)
1326                 return NULL;
1327
1328         if (!s->length)
1329                 return g_strdup ("");
1330
1331         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
1332         if (error)
1333                 g_warning (error->message);
1334
1335         return as;
1336 }
1337
1338 /*
1339  * mono_string_to_utf16:
1340  * @s: a MonoString
1341  *
1342  * Return an null-terminated array of the utf-16 chars
1343  * contained in @s. The result must be freed with g_free().
1344  * This is a temporary helper until our string implementation
1345  * is reworked to always include the null terminating char.
1346  */
1347 gunichar2 *
1348 mono_string_to_utf16 (MonoString *s)
1349 {
1350         char *as;
1351
1352         if (s == NULL)
1353                 return NULL;
1354
1355         as = g_malloc ((s->length * 2) + 2);
1356         as [(s->length * 2)] = '\0';
1357         as [(s->length * 2) + 1] = '\0';
1358
1359         if (!s->length) {
1360                 return (gunichar2 *)(as);
1361         }
1362         
1363         memcpy (as, mono_string_chars(s), s->length * 2);
1364         return (gunichar2 *)(as);
1365 }
1366
1367 static void
1368 default_ex_handler (MonoException *ex)
1369 {
1370         MonoObject *o = (MonoObject*)ex;
1371         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
1372 }
1373
1374 static MonoExceptionFunc ex_handler = default_ex_handler;
1375
1376 void
1377 mono_install_handler        (MonoExceptionFunc func)
1378 {
1379         ex_handler = func? func: default_ex_handler;
1380 }
1381
1382 /*
1383  * mono_raise_exception:
1384  * @ex: exception object
1385  *
1386  * Signal the runtime that the exception @ex has been raised in unmanaged code.
1387  */
1388 void
1389 mono_raise_exception (MonoException *ex) 
1390 {
1391         ex_handler (ex);
1392 }
1393
1394 MonoWaitHandle *
1395 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
1396 {
1397         MonoWaitHandle *res;
1398
1399         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
1400
1401         res->handle = handle;
1402
1403         return res;
1404 }
1405
1406 MonoAsyncResult *
1407 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
1408 {
1409         MonoAsyncResult *res;
1410
1411         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
1412
1413         res->data = data;
1414         res->async_state = state;
1415         res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
1416         res->sync_completed = FALSE;
1417         res->completed = FALSE;
1418
1419         return res;
1420 }
1421
1422 void
1423 mono_message_init (MonoDomain *domain,
1424                    MonoMethodMessage *this, 
1425                    MonoReflectionMethod *method,
1426                    MonoArray *out_args)
1427 {
1428         MonoMethodSignature *sig = method->method->signature;
1429         MonoString *name;
1430         int i, j;
1431         char **names;
1432         guint8 arg_type;
1433
1434         this->method = method;
1435
1436         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
1437         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
1438
1439         names = g_new (char *, sig->param_count);
1440         mono_method_get_param_names (method->method, (const char **) names);
1441         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
1442         
1443         for (i = 0; i < sig->param_count; i++) {
1444                  name = mono_string_new (domain, names [i]);
1445                  mono_array_set (this->names, gpointer, i, name);       
1446         }
1447
1448         g_free (names);
1449         
1450         for (i = 0, j = 0; i < sig->param_count; i++) {
1451
1452                 if (sig->params [i]->byref) {
1453                         if (out_args) {
1454                                 gpointer arg = mono_array_get (out_args, gpointer, j);
1455                                 mono_array_set (this->args, gpointer, i, arg);
1456                                 j++;
1457                         }
1458                         arg_type = 2;
1459                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN)
1460                                 arg_type |= 1;
1461                 } else {
1462                         arg_type = 1;
1463                 }
1464
1465                 mono_array_set (this->arg_types, guint8, i, arg_type);
1466         }
1467 }
1468
1469 /**
1470  * mono_remoting_invoke:
1471  * @real_proxy: pointer to a RealProxy object
1472  * @msg: The MonoMethodMessage to execute
1473  * @exc: used to store exceptions
1474  * @out_args: used to store output arguments
1475  *
1476  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
1477  * IMessage interface and it is not trivial to extract results from there. So
1478  * we call an helper method PrivateInvoke instead of calling
1479  * RealProxy::Invoke() directly.
1480  *
1481  * Returns: the result object.
1482  */
1483 MonoObject *
1484 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
1485                       MonoObject **exc, MonoArray **out_args)
1486 {
1487         static MonoMethod *im = NULL;
1488         gpointer pa [4];
1489
1490         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
1491
1492         /* FIXME: make this domain dependent */
1493         if (!im) {
1494                 MonoClass *klass;
1495                 int i;
1496
1497                 klass = mono_defaults.real_proxy_class; 
1498                        
1499                 for (i = 0; i < klass->method.count; ++i) {
1500                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
1501                             klass->methods [i]->signature->param_count == 4) {
1502                                 im = klass->methods [i];
1503                                 break;
1504                         }
1505                 }
1506         
1507                 g_assert (im);
1508         }
1509
1510         pa [0] = real_proxy;
1511         pa [1] = msg;
1512         pa [2] = exc;
1513         pa [3] = out_args;
1514
1515         return mono_runtime_invoke (im, NULL, pa, exc);
1516 }
1517
1518 MonoObject *
1519 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
1520                      MonoObject **exc, MonoArray **out_args) 
1521 {
1522         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
1523
1524                 return mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)target)->rp, 
1525                                              msg, exc, out_args);
1526
1527         } else {
1528                 MonoDomain *domain = mono_domain_get (); 
1529                 MonoMethod *method = msg->method->method;
1530                 MonoMethodSignature *sig = method->signature;
1531                 int i, j, outarg_count = 0;
1532
1533                 for (i = 0; i < sig->param_count; i++) {
1534                         if (sig->params [i]->byref) 
1535                                 outarg_count++;
1536                 }
1537
1538                 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
1539                 *exc = NULL;
1540
1541                 for (i = 0, j = 0; i < sig->param_count; i++) {
1542                         if (sig->params [i]->byref) {
1543                                 gpointer arg;
1544                                 arg = mono_array_get (msg->args, gpointer, i);
1545                                 mono_array_set (*out_args, gpointer, j, arg);
1546                                 j++;
1547                         }
1548                 }
1549
1550                 return mono_runtime_invoke_array (method, target, msg->args, exc);
1551         }
1552 }
1553
1554 void
1555 mono_print_unhandled_exception (MonoObject *exc)
1556 {
1557         char *message = (char *) "";
1558         MonoString *str; 
1559         MonoMethod *method;
1560         MonoClass *klass;
1561         gboolean free_message = FALSE;
1562         gint i;
1563
1564         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
1565                 klass = exc->vtable->klass;
1566                 method = NULL;
1567                 while (klass && method == NULL) {
1568                         for (i = 0; i < klass->method.count; ++i) {
1569                                 method = klass->methods [i];
1570                                 if (!strcmp ("ToString", method->name) &&
1571                                     method->signature->param_count == 0 &&
1572                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1573                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
1574                                         break;
1575                                 }
1576                                 method = NULL;
1577                         }
1578                         
1579                         if (method == NULL)
1580                                 klass = klass->parent;
1581                 }
1582
1583                 g_assert (method);
1584
1585                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
1586                 if (str) {
1587                         message = mono_string_to_utf8 (str);
1588                         free_message = TRUE;
1589                 }
1590         }                               
1591
1592         /*
1593          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
1594          *         exc->vtable->klass->name, message);
1595          */
1596         g_printerr ("\nUnhandled Exception: %s\n", message);
1597         
1598         if (free_message)
1599                 g_free (message);
1600 }
1601
1602 /**
1603  * mono_delegate_ctor:
1604  * @this: pointer to an uninitialized delegate object
1605  * @target: target object
1606  * @addr: pointer to native code
1607  *
1608  * This is used to initialize a delegate. We also insert the method_info if
1609  * we find the info with mono_jit_info_table_find().
1610  */
1611 void
1612 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
1613 {
1614         MonoDomain *domain = mono_domain_get ();
1615         MonoDelegate *delegate = (MonoDelegate *)this;
1616         MonoMethod *method = NULL;
1617         MonoClass *class;
1618         MonoJitInfo *ji;
1619
1620         g_assert (this);
1621         g_assert (addr);
1622
1623         class = this->vtable->klass;
1624
1625         if ((ji = mono_jit_info_table_find (domain, addr))) {
1626                 method = ji->method;
1627                 delegate->method_info = mono_method_get_object (domain, method, NULL);
1628         }
1629
1630         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
1631                 g_assert (method);
1632                 method = mono_marshal_get_remoting_invoke (method);
1633                 delegate->method_ptr = mono_compile_method (method);
1634                 delegate->target = target;
1635         } else {
1636                 delegate->method_ptr = addr;
1637                 delegate->target = target;
1638         }
1639 }
1640
1641 /**
1642  * mono_method_call_message_new:
1643  *
1644  * Translates arguments pointers into a Message.
1645  */
1646 MonoMethodMessage *
1647 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
1648                               MonoDelegate **cb, MonoObject **state)
1649 {
1650         MonoDomain *domain = mono_domain_get ();
1651         MonoMethodSignature *sig = method->signature;
1652         MonoMethodMessage *msg;
1653         int i, count, type;
1654
1655         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
1656         
1657         if (invoke) {
1658                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
1659                 count =  sig->param_count - 2;
1660         } else {
1661                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
1662                 count =  sig->param_count;
1663         }
1664
1665         for (i = 0; i < count; i++) {
1666                 gpointer vpos;
1667                 MonoClass *class;
1668                 MonoObject *arg;
1669
1670                 if (sig->params [i]->byref)
1671                         vpos = *((gpointer *)params [i]);
1672                 else 
1673                         vpos = params [i];
1674
1675                 type = sig->params [i]->type;
1676                 class = mono_class_from_mono_type (sig->params [i]);
1677
1678                 if (class->valuetype)
1679                         arg = mono_value_box (domain, class, vpos);
1680                 else 
1681                         arg = *((MonoObject **)vpos);
1682                       
1683                 mono_array_set (msg->args, gpointer, i, arg);
1684         }
1685
1686         if (invoke) {
1687                 *cb = *((MonoDelegate **)params [i]);
1688                 i++;
1689                 *state = *((MonoObject **)params [i]);
1690         }
1691
1692         return msg;
1693 }
1694
1695 /**
1696  * mono_method_return_message_restore:
1697  *
1698  * Restore results from message based processing back to arguments pointers
1699  */
1700 void
1701 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
1702 {
1703         MonoMethodSignature *sig = method->signature;
1704         int i, j, type, size;
1705         
1706         for (i = 0, j = 0; i < sig->param_count; i++) {
1707                 MonoType *pt = sig->params [i];
1708
1709                 size = mono_type_stack_size (pt, NULL);
1710
1711                 if (pt->byref) {
1712                         char *arg = mono_array_get (out_args, gpointer, j);
1713                         type = pt->type;
1714                         
1715                         switch (type) {
1716                         case MONO_TYPE_VOID:
1717                                 g_assert_not_reached ();
1718                                 break;
1719                         case MONO_TYPE_U1:
1720                         case MONO_TYPE_I1:
1721                         case MONO_TYPE_BOOLEAN:
1722                         case MONO_TYPE_U2:
1723                         case MONO_TYPE_I2:
1724                         case MONO_TYPE_CHAR:
1725                         case MONO_TYPE_U4:
1726                         case MONO_TYPE_I4:
1727                         case MONO_TYPE_I8:
1728                         case MONO_TYPE_U8:
1729                         case MONO_TYPE_R4:
1730                         case MONO_TYPE_R8:
1731                         case MONO_TYPE_VALUETYPE: {
1732                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
1733                                 break;
1734                         }
1735                         case MONO_TYPE_STRING:
1736                         case MONO_TYPE_CLASS: 
1737                         case MONO_TYPE_ARRAY:
1738                         case MONO_TYPE_SZARRAY:
1739                                 *((MonoObject **)params [i]) = (MonoObject *)arg;
1740                                 break;
1741                         default:
1742                                 g_assert_not_reached ();
1743                         }
1744
1745                         j++;
1746                 }
1747         }
1748 }
1749
1750 /**
1751  * mono_load_remote_field:
1752  * @this: pointer to an object
1753  * @klass: klass of the object containing @field
1754  * @field: the field to load
1755  * @res: a storage to store the result
1756  *
1757  * This method is called by the runtime on attempts to load fields of
1758  * transparent proxy objects. @this points to such TP, @klass is the class of
1759  * the object containing @field. @res is a storage location which can be
1760  * used to store the result.
1761  *
1762  * Returns: an address pointing to the value of field.
1763  */
1764 gpointer
1765 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
1766 {
1767         static MonoMethod *getter = NULL;
1768         MonoDomain *domain = mono_domain_get ();
1769         MonoClass *field_class;
1770         MonoMethodMessage *msg;
1771         MonoArray *out_args;
1772         MonoObject *exc;
1773         gpointer tmp;
1774
1775         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
1776
1777         if (!res)
1778                 res = &tmp;
1779
1780         if (!getter) {
1781                 int i;
1782
1783                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
1784                         MonoMethod *cm = mono_defaults.object_class->methods [i];
1785                
1786                         if (!strcmp (cm->name, "FieldGetter")) {
1787                                 getter = cm;
1788                                 break;
1789                         }
1790                 }
1791                 g_assert (getter);
1792         }
1793         
1794         field_class = mono_class_from_mono_type (field->type);
1795
1796         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
1797         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
1798         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
1799
1800         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
1801         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
1802
1803         mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)this)->rp, msg, &exc, &out_args);
1804
1805         *res = mono_array_get (out_args, MonoObject *, 0);
1806
1807         if (field_class->valuetype) {
1808                 return ((char *)*res) + sizeof (MonoObject);
1809         } else
1810                 return res;
1811 }
1812
1813 /**
1814  * mono_store_remote_field:
1815  * @this: pointer to an object
1816  * @klass: klass of the object containing @field
1817  * @field: the field to load
1818  * @val: the value/object to store
1819  *
1820  * This method is called by the runtime on attempts to store fields of
1821  * transparent proxy objects. @this points to such TP, @klass is the class of
1822  * the object containing @field. @val is the new value to store in @field.
1823  */
1824 void
1825 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
1826 {
1827         static MonoMethod *setter = NULL;
1828         MonoDomain *domain = mono_domain_get ();
1829         MonoClass *field_class;
1830         MonoMethodMessage *msg;
1831         MonoArray *out_args;
1832         MonoObject *exc;
1833         MonoObject *arg;
1834
1835         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
1836
1837         if (!setter) {
1838                 int i;
1839
1840                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
1841                         MonoMethod *cm = mono_defaults.object_class->methods [i];
1842                
1843                         if (!strcmp (cm->name, "FieldSetter")) {
1844                                 setter = cm;
1845                                 break;
1846                         }
1847                 }
1848                 g_assert (setter);
1849         }
1850
1851         field_class = mono_class_from_mono_type (field->type);
1852
1853         if (field_class->valuetype)
1854                 arg = mono_value_box (domain, field_class, val);
1855         else 
1856                 arg = *((MonoObject **)val);
1857                 
1858
1859         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
1860         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
1861
1862         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
1863         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
1864         mono_array_set (msg->args, gpointer, 2, arg);
1865
1866         mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)this)->rp, msg, &exc, &out_args);
1867 }
1868
1869
1870
1871