2001-11-29 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 <string.h>
13 #include <mono/metadata/loader.h>
14 #include <mono/metadata/object.h>
15 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
16 #include <sys/mman.h>
17 #include <limits.h>    /* for PAGESIZE */
18 #ifndef PAGESIZE
19 #define PAGESIZE 4096
20 #endif
21 #endif
22
23 /**
24  * mono_object_allocate:
25  * @size: number of bytes to allocate
26  *
27  * This is a very simplistic routine until we have our GC-aware
28  * memory allocator. 
29  *
30  * Returns: an allocated object of size @size, or NULL on failure.
31  */
32 static void *
33 mono_object_allocate (size_t size)
34 {
35         void *o = calloc (1, size);
36
37         return o;
38 }
39
40 /**
41  * mono_object_free:
42  *
43  * Frees the memory used by the object.  Debugging purposes
44  * only, as we will have our GC system.
45  */
46 void
47 mono_object_free (MonoObject *o)
48 {
49         MonoClass *c = o->klass;
50         
51         memset (o, 0, c->instance_size);
52         free (o);
53 }
54
55 /**
56  * mono_object_new:
57  * @klass: the class of the object that we want to create
58  *
59  * Returns: A newly created object whose definition is
60  * looked up using @klass
61  */
62 MonoObject *
63 mono_object_new (MonoClass *klass)
64 {
65         MonoObject *o;
66
67         if (!klass->metadata_inited)
68                 mono_class_metadata_init (klass);
69
70         o = mono_object_allocate (klass->instance_size);
71         o->klass = klass;
72
73         return o;
74 }
75
76 /**
77  * mono_object_new_from_token:
78  * @image: Context where the type_token is hosted
79  * @token: a token of the type that we want to create
80  *
81  * Returns: A newly created object whose definition is
82  * looked up using @token in the @image image
83  */
84 MonoObject *
85 mono_object_new_from_token  (MonoImage *image, guint32 token)
86 {
87         MonoClass *class;
88
89         class = mono_class_get (image, token);
90
91         return mono_object_new (class);
92 }
93
94
95 /**
96  * mono_object_clone:
97  * @obj: the object to clone
98  *
99  * Returns: A newly created object who is a shallow copy of @obj
100  */
101 MonoObject *
102 mono_object_clone (MonoObject *obj)
103 {
104         MonoObject *o;
105         int size;
106         
107         size = obj->klass->instance_size;
108         o = mono_object_allocate (size);
109         /* FIXME: handle arrays... */
110         
111         memcpy (o, obj, size);
112
113         return o;
114 }
115
116 MonoArray*
117 mono_array_new_full (MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
118 {
119         guint32 byte_len;
120         MonoObject *o;
121         MonoArray *array;
122         MonoArrayBounds *bounds;
123         int i;
124
125         if (!array_class->metadata_inited)
126                 mono_class_metadata_init (array_class);
127         byte_len = mono_array_element_size (array_class);
128
129         bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
130         for (i = 0; i < array_class->rank; ++i) {
131                 bounds [i].length = lengths [i];
132                 byte_len *= lengths [i];
133         }
134
135         if (lower_bounds)
136                 for (i = 0; i < array_class->rank; ++i)
137                         bounds [i].lower_bound = lower_bounds [i];
138         /* 
139          * Following three lines almost taken from mono_object_new ():
140          * they need to be kept in sync.
141          */
142         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
143         if (!o)
144                 G_BREAKPOINT ();
145         o->klass = array_class;
146
147         array = (MonoArray*)o;
148
149         array->bounds = bounds;
150         return array;
151 }
152
153 /*
154  * mono_array_new:
155  * @image: image where the object is being referenced
156  * @eclass: element class
157  * @n: number of array elements
158  *
159  * This routine creates a new szarray with @n elements of type @token
160  */
161 MonoArray *
162 mono_array_new (MonoClass *eclass, guint32 n)
163 {
164         MonoClass *ac;
165
166         ac = mono_array_class_get (eclass, 1);
167         g_assert (ac != NULL);
168
169         return mono_array_new_full (ac, &n, NULL);
170 }
171
172 /**
173  * mono_string_new_utf16:
174  * @text: a pointer to an utf16 string
175  * @len: the length of the string
176  *
177  * Returns: A newly created string object which contains @text.
178  */
179 MonoString *
180 mono_string_new_utf16 (const guint16 *text, gint32 len)
181 {
182         MonoString *s;
183         MonoArray *ca;
184
185         s = (MonoString*)mono_object_new (mono_defaults.string_class);
186         g_assert (s != NULL);
187
188         ca = (MonoArray *)mono_array_new (mono_defaults.string_class, len);
189         g_assert (ca != NULL);
190         
191         s->c_str = ca;
192         s->length = len;
193
194         memcpy (ca->vector, text, len * 2);
195
196         return s;
197 }
198
199 /**
200  * mono_string_new:
201  * @text: a pointer to an utf8 string
202  *
203  * Returns: A newly created string object which contains @text.
204  */
205 MonoString*
206 mono_string_new (const char *text)
207 {
208         MonoString *o;
209         guint16 *ut;
210         int i, l;
211
212         /* fixme: use some kind of unicode library here */
213
214         l = strlen (text);
215         ut = g_malloc (l*2);
216
217         for (i = 0; i < l; i++)
218                 ut [i] = text[i];
219         
220         o = mono_string_new_utf16 (ut, l);
221
222         g_free (ut);
223
224         return o;
225 }
226
227 /**
228  * mono_value_box:
229  * @class: the class of the value
230  * @value: a pointer to the unboxed data
231  *
232  * Returns: A newly created object which contains @value.
233  */
234 MonoObject *
235 mono_value_box (MonoClass *class, gpointer value)
236 {
237         MonoObject *res;
238         int size;
239
240         g_assert (class->valuetype);
241
242         size = mono_class_instance_size (class);
243         res = mono_object_allocate (size);
244         res->klass = class;
245
246         size = size - sizeof (MonoObject);
247
248         memcpy ((char *)res + sizeof (MonoObject), value, size);
249
250         return res;
251 }
252
253 /**
254  * mono_object_isinst:
255  * @obj: an object
256  * @klass: a pointer to a class 
257  *
258  * Returns: #TRUE if @obj is derived from @klass
259  */
260 gboolean
261 mono_object_isinst (MonoObject *obj, MonoClass *klass)
262 {
263         MonoClass *oklass = obj->klass;
264
265         while (oklass) {
266                 if (oklass == klass)
267                         return TRUE;
268                 oklass = oklass->parent;
269         }
270         return FALSE;
271 }
272
273 static GHashTable *ldstr_table = NULL;
274
275 static int
276 ldstr_hash (const char* str)
277 {
278         guint len, h;
279         const char *end;
280         len = mono_metadata_decode_blob_size (str, &str);
281         end = str + len;
282         h = *str;
283         /*
284          * FIXME: The distribution may not be so nice with lots of
285          * null chars in the string.
286          */
287         for (str += 1; str < end; str++)
288                 h = (h << 5) - h + *str;
289         return h;
290 }
291
292 static gboolean
293 ldstr_equal (const char *str1, const char *str2) {
294         int len;
295         if ((len=mono_metadata_decode_blob_size (str1, &str1)) !=
296                                 mono_metadata_decode_blob_size (str2, &str2))
297                 return 0;
298         return memcmp (str1, str2, len) == 0;
299 }
300
301 typedef struct {
302         MonoString *obj;
303         MonoString *found;
304 } InternCheck;
305
306 static void
307 check_interned (gpointer key, MonoString *value, InternCheck *check)
308 {
309         if (value == check->obj)
310                 check->found = value;
311 }
312
313 MonoString*
314 mono_string_is_interned (MonoString *o)
315 {
316         InternCheck check;
317         check.obj = o;
318         check.found = NULL;
319         /*
320          * Yes, this is slow. Our System.String implementation needs to be redone.
321          * And GLib needs foreach() methods that can be stopped halfway.
322          */
323         g_hash_table_foreach (ldstr_table, (GHFunc)check_interned, &check);
324         return check.found;
325 }
326
327 MonoString*
328 mono_string_intern (MonoString *str)
329 {
330         MonoString *res;
331         char *ins = g_malloc (4 + str->length * 2);
332         char *p;
333         
334         /* Encode the length */
335         p = ins;
336         mono_metadata_encode_value (str->length, p, &p);
337         memcpy (p, str->c_str->vector, str->length * 2);
338         
339         if ((res = g_hash_table_lookup (ldstr_table, str))) {
340                 g_free (ins);
341                 return res;
342         }
343         g_hash_table_insert (ldstr_table, ins, str);
344         return str;
345 }
346
347 MonoString*
348 mono_ldstr (MonoImage *image, guint32 index)
349 {
350         const char *str, *sig;
351         MonoString *o;
352         size_t len2;
353         
354         if (!ldstr_table)
355                 ldstr_table = g_hash_table_new ((GHashFunc)ldstr_hash, (GCompareFunc)ldstr_equal);
356         
357         sig = str = mono_metadata_user_string (image, index);
358         
359         if ((o = g_hash_table_lookup (ldstr_table, str)))
360                 return o;
361         
362         len2 = mono_metadata_decode_blob_size (str, &str);
363 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
364 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
365         {
366                 gint i;
367                 guint16 *s;
368
369                 /* FIXME: it will be better to just add WRITE and after get it to previous state */
370                 mprotect ((void *) ((int) str & ~(PAGESIZE - 1)), len2 + ((int) str & (PAGESIZE - 1)),
371                                     PROT_READ | PROT_WRITE | PROT_EXEC);
372                 len2 >>= 1;
373                 for (i = 0, s = (guint16 *) str; i < len2; i++, s++) {
374                         *s = ((*s & 0xff) << 8) | (*s >> 8);
375                 }
376         }
377 #undef SWAP16
378 #else
379                 len2 >>= 1;
380 #endif
381
382         o = mono_string_new_utf16 ((guint16*)str, len2);
383         g_hash_table_insert (ldstr_table, (gpointer)sig, o);
384
385         return o;
386 }
387
388 char *
389 mono_string_to_utf8 (MonoString *s)
390 {
391         char *as, *vector;
392         int i;
393
394         g_assert (s != NULL);
395
396         if (!s->length || !s->c_str)
397                 return g_strdup ("");
398
399         vector = (char*)s->c_str->vector;
400
401         g_assert (vector != NULL);
402
403         as = g_malloc (s->length + 1);
404
405         /* fixme: replace with a real unicode/ansi conversion */
406         for (i = 0; i < s->length; i++) {
407                 as [i] = vector [i*2];
408         }
409
410         as [i] = '\0';
411
412         return as;
413 }
414
415 static void
416 default_ex_handler (MonoException *ex)
417 {
418         MonoObject *o = (MonoObject*)ex;
419         g_error ("Exception %s.%s raised in C code", o->klass->name_space, o->klass->name);
420 }
421
422 static MonoExceptionFunc ex_handler = default_ex_handler;
423
424 void
425 mono_install_handler        (MonoExceptionFunc func)
426 {
427         ex_handler = func? func: default_ex_handler;
428 }
429
430 void
431 mono_raise_exception (MonoException *ex) 
432 {
433         ex_handler (ex);
434 }
435