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