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