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