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