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