2001-10-04 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 <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_new_object:
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_new_object (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_new_object_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_new_object_from_token  (MonoImage *image, guint32 token)
80 {
81         MonoClass *class;
82
83         class = mono_class_get (image, token);
84
85         return mono_new_object (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 /*
110  * mono_new_szarray:
111  * @image: image where the object is being referenced
112  * @eclass: element class
113  * @n: number of array elements
114  *
115  * This routine creates a new szarray with @n elements of type @token
116  */
117 MonoObject *
118 mono_new_szarray (MonoClass *eclass, guint32 n)
119 {
120         MonoClass *c;
121         MonoObject *o;
122         MonoArrayObject *ao;
123         MonoArrayClass *ac;
124
125         c = mono_array_class_get (eclass, 1);
126         g_assert (c != NULL);
127
128         o = mono_new_object (c);
129
130         ao = (MonoArrayObject *)o;
131         ac = (MonoArrayClass *)c;
132
133         ao->bounds = g_malloc0 (sizeof (MonoArrayBounds));
134         ao->bounds [0].length = n;
135         ao->bounds [0].lower_bound = 0;
136
137         ao->vector = g_malloc0 (n * mono_array_element_size (ac));
138
139         return o;
140 }
141
142 /**
143  * mono_new_utf16_string:
144  * @text: a pointer to an utf16 string
145  * @len: the length of the string
146  *
147  * Returns: A newly created string object which contains @text.
148  */
149 MonoObject *
150 mono_new_utf16_string (const char *text, gint32 len)
151 {
152         MonoObject *s;
153         MonoArrayObject *ca;
154
155         s = mono_new_object (mono_defaults.string_class);
156         g_assert (s != NULL);
157
158         ca = (MonoArrayObject *)mono_new_szarray (mono_defaults.string_class, len);
159         g_assert (ca != NULL);
160         
161         ((MonoStringObject *)s)->c_str = ca;
162         ((MonoStringObject *)s)->length = len;
163
164         memcpy (ca->vector, text, len * 2);
165
166         return s;
167 }
168
169 /**
170  * mono_new_string:
171  * @text: a pointer to an utf8 string
172  *
173  * Returns: A newly created string object which contains @text.
174  */
175 MonoObject *
176 mono_new_string (const char *text)
177 {
178         MonoObject *o;
179         guint16 *ut;
180         int i, l;
181
182         /* fixme: use some kind of unicode library here */
183
184         l = strlen (text);
185         ut = g_malloc (l*2);
186
187         for (i = 0; i < l; i++)
188                 ut [i] = text[i];
189         
190         o = mono_new_utf16_string ((char *)ut, l);
191
192         g_free (ut);
193
194         return o;
195 }
196
197 /**
198  * mono_value_box:
199  * @class: the class of the value
200  * @value: a pointer to the unboxed data
201  *
202  * Returns: A newly created object which contains @value.
203  */
204 MonoObject *
205 mono_value_box (MonoClass *class, gpointer value)
206 {
207         MonoObject *res;
208         int size;
209
210         g_assert (class->valuetype);
211
212         size = mono_class_instance_size (class);
213         res = mono_object_allocate (size);
214         res->klass = class;
215
216         size = size - sizeof (MonoObject);
217
218         memcpy ((char *)res + sizeof (MonoObject), value, size);
219
220         return res;
221 }
222
223 /**
224  * mono_object_isinst:
225  * @obj: an object
226  * @klass: a pointer to a class 
227  *
228  * Returns: #TRUE if @obj is derived from @klass
229  */
230 gboolean
231 mono_object_isinst (MonoObject *obj, MonoClass *klass)
232 {
233         MonoClass *oklass = obj->klass;
234
235         while (oklass) {
236                 if (oklass == klass)
237                         return TRUE;
238                 oklass = oklass->parent;
239         }
240         return FALSE;
241 }
242
243 static GHashTable *ldstr_table = NULL;
244
245 static int
246 ldstr_hash (const char* str)
247 {
248         guint len, h;
249         const char *end;
250         len = mono_metadata_decode_blob_size (str, &str);
251         end = str + len;
252         h = *str;
253         /*
254          * FIXME: The distribution may not be so nice with lots of
255          * null chars in the string.
256          */
257         for (str += 1; str < end; str++)
258                 h = (h << 5) - h + *str;
259         return h;
260 }
261
262 static gboolean
263 ldstr_equal (const char *str1, const char *str2) {
264         int len;
265         if ((len=mono_metadata_decode_blob_size (str1, &str1)) !=
266                                 mono_metadata_decode_blob_size (str2, &str2))
267                 return 0;
268         return memcmp (str1, str2, len) == 0;
269 }
270
271 typedef struct {
272         MonoObject *obj;
273         MonoObject *found;
274 } InternCheck;
275
276 static void
277 check_interned (gpointer key, MonoObject *value, InternCheck *check)
278 {
279         if (value == check->obj)
280                 check->found = value;
281 }
282
283 MonoObject*
284 mono_string_is_interned (MonoObject *o)
285 {
286         InternCheck check;
287         check.obj = o;
288         check.found = NULL;
289         /*
290          * Yes, this is slow. Our System.String implementation needs to be redone.
291          * And GLib needs foreach() methods that can be stopped halfway.
292          */
293         g_hash_table_foreach (ldstr_table, (GHFunc)check_interned, &check);
294         return check.found;
295 }
296
297 MonoObject*
298 mono_string_intern (MonoObject *o)
299 {
300         MonoObject *res;
301         MonoStringObject *str = (MonoStringObject*) o;
302         char *ins = g_malloc (4 + str->length * 2);
303         char *p;
304         
305         /* Encode the length */
306         p = ins;
307         mono_metadata_encode_value (str->length, p, &p);
308         memcpy (p, str->c_str->vector, str->length * 2);
309         
310         if ((res = g_hash_table_lookup (ldstr_table, str))) {
311                 g_free (ins);
312                 return res;
313         }
314         g_hash_table_insert (ldstr_table, ins, str);
315         return (MonoObject*)str;
316 }
317
318 MonoObject*
319 mono_ldstr (MonoImage *image, guint32 index)
320 {
321         const char *str, *sig;
322         MonoObject *o;
323         guint len;
324         
325         if (!ldstr_table)
326                 ldstr_table = g_hash_table_new ((GHashFunc)ldstr_hash, (GCompareFunc)ldstr_equal);
327         
328         sig = str = mono_metadata_user_string (image, index);
329         
330         if ((o = g_hash_table_lookup (ldstr_table, str)))
331                 return o;
332         
333         len = mono_metadata_decode_blob_size (str, &str);
334         o = mono_new_utf16_string (str, len >> 1);
335         g_hash_table_insert (ldstr_table, sig, o);
336
337         return o;
338 }
339
340 char *
341 mono_string_to_utf8 (MonoObject *o)
342 {
343         MonoStringObject *s = (MonoStringObject *)o;
344         char *as, *vector;
345         int i;
346
347         g_assert (o != NULL);
348
349         if (!s->length)
350                 return g_strdup ("");
351
352         vector = s->c_str->vector;
353
354         g_assert (vector != NULL);
355
356         as = g_malloc (s->length + 1);
357
358         /* fixme: replace with a real unicode/ansi conversion */
359         for (i = 0; i < s->length; i++) {
360                 as [i] = vector [i*2];
361         }
362
363         as [i] = '\0';
364
365         return as;
366 }
367