2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
7 * (C) 2001 Ximian, Inc.
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
20 #include <limits.h> /* for PAGESIZE */
27 default_runtime_object_init (MonoObject *o)
32 MonoRuntimeObjectInit mono_runtime_object_init = default_runtime_object_init;
33 MonoRuntimeExecMain mono_runtime_exec_main = NULL;
36 mono_install_runtime_object_init (MonoRuntimeObjectInit func)
38 mono_runtime_object_init = func? func: default_runtime_object_init;
42 mono_install_runtime_exec_main (MonoRuntimeExecMain func)
44 mono_runtime_exec_main = func;
48 * mono_object_allocate:
49 * @size: number of bytes to allocate
51 * This is a very simplistic routine until we have our GC-aware
54 * Returns: an allocated object of size @size, or NULL on failure.
57 mono_object_allocate (size_t size)
59 void *o = calloc (1, size);
67 * Frees the memory used by the object. Debugging purposes
68 * only, as we will have our GC system.
71 mono_object_free (MonoObject *o)
73 MonoClass *c = o->vtable->klass;
75 memset (o, 0, c->instance_size);
81 * @klass: the class of the object that we want to create
83 * Returns: A newly created object whose definition is
84 * looked up using @klass
87 mono_object_new (MonoDomain *domain, MonoClass *klass)
92 mono_class_init (klass);
94 o = mono_object_allocate (klass->instance_size);
95 o->vtable = mono_class_vtable (domain, klass);
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
105 * Returns: A newly created object whose definition is
106 * looked up using @token in the @image image
109 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
113 class = mono_class_get (image, token);
115 return mono_object_new (domain, class);
121 * @obj: the object to clone
123 * Returns: A newly created object who is a shallow copy of @obj
126 mono_object_clone (MonoObject *obj)
131 size = obj->vtable->klass->instance_size;
132 o = mono_object_allocate (size);
134 memcpy (o, obj, size);
141 * @array: the array to clone
143 * Returns: A newly created array who is a shallow copy of @array
146 mono_array_clone (MonoArray *array)
151 MonoClass *klass = array->obj.vtable->klass;
153 sizes = alloca (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;
160 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
161 klass, sizes, sizes + klass->rank);
162 memcpy (o, array, sizeof(MonoArray) + size);
168 mono_array_new_full (MonoDomain *domain, MonoClass *array_class,
169 guint32 *lengths, guint32 *lower_bounds)
174 MonoArrayBounds *bounds;
177 if (!array_class->inited)
178 mono_class_init (array_class);
180 byte_len = mono_array_element_size (array_class);
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];
189 for (i = 0; i < array_class->rank; ++i)
190 bounds [i].lower_bound = lower_bounds [i];
192 * Following three lines almost taken from mono_object_new ():
193 * they need to be kept in sync.
195 o = mono_object_allocate (sizeof (MonoArray) + byte_len);
198 o->vtable = mono_class_vtable (domain, array_class);
200 array = (MonoArray*)o;
202 array->bounds = bounds;
203 array->max_length = bounds [0].length;
210 * @image: image where the object is being referenced
211 * @eclass: element class
212 * @n: number of array elements
214 * This routine creates a new szarray with @n elements of type @token
217 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
221 ac = mono_array_class_get (eclass, 1);
222 g_assert (ac != NULL);
224 return mono_array_new_full (domain, ac, &n, NULL);
228 * mono_string_new_utf16:
229 * @text: a pointer to an utf16 string
230 * @len: the length of the string
232 * Returns: A newly created string object which contains @text.
235 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
240 s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
241 g_assert (s != NULL);
243 ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
244 g_assert (ca != NULL);
249 memcpy (ca->vector, text, len * 2);
256 (MonoDomain *domain, const char *text, guint length)
258 GError *error = NULL;
259 MonoString *o = NULL;
264 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
267 o = mono_string_new_utf16 (domain, ut, items_written);
269 g_error_free (error);
278 * @text: a pointer to an utf8 string
280 * Returns: A newly created string object which contains @text.
283 mono_string_new (MonoDomain *domain, const char *text)
285 GError *error = NULL;
286 MonoString *o = NULL;
293 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
296 o = mono_string_new_utf16 (domain, ut, items_written);
298 g_error_free (error);
307 * @class: the class of the value
308 * @value: a pointer to the unboxed data
310 * Returns: A newly created object which contains @value.
313 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
318 g_assert (class->valuetype);
320 size = mono_class_instance_size (class);
321 res = mono_object_allocate (size);
322 res->vtable = mono_class_vtable (domain, class);
324 size = size - sizeof (MonoObject);
326 memcpy ((char *)res + sizeof (MonoObject), value, size);
332 * mono_object_isinst:
334 * @klass: a pointer to a class
336 * Returns: @obj if @obj is derived from @klass
339 mono_object_isinst (MonoObject *obj, MonoClass *klass)
351 mono_class_init (klass);
353 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
354 if ((klass->interface_id <= oklass->max_interface_id) &&
355 vt->interface_offsets [klass->interface_id])
358 if ((oklass->baseval - klass->baseval) <= klass->diffval)
372 check_interned (gpointer key, MonoString *value, InternCheck *check)
374 if (value == check->obj)
375 check->found = value;
379 mono_string_is_interned (MonoString *o)
386 * Yes, this is slow. Our System.String implementation needs to be redone.
387 * And GLib needs foreach() methods that can be stopped halfway.
389 g_hash_table_foreach (((MonoObject *)o)->vtable->domain->ldstr_table, (GHFunc)check_interned, &check);
394 mono_string_intern (MonoString *str)
396 GHashTable *ldstr_table;
398 char *ins = g_malloc (4 + str->length * 2);
402 /* Encode the length */
404 mono_metadata_encode_value (2 * str->length, p, &p);
407 mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
408 bloblen = (p - ins) + 2 * str->length;
409 memcpy (p, str->c_str->vector, str->length * 2);
410 ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
411 if ((res = g_hash_table_lookup (ldstr_table, ins))) {
415 g_hash_table_insert (ldstr_table, ins, str);
420 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 index)
422 const char *str, *sig;
426 sig = str = mono_metadata_user_string (image, index);
427 len2 = mono_metadata_decode_blob_size (str, &str);
429 if ((o = g_hash_table_lookup (domain->ldstr_table, sig)))
432 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
433 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
437 /* FIXME: we need to find better way for swapping strings, i.e. swap all string after image load */
438 static GHashTable *converted_strings = NULL;
440 if (!converted_strings)
441 converted_strings = g_hash_table_new (g_str_hash, g_str_equal);
443 if (converted_strings && !g_hash_table_lookup (converted_strings, str)) {
444 /* FIXME: it will be better to just add WRITE and after get it to previous state */
445 mprotect ((void *) ((int) str & ~(PAGESIZE - 1)), len2 + ((int) str & (PAGESIZE - 1)),
446 PROT_READ | PROT_WRITE | PROT_EXEC);
448 /* printf ("swap %p\n", str); */
449 for (i = 0, s = (guint16 *) str; i < len2; i++, s++) {
450 *s = ((*s & 0xff) << 8) | (*s >> 8);
452 g_hash_table_insert (converted_strings, (gpointer) str, (gpointer) str);
461 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
462 g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
468 mono_string_to_utf8 (MonoString *s)
471 GError *error = NULL;
473 g_assert (s != NULL);
475 if (!s->length || !s->c_str)
476 return g_strdup ("");
478 vector = (char*)s->c_str->vector;
480 g_assert (vector != NULL);
482 as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
490 mono_string_to_utf16 (MonoString *s)
494 g_assert (s != NULL);
496 as = g_malloc ((s->length * 2) + 2);
497 as [(s->length * 2)] = '\0';
498 as [(s->length * 2) + 1] = '\0';
500 if (!s->length || !s->c_str) {
504 memcpy (as, mono_string_chars(s), s->length * 2);
510 default_ex_handler (MonoException *ex)
512 MonoObject *o = (MonoObject*)ex;
513 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
516 static MonoExceptionFunc ex_handler = default_ex_handler;
519 mono_install_handler (MonoExceptionFunc func)
521 ex_handler = func? func: default_ex_handler;
525 mono_raise_exception (MonoException *ex)