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