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