imported delegate patches from Daniel, new GetHashCode icalls
[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/tabledefs.h>
15 #include <mono/metadata/loader.h>
16 #include <mono/metadata/object.h>
17 #include <mono/metadata/appdomain.h>
18 #if HAVE_BOEHM_GC
19 #include <gc/gc.h>
20 #endif
21
22 static void
23 default_runtime_object_init (MonoObject *o)
24 {
25         return;
26 }
27
28 MonoRuntimeObjectInit mono_runtime_object_init = default_runtime_object_init;
29 MonoRuntimeExecMain   mono_runtime_exec_main = NULL;
30
31 void
32 mono_install_runtime_object_init (MonoRuntimeObjectInit func)
33 {
34         mono_runtime_object_init = func? func: default_runtime_object_init;
35 }
36
37 void
38 mono_install_runtime_exec_main (MonoRuntimeExecMain func)
39 {
40         mono_runtime_exec_main = func;
41 }
42
43 /**
44  * mono_object_allocate:
45  * @size: number of bytes to allocate
46  *
47  * This is a very simplistic routine until we have our GC-aware
48  * memory allocator. 
49  *
50  * Returns: an allocated object of size @size, or NULL on failure.
51  */
52 void *
53 mono_object_allocate (size_t size)
54 {
55 #if HAVE_BOEHM_GC
56         void *o = GC_malloc (size);
57 #else
58         void *o = calloc (1, size);
59 #endif
60
61         return o;
62 }
63
64 /**
65  * mono_object_free:
66  *
67  * Frees the memory used by the object.  Debugging purposes
68  * only, as we will have our GC system.
69  */
70 void
71 mono_object_free (MonoObject *o)
72 {
73 #if HAVE_BOEHM_GC
74         g_error ("mono_object_free called with boehm gc.");
75 #else
76         MonoClass *c = o->vtable->klass;
77         
78         memset (o, 0, c->instance_size);
79         free (o);
80 #endif
81 }
82
83 /**
84  * mono_object_new:
85  * @klass: the class of the object that we want to create
86  *
87  * Returns: A newly created object whose definition is
88  * looked up using @klass
89  */
90 MonoObject *
91 mono_object_new (MonoDomain *domain, MonoClass *klass)
92 {
93         static guint32 uoid = 0;
94         MonoObject *o;
95
96         if (!klass->inited)
97                 mono_class_init (klass);
98
99
100         if (klass->ghcimpl) {
101                 o = mono_object_allocate (klass->instance_size);
102                 o->vtable = mono_class_vtable (domain, klass);
103         } else {
104                 guint32 *t;
105                 t = mono_object_allocate (klass->instance_size + 4);
106                 *t = ++uoid;
107                 o = (MonoObject *)(++t);
108                 o->vtable = mono_class_vtable (domain, klass);
109         }
110
111         return o;
112 }
113
114 /**
115  * mono_object_new_from_token:
116  * @image: Context where the type_token is hosted
117  * @token: a token of the type that we want to create
118  *
119  * Returns: A newly created object whose definition is
120  * looked up using @token in the @image image
121  */
122 MonoObject *
123 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
124 {
125         MonoClass *class;
126
127         class = mono_class_get (image, token);
128
129         return mono_object_new (domain, class);
130 }
131
132
133 /**
134  * mono_object_clone:
135  * @obj: the object to clone
136  *
137  * Returns: A newly created object who is a shallow copy of @obj
138  */
139 MonoObject *
140 mono_object_clone (MonoObject *obj)
141 {
142         MonoObject *o;
143         int size;
144
145         size = obj->vtable->klass->instance_size;
146         o = mono_object_allocate (size);
147
148         memcpy (o, obj, size);
149
150         return o;
151 }
152
153 /**
154  * mono_array_clone:
155  * @array: the array to clone
156  *
157  * Returns: A newly created array who is a shallow copy of @array
158  */
159 MonoArray*
160 mono_array_clone (MonoArray *array)
161 {
162         MonoArray *o;
163         int size, i;
164         guint32 *sizes;
165         MonoClass *klass = array->obj.vtable->klass;
166         
167         sizes = alloca (klass->rank * sizeof(guint32) * 2);
168         size = mono_array_element_size (klass);
169         for (i = 0; i < klass->rank; ++i) {
170                 sizes [i] = array->bounds [i].length;
171                 size *= array->bounds [i].length;
172                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
173         }
174         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
175                                  klass, sizes, sizes + klass->rank);
176         memcpy (o, array, sizeof(MonoArray) + size);
177
178         return o;
179 }
180
181 MonoArray*
182 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
183                      guint32 *lengths, guint32 *lower_bounds)
184 {
185         guint32 byte_len;
186         MonoObject *o;
187         MonoArray *array;
188         MonoArrayBounds *bounds;
189         int i;
190
191         if (!array_class->inited)
192                 mono_class_init (array_class);
193
194         byte_len = mono_array_element_size (array_class);
195
196         bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
197         for (i = 0; i < array_class->rank; ++i) {
198                 bounds [i].length = lengths [i];
199                 byte_len *= lengths [i];
200         }
201
202         if (lower_bounds)
203                 for (i = 0; i < array_class->rank; ++i)
204                         bounds [i].lower_bound = lower_bounds [i];
205         /* 
206          * Following three lines almost taken from mono_object_new ():
207          * they need to be kept in sync.
208          */
209         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
210         if (!o)
211                 G_BREAKPOINT ();
212         o->vtable = mono_class_vtable (domain, array_class);
213
214         array = (MonoArray*)o;
215
216         array->bounds = bounds;
217         array->max_length = bounds [0].length;
218
219         return array;
220 }
221
222 /*
223  * mono_array_new:
224  * @image: image where the object is being referenced
225  * @eclass: element class
226  * @n: number of array elements
227  *
228  * This routine creates a new szarray with @n elements of type @token
229  */
230 MonoArray *
231 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
232 {
233         MonoClass *ac;
234
235         ac = mono_array_class_get (&eclass->byval_arg, 1);
236         g_assert (ac != NULL);
237
238         return mono_array_new_full (domain, ac, &n, NULL);
239 }
240
241 /**
242  * mono_string_new_utf16:
243  * @text: a pointer to an utf16 string
244  * @len: the length of the string
245  *
246  * Returns: A newly created string object which contains @text.
247  */
248 MonoString *
249 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
250 {
251         MonoString *s;
252         MonoArray *ca;
253
254         s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
255         g_assert (s != NULL);
256
257         ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
258         g_assert (ca != NULL);
259         
260         s->c_str = ca;
261         s->length = len;
262
263         memcpy (ca->vector, text, len * 2);
264
265         return s;
266 }
267
268 MonoString*
269 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
270 {
271         GError *error = NULL;
272         MonoString *o = NULL;
273         guint16 *ut;
274         glong items_written;
275
276         
277         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
278
279         if (!error)
280                 o = mono_string_new_utf16 (domain, ut, items_written);
281         else 
282                 g_error_free (error);
283
284         g_free (ut);
285
286         return o;
287 }
288
289 /**
290  * mono_string_new:
291  * @text: a pointer to an utf8 string
292  *
293  * Returns: A newly created string object which contains @text.
294  */
295 MonoString*
296 mono_string_new (MonoDomain *domain, const char *text)
297 {
298         GError *error = NULL;
299         MonoString *o = NULL;
300         guint16 *ut;
301         glong items_written;
302         int l;
303
304         l = strlen (text);
305         
306         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
307
308         if (!error)
309                 o = mono_string_new_utf16 (domain, ut, items_written);
310         else 
311                 g_error_free (error);
312
313         g_free (ut);
314
315         return o;
316 }
317
318 /**
319  * mono_value_box:
320  * @class: the class of the value
321  * @value: a pointer to the unboxed data
322  *
323  * Returns: A newly created object which contains @value.
324  */
325 MonoObject *
326 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
327 {
328         MonoObject *res;
329         int size;
330
331         g_assert (class->valuetype);
332
333         size = mono_class_instance_size (class);
334         res = mono_object_allocate (size);
335         res->vtable = mono_class_vtable (domain, class);
336
337         size = size - sizeof (MonoObject);
338
339         memcpy ((char *)res + sizeof (MonoObject), value, size);
340
341         return res;
342 }
343
344 /**
345  * mono_object_isinst:
346  * @obj: an object
347  * @klass: a pointer to a class 
348  *
349  * Returns: @obj if @obj is derived from @klass
350  */
351 MonoObject *
352 mono_object_isinst (MonoObject *obj, MonoClass *klass)
353 {
354         MonoVTable *vt;
355         MonoClass *oklass;
356
357         if (!obj)
358                 return NULL;
359
360         vt = obj->vtable;
361         oklass = vt->klass;
362
363         if (!klass->inited)
364                 mono_class_init (klass);
365
366         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
367                 if ((klass->interface_id <= oklass->max_interface_id) &&
368                     vt->interface_offsets [klass->interface_id])
369                         return obj;
370         } else {
371                 if (oklass->rank && oklass->rank == klass->rank) {
372                         if ((oklass->element_class->baseval - klass->element_class->baseval) <= 
373                             klass->element_class->diffval)
374                                 return obj;
375                 } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
376                         return obj;
377         }
378
379         return NULL;
380 }
381
382
383 typedef struct {
384         MonoString *obj;
385         MonoString *found;
386 } InternCheck;
387
388 static void
389 check_interned (gpointer key, MonoString *value, InternCheck *check)
390 {
391         if (value == check->obj)
392                 check->found = value;
393 }
394
395 MonoString*
396 mono_string_is_interned (MonoString *o)
397 {
398         InternCheck check;
399         check.obj = o;
400         check.found = NULL;
401
402         /*
403          * Yes, this is slow. Our System.String implementation needs to be redone.
404          * And GLib needs foreach() methods that can be stopped halfway.
405          */
406         g_hash_table_foreach (((MonoObject *)o)->vtable->domain->ldstr_table, (GHFunc)check_interned, &check);
407         return check.found;
408 }
409
410 MonoString*
411 mono_string_intern (MonoString *str)
412 {
413         GHashTable *ldstr_table;
414         MonoString *res;
415         char *ins = g_malloc (4 + str->length * 2);
416         char *p;
417         int bloblen;
418         
419         /* Encode the length */
420         p = ins;
421         mono_metadata_encode_value (2 * str->length, p, &p);
422         bloblen = p - ins;
423         p = ins;
424         mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
425         bloblen = (p - ins) + 2 * str->length;
426         /*
427          * ins is stored in the hash table as a key and needs to have the same
428          * representation as in the metadata: we swap the character bytes on big
429          * endian boxes.
430          */
431 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
432         {
433                 int i;
434                 char *p2 = mono_array_addr (str->c_str, char, 0);
435                 for (i = 0; i < str->length; ++i) {
436                         *p++ = p2 [1];
437                         *p++ = p2 [0];
438                         p2 += 2;
439                 }
440         }
441 #else
442         memcpy (p, str->c_str->vector, str->length * 2);
443 #endif
444         ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
445         if ((res = g_hash_table_lookup (ldstr_table, ins))) {
446                 g_free (ins);
447                 return res;
448         }
449         g_hash_table_insert (ldstr_table, ins, str);
450         return str;
451 }
452
453 MonoString*
454 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 index)
455 {
456         const char *str, *sig;
457         MonoString *o;
458         size_t len2;
459                 
460         sig = str = mono_metadata_user_string (image, index);
461         len2 = mono_metadata_decode_blob_size (str, &str);
462         
463         if ((o = g_hash_table_lookup (domain->ldstr_table, sig)))
464                 return o;
465         
466         len2 >>= 1;
467
468         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
469 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
470         {
471                 int i;
472                 guint16 *p2 = (guint16*)mono_array_addr (o->c_str, guint16, 0);
473                 for (i = 0; i < len2; ++i) {
474                         *p2 = GUINT16_FROM_LE (*p2);
475                         ++p2;
476                 }
477         }
478 #endif
479         g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
480
481         return o;
482 }
483
484 char *
485 mono_string_to_utf8 (MonoString *s)
486 {
487         char *as, *vector;
488         GError *error = NULL;
489
490         g_assert (s != NULL);
491
492         if (!s->length || !s->c_str)
493                 return g_strdup ("");
494
495         vector = (char*)s->c_str->vector;
496
497         g_assert (vector != NULL);
498
499         as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
500         if (error)
501                 g_warning (error->message);
502
503         return as;
504 }
505
506 char *
507 mono_string_to_utf16 (MonoString *s)
508 {
509         char *as;
510
511         g_assert (s != NULL);
512
513         as = g_malloc ((s->length * 2) + 2);
514         as [(s->length * 2)] = '\0';
515         as [(s->length * 2) + 1] = '\0';
516
517         if (!s->length || !s->c_str) {
518                 return (as);
519         }
520         
521         memcpy (as, mono_string_chars(s), s->length * 2);
522         
523         return (as);
524 }
525
526 static void
527 default_ex_handler (MonoException *ex)
528 {
529         MonoObject *o = (MonoObject*)ex;
530         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
531 }
532
533 static MonoExceptionFunc ex_handler = default_ex_handler;
534
535 void
536 mono_install_handler        (MonoExceptionFunc func)
537 {
538         ex_handler = func? func: default_ex_handler;
539 }
540
541 void
542 mono_raise_exception (MonoException *ex) 
543 {
544         ex_handler (ex);
545 }
546