object layout change
[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 = g_malloc (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.string_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 /**
255  * mono_string_new:
256  * @text: a pointer to an utf8 string
257  *
258  * Returns: A newly created string object which contains @text.
259  */
260 MonoString*
261 mono_string_new (MonoDomain *domain, const char *text)
262 {
263         GError *error = NULL;
264         MonoString *o = NULL;
265         guint16 *ut;
266         glong items_written;
267         int l;
268
269         l = strlen (text);
270         
271         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
272
273         if (!error)
274                 o = mono_string_new_utf16 (domain, ut, items_written);
275         else 
276                 g_error_free (error);
277
278         g_free (ut);
279
280         return o;
281 }
282
283 /**
284  * mono_value_box:
285  * @class: the class of the value
286  * @value: a pointer to the unboxed data
287  *
288  * Returns: A newly created object which contains @value.
289  */
290 MonoObject *
291 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
292 {
293         MonoObject *res;
294         int size;
295
296         g_assert (class->valuetype);
297
298         size = mono_class_instance_size (class);
299         res = mono_object_allocate (size);
300         res->vtable = mono_class_vtable (domain, class);
301
302         size = size - sizeof (MonoObject);
303
304         memcpy ((char *)res + sizeof (MonoObject), value, size);
305
306         return res;
307 }
308
309 /**
310  * mono_object_isinst:
311  * @obj: an object
312  * @klass: a pointer to a class 
313  *
314  * Returns: @obj if @obj is derived from @klass
315  */
316 MonoObject *
317 mono_object_isinst (MonoObject *obj, MonoClass *klass)
318 {
319         MonoVTable *vt;
320         MonoClass *oklass;
321
322         if (!obj)
323                 return NULL;
324
325         vt = obj->vtable;
326         oklass = vt->klass;
327
328         if (!klass->inited)
329                 mono_class_init (klass);
330
331         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
332                 if ((klass->interface_id <= oklass->max_interface_id) &&
333                     vt->interface_offsets [klass->interface_id])
334                         return obj;
335         } else {
336                 if ((oklass->baseval - klass->baseval) <= klass->diffval)
337                         return obj;
338         }
339
340         return NULL;
341 }
342
343
344 typedef struct {
345         MonoString *obj;
346         MonoString *found;
347 } InternCheck;
348
349 static void
350 check_interned (gpointer key, MonoString *value, InternCheck *check)
351 {
352         if (value == check->obj)
353                 check->found = value;
354 }
355
356 MonoString*
357 mono_string_is_interned (MonoString *o)
358 {
359         InternCheck check;
360         check.obj = o;
361         check.found = NULL;
362
363         /*
364          * Yes, this is slow. Our System.String implementation needs to be redone.
365          * And GLib needs foreach() methods that can be stopped halfway.
366          */
367         g_hash_table_foreach (((MonoObject *)o)->vtable->domain->ldstr_table, (GHFunc)check_interned, &check);
368         return check.found;
369 }
370
371 MonoString*
372 mono_string_intern (MonoString *str)
373 {
374         GHashTable *ldstr_table;
375         MonoString *res;
376         char *ins = g_malloc (4 + str->length * 2);
377         char *p;
378         
379         /* Encode the length */
380         p = ins;
381         mono_metadata_encode_value (str->length, p, &p);
382         memcpy (p, str->c_str->vector, str->length * 2);
383         ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
384         if ((res = g_hash_table_lookup (ldstr_table, str))) {
385                 g_free (ins);
386                 return res;
387         }
388         g_hash_table_insert (ldstr_table, ins, str);
389         return str;
390 }
391
392 MonoString*
393 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 index)
394 {
395         const char *str, *sig;
396         MonoString *o;
397         size_t len2;
398                 
399         sig = str = mono_metadata_user_string (image, index);
400         
401         if ((o = g_hash_table_lookup (domain->ldstr_table, str)))
402                 return o;
403         
404         len2 = mono_metadata_decode_blob_size (str, &str);
405 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
406 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
407         {
408                 gint i;
409                 guint16 *s;
410
411                 /* FIXME: it will be better to just add WRITE and after get it to previous state */
412                 mprotect ((void *) ((int) str & ~(PAGESIZE - 1)), len2 + ((int) str & (PAGESIZE - 1)),
413                                     PROT_READ | PROT_WRITE | PROT_EXEC);
414                 len2 >>= 1;
415                 /* printf ("swap %p\n", str); */
416                 for (i = 0, s = (guint16 *) str; i < len2; i++, s++) {
417                         *s = ((*s & 0xff) << 8) | (*s >> 8);
418                 }
419         }
420 #undef SWAP16
421 #else
422                 len2 >>= 1;
423 #endif
424
425         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
426         g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
427
428         return o;
429 }
430
431 char *
432 mono_string_to_utf8 (MonoString *s)
433 {
434         char *as, *vector;
435         GError *error = NULL;
436
437         g_assert (s != NULL);
438
439         if (!s->length || !s->c_str)
440                 return g_strdup ("");
441
442         vector = (char*)s->c_str->vector;
443
444         g_assert (vector != NULL);
445
446         as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
447
448         g_assert (!error);
449
450         return as;
451 }
452
453 char *
454 mono_string_to_utf16 (MonoString *s)
455 {
456         char *as;
457
458         g_assert (s != NULL);
459
460         as = g_malloc ((s->length * 2) + 2);
461         as [(s->length * 2)] = '\0';
462         as [(s->length * 2) + 1] = '\0';
463
464         if (!s->length || !s->c_str) {
465                 return (as);
466         }
467         
468         memcpy (as, mono_string_chars(s), s->length * 2);
469         
470         return (as);
471 }
472
473 static void
474 default_ex_handler (MonoException *ex)
475 {
476         MonoObject *o = (MonoObject*)ex;
477         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
478 }
479
480 static MonoExceptionFunc ex_handler = default_ex_handler;
481
482 void
483 mono_install_handler        (MonoExceptionFunc func)
484 {
485         ex_handler = func? func: default_ex_handler;
486 }
487
488 void
489 mono_raise_exception (MonoException *ex) 
490 {
491         ex_handler (ex);
492 }
493