Thu May 9 18:50:00 EDT 2002 Daniel Morgan <danmorg@sc.rr.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 #if HAVE_BOEHM_GC
22 #include <gc/gc.h>
23 #endif
24
25 MonoStats mono_stats;
26
27 /* next object id for object hashcode */
28 static guint32 uoid = 0;
29
30 void
31 mono_runtime_object_init (MonoObject *this)
32 {
33         int i;
34         MonoMethod *method = NULL;
35         MonoClass *klass = this->vtable->klass;
36
37         for (i = 0; i < klass->method.count; ++i) {
38                 if (!strcmp (".ctor", klass->methods [i]->name) &&
39                     klass->methods [i]->signature->param_count == 0) {
40                         method = klass->methods [i];
41                         break;
42                 }
43         }
44
45         g_assert (method);
46
47         mono_runtime_invoke (method, this, NULL);
48 }
49
50 /*
51  * runtime_class_init:
52  * @klass: klass that needs to be initialized
53  *
54  * This routine calls the class constructor for @class.
55  */
56 void
57 mono_runtime_class_init (MonoClass *klass)
58 {
59         int i;
60
61         for (i = 0; i < klass->method.count; ++i) {
62                 MonoMethod *method = klass->methods [i];
63                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
64                     (strcmp (".cctor", method->name) == 0)) {
65                         mono_runtime_invoke (method, NULL, NULL);
66                         return;
67                 }
68         }
69         /* No class constructor found */
70 }
71
72 static gpointer
73 default_trampoline (MonoMethod *method)
74 {
75         return method;
76 }
77
78 static gpointer
79 default_remoting_trampoline (MonoMethod *method)
80 {
81         g_error ("remoting not installed");
82         return NULL;
83 }
84
85 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
86 static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
87
88 void
89 mono_install_trampoline (MonoTrampoline func) 
90 {
91         arch_create_jit_trampoline = func? func: default_trampoline;
92 }
93
94 void
95 mono_install_remoting_trampoline (MonoTrampoline func) 
96 {
97         arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
98 }
99
100 #if 0 && HAVE_BOEHM_GC
101 static void
102 vtable_finalizer (void *obj, void *data) {
103         g_print ("%s finalized (%p)\n", (char*)data, obj);
104 }
105 #endif
106
107 /**
108  * mono_class_vtable:
109  * @domain: the application domain
110  * @class: the class to initialize
111  *
112  * VTables are domain specific because we create domain specific code, and 
113  * they contain the domain specific static class data.
114  */
115 MonoVTable *
116 mono_class_vtable (MonoDomain *domain, MonoClass *class)
117 {
118         MonoClass *k;
119         MonoVTable *vt;
120         MonoClassField *field;
121         guint32 cindex;
122         guint32 cols [MONO_CONSTANT_SIZE];
123         const char *p;
124         char *t;
125         int i, len;
126
127         g_assert (class);
128
129         /* can interfaces have static fields? */
130         if (class->flags & TYPE_ATTRIBUTE_INTERFACE)
131                 g_assert_not_reached ();
132
133         mono_domain_lock (domain);
134         if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
135                 mono_domain_unlock (domain);
136                 return vt;
137         }
138         
139         if (!class->inited)
140                 mono_class_init (class);
141
142 //      mono_stats.used_class_count++;
143 //      mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
144
145         vt = mono_mempool_alloc0 (domain->mp,  sizeof (MonoVTable) + 
146                                   class->vtable_size * sizeof (gpointer));
147         vt->klass = class;
148         vt->domain = domain;
149
150         if (class->class_size) {
151 #if HAVE_BOEHM_GC
152                 vt->data = GC_malloc (class->class_size + 8);
153                 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
154                 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
155                 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
156 #else
157                 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
158                 
159 #endif
160 //              mono_stats.class_static_data_size += class->class_size + 8;
161         }
162
163         for (i = class->field.first; i < class->field.last; ++i) {
164                 field = &class->fields [i - class->field.first];
165                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
166                         continue;
167                 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
168                         continue;
169                 cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1));
170                 if (!cindex) {
171                         g_warning ("constant for field %s not found", field->name);
172                         continue;
173                 }
174                 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, cols, MONO_CONSTANT_SIZE);
175                 p = mono_metadata_blob_heap (class->image, cols [MONO_CONSTANT_VALUE]);
176                 len = mono_metadata_decode_blob_size (p, &p);
177                 t = (char*)vt->data + field->offset;
178                 /* should we check that the type matches? */
179                 switch (cols [MONO_CONSTANT_TYPE]) {
180                 case MONO_TYPE_BOOLEAN:
181                 case MONO_TYPE_U1:
182                 case MONO_TYPE_I1:
183                         *t = *p;
184                         break;
185                 case MONO_TYPE_CHAR:
186                 case MONO_TYPE_U2:
187                 case MONO_TYPE_I2: {
188                         guint16 *val = (guint16*)t;
189                         *val = read16 (p);
190                         break;
191                 }
192                 case MONO_TYPE_U4:
193                 case MONO_TYPE_I4: {
194                         guint32 *val = (guint32*)t;
195                         *val = read32 (p);
196                         break;
197                 }
198                 case MONO_TYPE_U8:
199                 case MONO_TYPE_I8: {
200                         guint64 *val = (guint64*)t;
201                         *val = read64 (p);
202                         break;
203                 }
204                 case MONO_TYPE_R4: {
205                         float *val = (float*)t;
206                         readr4 (p, val);
207                         break;
208                 }
209                 case MONO_TYPE_R8: {
210                         double *val = (double*)t;
211                         readr8 (p, val);
212                         break;
213                 }
214                 case MONO_TYPE_STRING: {
215                         //gpointer *val = (gpointer*)t;
216                         //*val = mono_string_new_utf16 (domain, (const guint16*)p, len/2);
217                         break;
218                 }
219                 case MONO_TYPE_CLASS:
220                         /* nothing to do, we malloc0 the data and the value can be 0 only */
221                         break;
222                 default:
223                         g_warning ("type 0x%02x should not be in constant table", cols [MONO_CONSTANT_TYPE]);
224                 }
225         }
226
227         vt->max_interface_id = class->max_interface_id;
228         
229         vt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
230                 sizeof (gpointer) * (class->max_interface_id + 1));
231
232         /* initialize interface offsets */
233         for (k = class; k ; k = k->parent) {
234                 for (i = 0; i < k->interface_count; i++) {
235                         int slot;
236                         MonoClass *ic = k->interfaces [i];
237                         slot = class->interface_offsets [ic->interface_id];
238                         vt->interface_offsets [ic->interface_id] = &vt->vtable [slot];
239                 }
240         }
241
242         /* initialize vtable */
243         for (i = 0; i < class->vtable_size; ++i) {
244                 MonoMethod *cm;
245                
246                 if ((cm = class->vtable [i]))
247                         vt->vtable [i] = arch_create_jit_trampoline (cm);
248         }
249
250         mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
251         mono_domain_unlock (domain);
252
253         mono_runtime_class_init (class);
254
255         return vt;
256 }
257
258 /**
259  * mono_class_proxy_vtable:
260  * @domain: the application domain
261  * @class: the class to proxy
262  *
263  * Creates a vtable for transparent proxies. It is basically
264  * a copy of the real vtable of @class, but all function pointers invoke
265  * the remoting functions, and vtable->klass points to the 
266  * transparent proxy class, and not to @class.
267  */
268 MonoVTable *
269 mono_class_proxy_vtable (MonoDomain *domain, MonoClass *class)
270 {
271         MonoVTable *vt, *pvt;
272         int i, vtsize;
273
274         if ((pvt = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class)))
275                 return pvt;
276
277         vt = mono_class_vtable (domain, class);
278         vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
279
280 //      mono_stats.class_vtable_size += vtsize;
281
282         pvt = mono_mempool_alloc (domain->mp, vtsize);
283         memcpy (pvt, vt, vtsize);
284
285         pvt->klass = mono_defaults.transparent_proxy_class;
286
287         /* initialize vtable */
288         for (i = 0; i < class->vtable_size; ++i) {
289                 MonoMethod *cm;
290                
291                 if ((cm = class->vtable [i]))
292                         pvt->vtable [i] = arch_create_remoting_trampoline (cm);
293         }
294
295         mono_g_hash_table_insert (domain->proxy_vtable_hash, class, pvt);
296
297         return pvt;
298 }
299
300 static MonoInvokeFunc default_mono_runtime_invoke = NULL;
301
302 MonoObject*
303 mono_runtime_invoke (MonoMethod *method, void *obj, void **params)
304 {
305         if (!default_mono_runtime_invoke) {
306                 g_error ("runtime invoke called on uninitialized runtime");
307                 return NULL;
308         }
309         return default_mono_runtime_invoke (method, obj, params);
310 }
311
312 static MonoArray* main_args;
313
314 MonoArray*
315 mono_runtime_get_main_args (void)
316 {
317         return main_args;
318 }
319
320 /*
321  * Execute a standard Main() method (argc/argv contains the
322  * executable name). This method also sets the command line argument value
323  * needed by System.Environment.
324  */
325 int
326 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[])
327 {
328         int i;
329         MonoArray *args = NULL;
330         MonoDomain *domain = mono_domain_get ();
331
332         main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
333         for (i = 0; i < argc; ++i) {
334                 MonoString *arg = mono_string_new (domain, argv [i]);
335                 mono_array_set (main_args, gpointer, i, arg);
336         }
337         argc--;
338         argv++;
339         if (method->signature->param_count) {
340                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
341                 for (i = 0; i < argc; ++i) {
342                         MonoString *arg = mono_string_new (domain, argv [i]);
343                         mono_array_set (args, gpointer, i, arg);
344                 }
345         }
346         
347         return mono_runtime_exec_main (method, args);
348 }
349
350 /*
351  * Execute a standard Main() method (args doesn't contain the
352  * executable name).
353  */
354 int
355 mono_runtime_exec_main (MonoMethod *method, MonoArray *args)
356 {
357         gpointer pa [1];
358
359         pa [0] = args;
360
361         /* FIXME: check signature of method */
362         if (method->signature->ret->type == MONO_TYPE_I4) {
363                 MonoObject *res;
364                 res = mono_runtime_invoke (method, NULL, pa);
365                 return *(guint32 *)((char *)res + sizeof (MonoObject));
366         } else {
367                 mono_runtime_invoke (method, NULL, pa);
368                 return 0;
369         }
370 }
371
372 void
373 mono_install_runtime_invoke (MonoInvokeFunc func)
374 {
375         default_mono_runtime_invoke = func;
376 }
377
378 MonoObject*
379 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params)
380 {
381         MonoMethodSignature *sig = method->signature;
382         gpointer *pa = NULL;
383         int i;
384                 
385         if (NULL != params) {
386                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
387                 for (i = 0; i < mono_array_length (params); i++) {
388                         if (sig->params [i]->byref) {
389                                 /* nothing to do */
390                         }
391
392                         switch (sig->params [i]->type) {
393                         case MONO_TYPE_U1:
394                         case MONO_TYPE_I1:
395                         case MONO_TYPE_BOOLEAN:
396                         case MONO_TYPE_U2:
397                         case MONO_TYPE_I2:
398                         case MONO_TYPE_CHAR:
399                         case MONO_TYPE_U:
400                         case MONO_TYPE_I:
401                         case MONO_TYPE_U4:
402                         case MONO_TYPE_I4:
403                         case MONO_TYPE_U8:
404                         case MONO_TYPE_I8:
405                         case MONO_TYPE_VALUETYPE:
406                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
407                                 break;
408                         case MONO_TYPE_STRING:
409                         case MONO_TYPE_OBJECT:
410                         case MONO_TYPE_CLASS:
411                                 pa [i] = (char *)(((gpointer *)params->vector)[i]);
412                                 break;
413                         default:
414                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
415                         }
416                 }
417         }
418
419         if (!strcmp (method->name, ".ctor")) {
420                 obj = mono_object_new (mono_domain_get (), method->klass);
421                 mono_runtime_invoke (method, obj, pa);
422                 return obj;
423         } else
424                 return mono_runtime_invoke (method, obj, pa);
425 }
426
427 /**
428  * mono_object_allocate:
429  * @size: number of bytes to allocate
430  *
431  * This is a very simplistic routine until we have our GC-aware
432  * memory allocator. 
433  *
434  * Returns: an allocated object of size @size, or NULL on failure.
435  */
436 void *
437 mono_object_allocate (size_t size)
438 {
439 #if HAVE_BOEHM_GC
440         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
441         void *o = GC_malloc (size);
442 #else
443         void *o = calloc (1, size);
444 #endif
445
446         return o;
447 }
448
449 /**
450  * mono_object_free:
451  *
452  * Frees the memory used by the object.  Debugging purposes
453  * only, as we will have our GC system.
454  */
455 void
456 mono_object_free (MonoObject *o)
457 {
458 #if HAVE_BOEHM_GC
459         g_error ("mono_object_free called with boehm gc.");
460 #else
461         MonoClass *c = o->vtable->klass;
462         
463         memset (o, 0, c->instance_size);
464         free (o);
465 #endif
466 }
467
468 /**
469  * mono_object_new:
470  * @klass: the class of the object that we want to create
471  *
472  * Returns: A newly created object whose definition is
473  * looked up using @klass
474  */
475 MonoObject *
476 mono_object_new (MonoDomain *domain, MonoClass *klass)
477 {
478         return mono_object_new_specific (mono_class_vtable (domain, klass));
479 }
480
481 /**
482  * mono_object_new_specific:
483  * @vtable: the vtable of the object that we want to create
484  *
485  * Returns: A newly created object with class and domain specified
486  * by @vtable
487  */
488 MonoObject *
489 mono_object_new_specific (MonoVTable *vtable)
490 {
491         MonoObject *o;
492
493         mono_stats.new_object_count++;          /* thread safe? */
494
495         /* if the returned pointer is not the same as the address returned by GC_malloc(), 
496          * we need to change also metadata/gc.c to take into account the new offset.
497          */
498         if (vtable->klass->ghcimpl)
499                 o = mono_object_allocate (vtable->klass->instance_size);
500         else {
501                 guint32 *t;
502                 t = mono_object_allocate (vtable->klass->instance_size + 4);
503                 *t = ++uoid;
504                 o = (MonoObject *)(++t);
505         }
506         o->vtable = vtable;
507         if (vtable->klass->has_finalize)
508                 mono_object_register_finalizer (o);
509         
510         return o;
511 }
512
513 /**
514  * mono_object_new_from_token:
515  * @image: Context where the type_token is hosted
516  * @token: a token of the type that we want to create
517  *
518  * Returns: A newly created object whose definition is
519  * looked up using @token in the @image image
520  */
521 MonoObject *
522 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
523 {
524         MonoClass *class;
525
526         class = mono_class_get (image, token);
527
528         return mono_object_new (domain, class);
529 }
530
531
532 /**
533  * mono_object_clone:
534  * @obj: the object to clone
535  *
536  * Returns: A newly created object who is a shallow copy of @obj
537  */
538 MonoObject *
539 mono_object_clone (MonoObject *obj)
540 {
541         MonoObject *o;
542         int size;
543
544         size = obj->vtable->klass->instance_size;
545         o = mono_object_allocate (size);
546
547         memcpy (o, obj, size);
548
549         if (obj->vtable->klass->has_finalize)
550                 mono_object_register_finalizer (o);
551         return o;
552 }
553
554 /**
555  * mono_array_clone:
556  * @array: the array to clone
557  *
558  * Returns: A newly created array who is a shallow copy of @array
559  */
560 MonoArray*
561 mono_array_clone (MonoArray *array)
562 {
563         MonoArray *o;
564         int size, i;
565         guint32 *sizes;
566         MonoClass *klass = array->obj.vtable->klass;
567
568         if (array->bounds == NULL) {
569                 size = mono_array_length (array);
570                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
571                                          klass, &size, NULL);
572
573                 size *= mono_array_element_size (klass);
574                 memcpy (o, array, sizeof (MonoArray) + size);
575
576                 return o;
577         }
578         
579         sizes = alloca (klass->rank * sizeof(guint32) * 2);
580         size = mono_array_element_size (klass);
581         for (i = 0; i < klass->rank; ++i) {
582                 sizes [i] = array->bounds [i].length;
583                 size *= array->bounds [i].length;
584                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
585         }
586         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
587                                  klass, sizes, sizes + klass->rank);
588         memcpy (o, array, sizeof(MonoArray) + size);
589
590         return o;
591 }
592
593 /*
594  * mono_array_new_full:
595  * @domain: domain where the object is created
596  * @array_class: array class
597  * @lengths: lengths for each dimension in the array
598  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
599  *
600  * This routine creates a new array objects with the given dimensions,
601  * lower bounds and type.
602  */
603 MonoArray*
604 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
605                      guint32 *lengths, guint32 *lower_bounds)
606 {
607         guint32 byte_len, len;
608         MonoObject *o;
609         MonoArray *array;
610         MonoArrayBounds *bounds;
611         int i;
612
613         if (!array_class->inited)
614                 mono_class_init (array_class);
615
616         byte_len = mono_array_element_size (array_class);
617         len = 1;
618
619         if (array_class->rank == 1 &&
620             (lower_bounds == NULL || lower_bounds [0] == 0)) {
621                 bounds = NULL;
622                 len = lengths [0];
623         } else {
624         #if HAVE_BOEHM_GC
625                 bounds = GC_malloc (sizeof (MonoArrayBounds) * array_class->rank);
626         #else
627                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
628         #endif
629                 for (i = 0; i < array_class->rank; ++i) {
630                         bounds [i].length = lengths [i];
631                         len *= lengths [i];
632                 }
633
634                 if (lower_bounds)
635                         for (i = 0; i < array_class->rank; ++i)
636                                 bounds [i].lower_bound = lower_bounds [i];
637         }
638
639         byte_len *= len;
640         /* 
641          * Following three lines almost taken from mono_object_new ():
642          * they need to be kept in sync.
643          */
644         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
645         if (!o)
646                 G_BREAKPOINT ();
647         o->vtable = mono_class_vtable (domain, array_class);
648
649         array = (MonoArray*)o;
650
651         array->bounds = bounds;
652         array->max_length = len;
653
654         return array;
655 }
656
657 /*
658  * mono_array_new:
659  * @domain: domain where the object is created
660  * @eclass: element class
661  * @n: number of array elements
662  *
663  * This routine creates a new szarray with @n elements of type @eclass.
664  */
665 MonoArray *
666 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
667 {
668         MonoClass *ac;
669
670         ac = mono_array_class_get (&eclass->byval_arg, 1);
671         g_assert (ac != NULL);
672
673         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
674 }
675
676 /*
677  * mono_array_new_specific:
678  * @vtable: a vtable in the appropriate domain for an initialized class
679  * @n: number of array elements
680  *
681  * This routine is a fast alternative to mono_array_new() for code which
682  * can be sure about the domain it operates in.
683  */
684 MonoArray *
685 mono_array_new_specific (MonoVTable *vtable, guint32 n)
686 {
687         MonoObject *o;
688         MonoArray *ao;
689         gsize byte_len;
690
691         byte_len = n * mono_array_element_size (vtable->klass);
692         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
693         if (!o)
694                 G_BREAKPOINT ();
695         o->vtable = vtable;
696
697         ao = (MonoArray *)o;
698         ao->bounds = NULL;
699         ao->max_length = n;
700
701         return ao;
702 }
703
704 /**
705  * mono_string_new_utf16:
706  * @text: a pointer to an utf16 string
707  * @len: the length of the string
708  *
709  * Returns: A newly created string object which contains @text.
710  */
711 MonoString *
712 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
713 {
714         MonoString *s;
715         
716         s = mono_string_new_size (domain, len);
717         g_assert (s != NULL);
718
719         memcpy (mono_string_chars (s), text, len * 2);
720
721         return s;
722 }
723
724 /**
725  * mono_string_new_size:
726  * @text: a pointer to an utf16 string
727  * @len: the length of the string
728  *
729  * Returns: A newly created string object of @len
730  */
731 MonoString *
732 mono_string_new_size (MonoDomain *domain, gint32 len)
733 {
734         MonoString *s;
735
736         /* 
737          * enable to get a good speedup: we still need to figure out
738          * how the sync structure is freed.
739          */
740 #if 0
741         s = GC_malloc_atomic (sizeof (MonoString) + ((len + 1) * 2));
742         s->object.synchronisation = 0;
743         mono_string_chars (s) [len] = 0;
744 #else
745         s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
746 #endif
747         if (!s)
748                 G_BREAKPOINT ();
749
750         s->object.vtable = mono_class_vtable (domain, mono_defaults.string_class);
751         s->length = len;
752
753         return s;
754 }
755
756 /*
757  * mono_string_new_len:
758  * @text: a pointer to an utf8 string
759  * @length: number of bytes in @text to consider
760  *
761  * Returns: A newly created string object which contains @text.
762  */
763 MonoString*
764 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
765 {
766         GError *error = NULL;
767         MonoString *o = NULL;
768         guint16 *ut;
769         glong items_written;
770
771         
772         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
773
774         if (!error)
775                 o = mono_string_new_utf16 (domain, ut, items_written);
776         else 
777                 g_error_free (error);
778
779         g_free (ut);
780
781         return o;
782 }
783
784 /**
785  * mono_string_new:
786  * @text: a pointer to an utf8 string
787  *
788  * Returns: A newly created string object which contains @text.
789  */
790 MonoString*
791 mono_string_new (MonoDomain *domain, const char *text)
792 {
793         GError *error = NULL;
794         MonoString *o = NULL;
795         guint16 *ut;
796         glong items_written;
797         int l;
798
799         l = strlen (text);
800         
801         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
802
803         if (!error)
804                 o = mono_string_new_utf16 (domain, ut, items_written);
805         else 
806                 g_error_free (error);
807
808         g_free (ut);
809
810         return o;
811 }
812
813 /*
814  * mono_string_new_wrapper:
815  * @text: pointer to utf8 characters.
816  *
817  * Helper function to create a string object from @text in the current domain.
818  */
819 MonoString*
820 mono_string_new_wrapper (const char *text)
821 {
822         MonoDomain *domain = mono_domain_get ();
823
824         return mono_string_new (domain, text);
825 }
826
827 /**
828  * mono_value_box:
829  * @class: the class of the value
830  * @value: a pointer to the unboxed data
831  *
832  * Returns: A newly created object which contains @value.
833  */
834 MonoObject *
835 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
836 {
837         MonoObject *res;
838         int size;
839
840         g_assert (class->valuetype);
841
842         size = mono_class_instance_size (class);
843         res = mono_object_allocate (size);
844         res->vtable = mono_class_vtable (domain, class);
845
846         size = size - sizeof (MonoObject);
847
848         memcpy ((char *)res + sizeof (MonoObject), value, size);
849
850         if (class->has_finalize)
851                 mono_object_register_finalizer (res);
852         return res;
853 }
854
855 /**
856  * mono_object_isinst:
857  * @obj: an object
858  * @klass: a pointer to a class 
859  *
860  * Returns: @obj if @obj is derived from @klass
861  */
862 MonoObject *
863 mono_object_isinst (MonoObject *obj, MonoClass *klass)
864 {
865         MonoVTable *vt;
866         MonoClass *oklass;
867
868         if (!obj)
869                 return NULL;
870
871         vt = obj->vtable;
872         oklass = vt->klass;
873
874         if (!klass->inited)
875                 mono_class_init (klass);
876
877         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
878                 if ((klass->interface_id <= oklass->max_interface_id) &&
879                     vt->interface_offsets [klass->interface_id])
880                         return obj;
881         } else {
882                 if (oklass == mono_defaults.transparent_proxy_class) {
883                         /* fixme: add check for IRemotingTypeInfo */
884                         oklass = ((MonoTransparentProxy *)obj)->klass;
885                 }
886                 if (klass->rank) {
887                         if (oklass->rank == klass->rank && 
888                             (oklass->element_class->baseval - klass->element_class->baseval) <= 
889                             klass->element_class->diffval)
890                                 return obj;
891                         
892                 } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
893                         return obj;
894         }
895
896         return NULL;
897 }
898
899 static MonoString*
900 mono_string_is_interned_lookup (MonoString *str, int insert)
901 {
902         MonoGHashTable *ldstr_table;
903         MonoString *res;
904         MonoDomain *domain;
905         char *ins = g_malloc (4 + str->length * 2);
906         char *p;
907         int bloblen;
908         
909         /* Encode the length */
910         p = ins;
911         mono_metadata_encode_value (2 * str->length, p, &p);
912         bloblen = p - ins;
913         p = ins;
914         mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
915         bloblen = (p - ins) + 2 * str->length;
916         /*
917          * ins is stored in the hash table as a key and needs to have the same
918          * representation as in the metadata: we swap the character bytes on big
919          * endian boxes.
920          */
921 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
922         {
923                 int i;
924                 char *p2 = mono_string_chars (str);
925                 for (i = 0; i < str->length; ++i) {
926                         *p++ = p2 [1];
927                         *p++ = p2 [0];
928                         p2 += 2;
929                 }
930         }
931 #else
932         memcpy (p, mono_string_chars (str), str->length * 2);
933 #endif
934         domain = ((MonoObject *)str)->vtable->domain;
935         ldstr_table = domain->ldstr_table;
936         mono_domain_lock (domain);
937         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
938                 mono_domain_unlock (domain);
939                 g_free (ins);
940                 return res;
941         }
942         if (insert) {
943                 mono_g_hash_table_insert (ldstr_table, ins, str);
944                 mono_domain_unlock (domain);
945                 return str;
946         }
947         mono_domain_unlock (domain);
948         g_free (ins);
949         return NULL;
950 }
951
952 MonoString*
953 mono_string_is_interned (MonoString *o)
954 {
955         return mono_string_is_interned_lookup (o, FALSE);
956 }
957
958 MonoString*
959 mono_string_intern (MonoString *str)
960 {
961         return mono_string_is_interned_lookup (str, TRUE);
962 }
963
964 /*
965  * mono_ldstr:
966  * @domain: the domain where the string will be used.
967  * @image: a metadata context
968  * @idx: index into the user string table.
969  * 
970  * Implementation for the ldstr opcode.
971  */
972 MonoString*
973 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
974 {
975         const char *str, *sig;
976         MonoString *o;
977         size_t len2;
978                 
979         sig = str = mono_metadata_user_string (image, idx);
980
981         mono_domain_lock (domain);
982         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
983                 mono_domain_unlock (domain);
984                 return o;
985         }
986         
987         len2 = mono_metadata_decode_blob_size (str, &str);
988         len2 >>= 1;
989
990         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
991 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
992         {
993                 int i;
994                 guint16 *p2 = (guint16*)mono_string_chars (o);
995                 for (i = 0; i < len2; ++i) {
996                         *p2 = GUINT16_FROM_LE (*p2);
997                         ++p2;
998                 }
999         }
1000 #endif
1001         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
1002         mono_domain_unlock (domain);
1003
1004         return o;
1005 }
1006
1007 /*
1008  * mono_string_to_utf8:
1009  * @s: a System.String
1010  *
1011  * Return the UTF8 representation for @s.
1012  * the resulting buffer nedds to be freed with g_free().
1013  */
1014 char *
1015 mono_string_to_utf8 (MonoString *s)
1016 {
1017         char *as;
1018         GError *error = NULL;
1019
1020         g_assert (s != NULL);
1021
1022         if (!s->length)
1023                 return g_strdup ("");
1024
1025         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
1026         if (error)
1027                 g_warning (error->message);
1028
1029         return as;
1030 }
1031
1032 /*
1033  * mono_string_to_utf16:
1034  * @s: a MonoString
1035  *
1036  * Return an null-terminated array of the utf-16 chars
1037  * contained in @s. The result must be freed with g_free().
1038  * This is a temporary helper until our string implementation
1039  * is reworked to always include the null terminating char.
1040  */
1041 gunichar2 *
1042 mono_string_to_utf16 (MonoString *s)
1043 {
1044         char *as;
1045
1046         g_assert (s != NULL);
1047
1048         as = g_malloc ((s->length * 2) + 2);
1049         as [(s->length * 2)] = '\0';
1050         as [(s->length * 2) + 1] = '\0';
1051
1052         if (!s->length) {
1053                 return (gunichar2 *)(as);
1054         }
1055         
1056         memcpy (as, mono_string_chars(s), s->length * 2);
1057         
1058         return (gunichar2 *)(as);
1059 }
1060
1061 static void
1062 default_ex_handler (MonoException *ex)
1063 {
1064         MonoObject *o = (MonoObject*)ex;
1065         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
1066 }
1067
1068 static MonoExceptionFunc ex_handler = default_ex_handler;
1069
1070 void
1071 mono_install_handler        (MonoExceptionFunc func)
1072 {
1073         ex_handler = func? func: default_ex_handler;
1074 }
1075
1076 /*
1077  * mono_raise_exception:
1078  * @ex: exception object
1079  *
1080  * Signal the runtime that the exception @ex has been raised in unmanaged code.
1081  */
1082 void
1083 mono_raise_exception (MonoException *ex) 
1084 {
1085         ex_handler (ex);
1086 }
1087
1088 MonoWaitHandle *
1089 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
1090 {
1091         MonoWaitHandle *res;
1092
1093         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
1094
1095         res->handle = handle;
1096
1097         return res;
1098 }
1099
1100 MonoAsyncResult *
1101 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
1102 {
1103         MonoAsyncResult *res;
1104
1105         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
1106
1107         res->data = data;
1108         res->async_state = state;
1109         res->handle = (MonoObject *)mono_wait_handle_new (domain, handle);
1110         res->sync_completed = FALSE;
1111         res->completed = FALSE;
1112
1113         return res;
1114 }
1115
1116 void
1117 mono_message_init (MonoDomain *domain,
1118                    MonoMethodMessage *this, 
1119                    MonoReflectionMethod *method,
1120                    MonoArray *out_args)
1121 {
1122         MonoMethodSignature *sig = method->method->signature;
1123         MonoString *name;
1124         int i, j;
1125         char **names;
1126         guint8 arg_type;
1127
1128         this->method = method;
1129
1130         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
1131         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
1132
1133         names = g_new (char *, sig->param_count);
1134         mono_method_get_param_names (method->method, (const char **) names);
1135         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
1136         
1137         for (i = 0; i < sig->param_count; i++) {
1138                  name = mono_string_new (domain, names [i]);
1139                  mono_array_set (this->names, gpointer, i, name);       
1140         }
1141
1142         g_free (names);
1143         
1144         for (i = 0, j = 0; i < sig->param_count; i++) {
1145
1146                 if (sig->params [i]->byref) {
1147                         if (out_args) {
1148                                 gpointer arg = mono_array_get (out_args, gpointer, j);
1149                                 mono_array_set (this->args, gpointer, i, arg);
1150                                 j++;
1151                         }
1152                         arg_type = 2;
1153                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_IN)
1154                                 arg_type |= 1;
1155                 } else {
1156                         arg_type = 1;
1157                 }
1158
1159                 mono_array_set (this->arg_types, guint8, i, arg_type);
1160         }
1161 }
1162
1163 /**
1164  * mono_remoting_invoke:
1165  * @real_proxy: pointer to a RealProxy object
1166  * @msg: The MonoMethodMessage to execute
1167  * @exc: used to store exceptions
1168  * @out_args: used to store output arguments
1169  *
1170  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
1171  * IMessage interface and it is not trivial to extract results from there. So
1172  * we call an helper method PrivateInvoke instead of calling
1173  * RealProxy::Invoke() directly.
1174  *
1175  * Returns: the result object.
1176  */
1177 MonoObject *
1178 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
1179                       MonoObject **exc, MonoArray **out_args)
1180 {
1181         static MonoMethod *im = NULL;
1182         gpointer pa [4];
1183
1184         //static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;
1185
1186         /* fixme: make this domain dependent */
1187         if (!im) {
1188                 MonoClass *klass;
1189                 int i;
1190
1191                 klass = mono_defaults.real_proxy_class; 
1192                        
1193                 for (i = 0; i < klass->method.count; ++i) {
1194                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
1195                             klass->methods [i]->signature->param_count == 4) {
1196                                 im = klass->methods [i];
1197                                 break;
1198                         }
1199                 }
1200         
1201                 g_assert (im);
1202         }
1203
1204         pa [0] = real_proxy;
1205         pa [1] = msg;
1206         pa [2] = exc;
1207         pa [3] = out_args;
1208
1209         return mono_runtime_invoke (im, NULL, pa);
1210 }
1211
1212 MonoObject *
1213 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
1214                      MonoObject **exc, MonoArray **out_args) 
1215 {
1216         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
1217
1218                 return mono_remoting_invoke ((MonoObject *)((MonoTransparentProxy *)target)->rp, 
1219                                              msg, exc, out_args);
1220
1221         } else {
1222                 MonoDomain *domain = mono_domain_get (); 
1223                 MonoMethod *method = msg->method->method;
1224                 MonoMethodSignature *sig = method->signature;
1225                 int i, j, outarg_count = 0;
1226
1227                 for (i = 0; i < sig->param_count; i++) {
1228                         if (sig->params [i]->byref) 
1229                                 outarg_count++;
1230                 }
1231
1232                 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
1233                 *exc = NULL;
1234
1235                 for (i = 0, j = 0; i < sig->param_count; i++) {
1236                         if (sig->params [i]->byref) {
1237                                 gpointer arg;
1238                                 arg = mono_array_get (msg->args, gpointer, i);
1239                                 mono_array_set (*out_args, gpointer, j, arg);
1240                                 j++;
1241                         }
1242                 }
1243
1244                 return mono_runtime_invoke_array (method, target, msg->args);
1245         }
1246 }
1247
1248
1249