Fri Mar 29 16:09:54 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 <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_debug_malloc (size, "object", 1);
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 #if HAVE_BOEHM_GC
197         bounds = GC_debug_malloc (sizeof (MonoArrayBounds) * array_class->rank, "bounds", 0);
198 #else
199         bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
200 #endif
201         for (i = 0; i < array_class->rank; ++i) {
202                 bounds [i].length = lengths [i];
203                 byte_len *= lengths [i];
204         }
205
206         if (lower_bounds)
207                 for (i = 0; i < array_class->rank; ++i)
208                         bounds [i].lower_bound = lower_bounds [i];
209         /* 
210          * Following three lines almost taken from mono_object_new ():
211          * they need to be kept in sync.
212          */
213         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
214         if (!o)
215                 G_BREAKPOINT ();
216         o->vtable = mono_class_vtable (domain, array_class);
217
218         array = (MonoArray*)o;
219
220         array->bounds = bounds;
221         array->max_length = bounds [0].length;
222
223         return array;
224 }
225
226 /*
227  * mono_array_new:
228  * @image: image where the object is being referenced
229  * @eclass: element class
230  * @n: number of array elements
231  *
232  * This routine creates a new szarray with @n elements of type @token
233  */
234 MonoArray *
235 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
236 {
237         MonoClass *ac;
238
239         ac = mono_array_class_get (&eclass->byval_arg, 1);
240         g_assert (ac != NULL);
241
242         return mono_array_new_full (domain, ac, &n, NULL);
243 }
244
245 /**
246  * mono_string_new_utf16:
247  * @text: a pointer to an utf16 string
248  * @len: the length of the string
249  *
250  * Returns: A newly created string object which contains @text.
251  */
252 MonoString *
253 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
254 {
255         MonoString *s;
256         MonoArray *ca;
257
258         s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
259         g_assert (s != NULL);
260
261         ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
262         g_assert (ca != NULL);
263         
264         s->c_str = ca;
265         s->length = len;
266
267         memcpy (ca->vector, text, len * 2);
268
269         return s;
270 }
271
272 MonoString*
273 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
274 {
275         GError *error = NULL;
276         MonoString *o = NULL;
277         guint16 *ut;
278         glong items_written;
279
280         
281         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
282
283         if (!error)
284                 o = mono_string_new_utf16 (domain, ut, items_written);
285         else 
286                 g_error_free (error);
287
288         g_free (ut);
289
290         return o;
291 }
292
293 /**
294  * mono_string_new:
295  * @text: a pointer to an utf8 string
296  *
297  * Returns: A newly created string object which contains @text.
298  */
299 MonoString*
300 mono_string_new (MonoDomain *domain, const char *text)
301 {
302         GError *error = NULL;
303         MonoString *o = NULL;
304         guint16 *ut;
305         glong items_written;
306         int l;
307
308         l = strlen (text);
309         
310         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
311
312         if (!error)
313                 o = mono_string_new_utf16 (domain, ut, items_written);
314         else 
315                 g_error_free (error);
316
317         g_free (ut);
318
319         return o;
320 }
321
322 MonoString*
323 mono_string_new_wrapper (const char *text)
324 {
325         MonoDomain *domain = mono_domain_get ();
326
327         return mono_string_new (domain, text);
328 }
329
330 /**
331  * mono_value_box:
332  * @class: the class of the value
333  * @value: a pointer to the unboxed data
334  *
335  * Returns: A newly created object which contains @value.
336  */
337 MonoObject *
338 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
339 {
340         MonoObject *res;
341         int size;
342
343         g_assert (class->valuetype);
344
345         size = mono_class_instance_size (class);
346         res = mono_object_allocate (size);
347         res->vtable = mono_class_vtable (domain, class);
348
349         size = size - sizeof (MonoObject);
350
351         memcpy ((char *)res + sizeof (MonoObject), value, size);
352
353         return res;
354 }
355
356 /**
357  * mono_object_isinst:
358  * @obj: an object
359  * @klass: a pointer to a class 
360  *
361  * Returns: @obj if @obj is derived from @klass
362  */
363 MonoObject *
364 mono_object_isinst (MonoObject *obj, MonoClass *klass)
365 {
366         MonoVTable *vt;
367         MonoClass *oklass;
368
369         if (!obj)
370                 return NULL;
371
372         vt = obj->vtable;
373         oklass = vt->klass;
374
375         if (!klass->inited)
376                 mono_class_init (klass);
377
378         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
379                 if ((klass->interface_id <= oklass->max_interface_id) &&
380                     vt->interface_offsets [klass->interface_id])
381                         return obj;
382         } else {
383                 if (oklass == mono_defaults.transparent_proxy_class) {
384                         /* fixme: add check for IRemotingTypeInfo */
385                         MonoRealProxy *rp = ((MonoTransparentProxy *)obj)->rp;
386                         MonoType *type;
387                         type = ((MonoReflectionType *)rp->class_to_proxy)->type;
388                         oklass = mono_class_from_mono_type (type);
389                 }
390                 if (oklass->rank && oklass->rank == klass->rank) {
391                         if ((oklass->element_class->baseval - klass->element_class->baseval) <= 
392                             klass->element_class->diffval)
393                                 return obj;
394                 } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
395                         return obj;
396         }
397
398         return NULL;
399 }
400
401 static MonoString*
402 mono_string_is_interned_lookup (MonoString *str, int insert)
403 {
404         MonoGHashTable *ldstr_table;
405         MonoString *res;
406         char *ins = g_malloc (4 + str->length * 2);
407         char *p;
408         int bloblen;
409         
410         /* Encode the length */
411         p = ins;
412         mono_metadata_encode_value (2 * str->length, p, &p);
413         bloblen = p - ins;
414         p = ins;
415         mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
416         bloblen = (p - ins) + 2 * str->length;
417         /*
418          * ins is stored in the hash table as a key and needs to have the same
419          * representation as in the metadata: we swap the character bytes on big
420          * endian boxes.
421          */
422 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
423         {
424                 int i;
425                 char *p2 = mono_array_addr (str->c_str, char, 0);
426                 for (i = 0; i < str->length; ++i) {
427                         *p++ = p2 [1];
428                         *p++ = p2 [0];
429                         p2 += 2;
430                 }
431         }
432 #else
433         memcpy (p, str->c_str->vector, str->length * 2);
434 #endif
435         ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
436         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
437                 g_free (ins);
438                 return res;
439         }
440         if (insert) {
441                 mono_g_hash_table_insert (ldstr_table, ins, str);
442                 return str;
443         }
444         g_free (ins);
445         return NULL;
446 }
447
448 MonoString*
449 mono_string_is_interned (MonoString *o)
450 {
451         return mono_string_is_interned_lookup (o, FALSE);
452 }
453
454 MonoString*
455 mono_string_intern (MonoString *str)
456 {
457         return mono_string_is_interned_lookup (str, TRUE);
458 }
459
460 MonoString*
461 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 index)
462 {
463         const char *str, *sig;
464         MonoString *o;
465         size_t len2;
466                 
467         sig = str = mono_metadata_user_string (image, index);
468         
469         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig)))
470                 return o;
471         
472         len2 = mono_metadata_decode_blob_size (str, &str);
473         len2 >>= 1;
474
475         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
476 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
477         {
478                 int i;
479                 guint16 *p2 = (guint16*)mono_array_addr (o->c_str, guint16, 0);
480                 for (i = 0; i < len2; ++i) {
481                         *p2 = GUINT16_FROM_LE (*p2);
482                         ++p2;
483                 }
484         }
485 #endif
486         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
487
488         return o;
489 }
490
491 char *
492 mono_string_to_utf8 (MonoString *s)
493 {
494         char *as, *vector;
495         GError *error = NULL;
496
497         g_assert (s != NULL);
498
499         if (!s->length || !s->c_str)
500                 return g_strdup ("");
501
502         vector = (char*)s->c_str->vector;
503
504         g_assert (vector != NULL);
505
506         as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
507         if (error)
508                 g_warning (error->message);
509
510         return as;
511 }
512
513 gunichar2 *
514 mono_string_to_utf16 (MonoString *s)
515 {
516         char *as;
517
518         g_assert (s != NULL);
519
520         as = g_malloc ((s->length * 2) + 2);
521         as [(s->length * 2)] = '\0';
522         as [(s->length * 2) + 1] = '\0';
523
524         if (!s->length || !s->c_str) {
525                 return (gunichar2 *)(as);
526         }
527         
528         memcpy (as, mono_string_chars(s), s->length * 2);
529         
530         return (gunichar2 *)(as);
531 }
532
533 static void
534 default_ex_handler (MonoException *ex)
535 {
536         MonoObject *o = (MonoObject*)ex;
537         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
538 }
539
540 static MonoExceptionFunc ex_handler = default_ex_handler;
541
542 void
543 mono_install_handler        (MonoExceptionFunc func)
544 {
545         ex_handler = func? func: default_ex_handler;
546 }
547
548 void
549 mono_raise_exception (MonoException *ex) 
550 {
551         ex_handler (ex);
552 }
553
554 MonoWaitHandle *
555 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
556 {
557         MonoWaitHandle *res;
558
559         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
560
561         res->handle = handle;
562
563         return res;
564 }
565
566 MonoAsyncResult *
567 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
568 {
569         MonoAsyncResult *res;
570
571         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
572
573         res->data = data;
574         res->async_state = state;
575         res->handle = mono_wait_handle_new (domain, handle);
576         res->sync_completed = FALSE;
577         res->completed = FALSE;
578
579         return res;
580 }
581