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