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