Fri Mar 29 18:09:08 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / object.c
index e49cf7b4a9918c32fb311acfa0a5abcfb2543c8c..365f1a2170003c372584f2a6bc512772ff5613e6 100644 (file)
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/loader.h>
 #include <mono/metadata/object.h>
-#if G_BYTE_ORDER != G_LITTLE_ENDIAN
-#include <sys/mman.h>
-#include <limits.h>    /* for PAGESIZE */
-#ifndef PAGESIZE
-#define PAGESIZE 4096
-#endif
+#include <mono/metadata/appdomain.h>
+#if HAVE_BOEHM_GC
+#include <gc/gc.h>
 #endif
 
 static void
@@ -55,7 +52,11 @@ mono_install_runtime_exec_main (MonoRuntimeExecMain func)
 void *
 mono_object_allocate (size_t size)
 {
+#if HAVE_BOEHM_GC
+       void *o = GC_debug_malloc (size, "object", 1);
+#else
        void *o = calloc (1, size);
+#endif
 
        return o;
 }
@@ -69,10 +70,14 @@ mono_object_allocate (size_t size)
 void
 mono_object_free (MonoObject *o)
 {
-       MonoClass *c = o->klass;
+#if HAVE_BOEHM_GC
+       g_error ("mono_object_free called with boehm gc.");
+#else
+       MonoClass *c = o->vtable->klass;
        
        memset (o, 0, c->instance_size);
        free (o);
+#endif
 }
 
 /**
@@ -83,15 +88,25 @@ mono_object_free (MonoObject *o)
  * looked up using @klass
  */
 MonoObject *
-mono_object_new (MonoClass *klass)
+mono_object_new (MonoDomain *domain, MonoClass *klass)
 {
+       static guint32 uoid = 0;
        MonoObject *o;
 
        if (!klass->inited)
                mono_class_init (klass);
 
-       o = mono_object_allocate (klass->instance_size);
-       o->klass = klass;
+
+       if (klass->ghcimpl) {
+               o = mono_object_allocate (klass->instance_size);
+               o->vtable = mono_class_vtable (domain, klass);
+       } else {
+               guint32 *t;
+               t = mono_object_allocate (klass->instance_size + 4);
+               *t = ++uoid;
+               o = (MonoObject *)(++t);
+               o->vtable = mono_class_vtable (domain, klass);
+       }
 
        return o;
 }
@@ -105,13 +120,13 @@ mono_object_new (MonoClass *klass)
  * looked up using @token in the @image image
  */
 MonoObject *
-mono_object_new_from_token  (MonoImage *image, guint32 token)
+mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
 {
        MonoClass *class;
 
        class = mono_class_get (image, token);
 
-       return mono_object_new (class);
+       return mono_object_new (domain, class);
 }
 
 
@@ -126,18 +141,46 @@ mono_object_clone (MonoObject *obj)
 {
        MonoObject *o;
        int size;
-       
-       size = obj->klass->instance_size;
+
+       size = obj->vtable->klass->instance_size;
        o = mono_object_allocate (size);
-       /* FIXME: handle arrays... */
-       
+
        memcpy (o, obj, size);
 
        return o;
 }
 
+/**
+ * mono_array_clone:
+ * @array: the array to clone
+ *
+ * Returns: A newly created array who is a shallow copy of @array
+ */
+MonoArray*
+mono_array_clone (MonoArray *array)
+{
+       MonoArray *o;
+       int size, i;
+       guint32 *sizes;
+       MonoClass *klass = array->obj.vtable->klass;
+       
+       sizes = alloca (klass->rank * sizeof(guint32) * 2);
+       size = mono_array_element_size (klass);
+       for (i = 0; i < klass->rank; ++i) {
+               sizes [i] = array->bounds [i].length;
+               size *= array->bounds [i].length;
+               sizes [i + klass->rank] = array->bounds [i].lower_bound;
+       }
+       o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
+                                klass, sizes, sizes + klass->rank);
+       memcpy (o, array, sizeof(MonoArray) + size);
+
+       return o;
+}
+
 MonoArray*
-mono_array_new_full (MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
+mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
+                    guint32 *lengths, guint32 *lower_bounds)
 {
        guint32 byte_len;
        MonoObject *o;
@@ -147,9 +190,14 @@ mono_array_new_full (MonoClass *array_class, guint32 *lengths, guint32 *lower_bo
 
        if (!array_class->inited)
                mono_class_init (array_class);
+
        byte_len = mono_array_element_size (array_class);
 
+#if HAVE_BOEHM_GC
+       bounds = GC_debug_malloc (sizeof (MonoArrayBounds) * array_class->rank, "bounds", 0);
+#else
        bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
+#endif
        for (i = 0; i < array_class->rank; ++i) {
                bounds [i].length = lengths [i];
                byte_len *= lengths [i];
@@ -165,7 +213,7 @@ mono_array_new_full (MonoClass *array_class, guint32 *lengths, guint32 *lower_bo
        o = mono_object_allocate (sizeof (MonoArray) + byte_len);
        if (!o)
                G_BREAKPOINT ();
-       o->klass = array_class;
+       o->vtable = mono_class_vtable (domain, array_class);
 
        array = (MonoArray*)o;
 
@@ -184,14 +232,14 @@ mono_array_new_full (MonoClass *array_class, guint32 *lengths, guint32 *lower_bo
  * This routine creates a new szarray with @n elements of type @token
  */
 MonoArray *
-mono_array_new (MonoClass *eclass, guint32 n)
+mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
 {
        MonoClass *ac;
 
-       ac = mono_array_class_get (eclass, 1);
+       ac = mono_array_class_get (&eclass->byval_arg, 1);
        g_assert (ac != NULL);
 
-       return mono_array_new_full (ac, &n, NULL);
+       return mono_array_new_full (domain, ac, &n, NULL);
 }
 
 /**
@@ -202,15 +250,15 @@ mono_array_new (MonoClass *eclass, guint32 n)
  * Returns: A newly created string object which contains @text.
  */
 MonoString *
-mono_string_new_utf16 (const guint16 *text, gint32 len)
+mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
 {
        MonoString *s;
        MonoArray *ca;
 
-       s = (MonoString*)mono_object_new (mono_defaults.string_class);
+       s = (MonoString*)mono_object_new (domain, mono_defaults.string_class);
        g_assert (s != NULL);
 
-       ca = (MonoArray *)mono_array_new (mono_defaults.string_class, len);
+       ca = (MonoArray *)mono_array_new (domain, mono_defaults.char_class, len);
        g_assert (ca != NULL);
        
        s->c_str = ca;
@@ -221,6 +269,27 @@ mono_string_new_utf16 (const guint16 *text, gint32 len)
        return s;
 }
 
+MonoString*
+mono_string_new_len (MonoDomain *domain, const char *text, guint length)
+{
+       GError *error = NULL;
+       MonoString *o = NULL;
+       guint16 *ut;
+       glong items_written;
+
+       
+       ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
+
+       if (!error)
+               o = mono_string_new_utf16 (domain, ut, items_written);
+       else 
+               g_error_free (error);
+
+       g_free (ut);
+
+       return o;
+}
+
 /**
  * mono_string_new:
  * @text: a pointer to an utf8 string
@@ -228,7 +297,7 @@ mono_string_new_utf16 (const guint16 *text, gint32 len)
  * Returns: A newly created string object which contains @text.
  */
 MonoString*
-mono_string_new (const char *text)
+mono_string_new (MonoDomain *domain, const char *text)
 {
        GError *error = NULL;
        MonoString *o = NULL;
@@ -241,7 +310,7 @@ mono_string_new (const char *text)
        ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
 
        if (!error)
-               o = mono_string_new_utf16 (ut, items_written);
+               o = mono_string_new_utf16 (domain, ut, items_written);
        else 
                g_error_free (error);
 
@@ -250,6 +319,14 @@ mono_string_new (const char *text)
        return o;
 }
 
+MonoString*
+mono_string_new_wrapper (const char *text)
+{
+       MonoDomain *domain = mono_domain_get ();
+
+       return mono_string_new (domain, text);
+}
+
 /**
  * mono_value_box:
  * @class: the class of the value
@@ -258,7 +335,7 @@ mono_string_new (const char *text)
  * Returns: A newly created object which contains @value.
  */
 MonoObject *
-mono_value_box (MonoClass *class, gpointer value)
+mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
 {
        MonoObject *res;
        int size;
@@ -267,7 +344,7 @@ mono_value_box (MonoClass *class, gpointer value)
 
        size = mono_class_instance_size (class);
        res = mono_object_allocate (size);
-       res->klass = class;
+       res->vtable = mono_class_vtable (domain, class);
 
        size = size - sizeof (MonoObject);
 
@@ -286,140 +363,127 @@ mono_value_box (MonoClass *class, gpointer value)
 MonoObject *
 mono_object_isinst (MonoObject *obj, MonoClass *klass)
 {
+       MonoVTable *vt;
        MonoClass *oklass;
 
        if (!obj)
                return NULL;
 
-       oklass = obj->klass;
+       vt = obj->vtable;
+       oklass = vt->klass;
 
        if (!klass->inited)
                mono_class_init (klass);
 
        if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
                if ((klass->interface_id <= oklass->max_interface_id) &&
-                   oklass->interface_offsets [klass->interface_id])
+                   vt->interface_offsets [klass->interface_id])
                        return obj;
        } else {
-               if ((oklass->baseval - klass->baseval) <= klass->diffval)
+               if (oklass == mono_defaults.transparent_proxy_class) {
+                       /* fixme: add check for IRemotingTypeInfo */
+                       MonoRealProxy *rp = ((MonoTransparentProxy *)obj)->rp;
+                       MonoType *type;
+                       type = ((MonoReflectionType *)rp->class_to_proxy)->type;
+                       oklass = mono_class_from_mono_type (type);
+               }
+               if (oklass->rank && oklass->rank == klass->rank) {
+                       if ((oklass->element_class->baseval - klass->element_class->baseval) <= 
+                           klass->element_class->diffval)
+                               return obj;
+               } else if ((oklass->baseval - klass->baseval) <= klass->diffval)
                        return obj;
        }
 
        return NULL;
 }
 
-static GHashTable *ldstr_table = NULL;
-
-static int
-ldstr_hash (const char* str)
+static MonoString*
+mono_string_is_interned_lookup (MonoString *str, int insert)
 {
-       guint len, h;
-       const char *end;
-       len = mono_metadata_decode_blob_size (str, &str);
-       end = str + len;
-       h = *str;
+       MonoGHashTable *ldstr_table;
+       MonoString *res;
+       char *ins = g_malloc (4 + str->length * 2);
+       char *p;
+       int bloblen;
+       
+       /* Encode the length */
+       p = ins;
+       mono_metadata_encode_value (2 * str->length, p, &p);
+       bloblen = p - ins;
+       p = ins;
+       mono_metadata_encode_value (bloblen + 2 * str->length, p, &p);
+       bloblen = (p - ins) + 2 * str->length;
        /*
-        * FIXME: The distribution may not be so nice with lots of
-        * null chars in the string.
+        * ins is stored in the hash table as a key and needs to have the same
+        * representation as in the metadata: we swap the character bytes on big
+        * endian boxes.
         */
-       for (str += 1; str < end; str++)
-               h = (h << 5) - h + *str;
-       return h;
-}
-
-static gboolean
-ldstr_equal (const char *str1, const char *str2) {
-       int len;
-       if ((len=mono_metadata_decode_blob_size (str1, &str1)) !=
-                               mono_metadata_decode_blob_size (str2, &str2))
-               return 0;
-       return memcmp (str1, str2, len) == 0;
-}
-
-typedef struct {
-       MonoString *obj;
-       MonoString *found;
-} InternCheck;
-
-static void
-check_interned (gpointer key, MonoString *value, InternCheck *check)
-{
-       if (value == check->obj)
-               check->found = value;
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+       {
+               int i;
+               char *p2 = mono_array_addr (str->c_str, char, 0);
+               for (i = 0; i < str->length; ++i) {
+                       *p++ = p2 [1];
+                       *p++ = p2 [0];
+                       p2 += 2;
+               }
+       }
+#else
+       memcpy (p, str->c_str->vector, str->length * 2);
+#endif
+       ldstr_table = ((MonoObject *)str)->vtable->domain->ldstr_table;
+       if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
+               g_free (ins);
+               return res;
+       }
+       if (insert) {
+               mono_g_hash_table_insert (ldstr_table, ins, str);
+               return str;
+       }
+       g_free (ins);
+       return NULL;
 }
 
 MonoString*
 mono_string_is_interned (MonoString *o)
 {
-       InternCheck check;
-       check.obj = o;
-       check.found = NULL;
-       /*
-        * Yes, this is slow. Our System.String implementation needs to be redone.
-        * And GLib needs foreach() methods that can be stopped halfway.
-        */
-       g_hash_table_foreach (ldstr_table, (GHFunc)check_interned, &check);
-       return check.found;
+       return mono_string_is_interned_lookup (o, FALSE);
 }
 
 MonoString*
 mono_string_intern (MonoString *str)
 {
-       MonoString *res;
-       char *ins = g_malloc (4 + str->length * 2);
-       char *p;
-       
-       /* Encode the length */
-       p = ins;
-       mono_metadata_encode_value (str->length, p, &p);
-       memcpy (p, str->c_str->vector, str->length * 2);
-       
-       if ((res = g_hash_table_lookup (ldstr_table, str))) {
-               g_free (ins);
-               return res;
-       }
-       g_hash_table_insert (ldstr_table, ins, str);
-       return str;
+       return mono_string_is_interned_lookup (str, TRUE);
 }
 
 MonoString*
-mono_ldstr (MonoImage *image, guint32 index)
+mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 index)
 {
        const char *str, *sig;
        MonoString *o;
        size_t len2;
-       
-       if (!ldstr_table)
-               ldstr_table = g_hash_table_new ((GHashFunc)ldstr_hash, (GCompareFunc)ldstr_equal);
-       
+               
        sig = str = mono_metadata_user_string (image, index);
        
-       if ((o = g_hash_table_lookup (ldstr_table, str)))
+       if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig)))
                return o;
        
        len2 = mono_metadata_decode_blob_size (str, &str);
+       len2 >>= 1;
+
+       o = mono_string_new_utf16 (domain, (guint16*)str, len2);
 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
-#define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
        {
-               gint i;
-               guint16 *s;
-
-               /* FIXME: it will be better to just add WRITE and after get it to previous state */
-               mprotect ((void *) ((int) str & ~(PAGESIZE - 1)), len2 + ((int) str & (PAGESIZE - 1)),
-                                   PROT_READ | PROT_WRITE | PROT_EXEC);
-               len2 >>= 1;
-               /* printf ("swap %p\n", str); */
-               for (i = 0, s = (guint16 *) str; i < len2; i++, s++) {
-                       *s = ((*s & 0xff) << 8) | (*s >> 8);
+               int i;
+               guint16 *p2 = (guint16*)mono_array_addr (o->c_str, guint16, 0);
+               for (i = 0; i < len2; ++i) {
+                       *p2 = GUINT16_FROM_LE (*p2);
+                       ++p2;
                }
        }
-#undef SWAP16
-#else
-               len2 >>= 1;
 #endif
-
-       o = mono_string_new_utf16 ((guint16*)str, len2);
-       g_hash_table_insert (ldstr_table, (gpointer)sig, o);
+       mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
 
        return o;
 }
@@ -439,14 +503,14 @@ mono_string_to_utf8 (MonoString *s)
 
        g_assert (vector != NULL);
 
-       as = g_utf16_to_utf8 (vector, s->length, NULL, NULL, &error);
-
-       g_assert (!error);
+       as = g_utf16_to_utf8 ((gunichar2 *)vector, s->length, NULL, NULL, &error);
+       if (error)
+               g_warning (error->message);
 
        return as;
 }
 
-char *
+gunichar2 *
 mono_string_to_utf16 (MonoString *s)
 {
        char *as;
@@ -458,19 +522,19 @@ mono_string_to_utf16 (MonoString *s)
        as [(s->length * 2) + 1] = '\0';
 
        if (!s->length || !s->c_str) {
-               return (as);
+               return (gunichar2 *)(as);
        }
        
        memcpy (as, mono_string_chars(s), s->length * 2);
        
-       return (as);
+       return (gunichar2 *)(as);
 }
 
 static void
 default_ex_handler (MonoException *ex)
 {
        MonoObject *o = (MonoObject*)ex;
-       g_error ("Exception %s.%s raised in C code", o->klass->name_space, o->klass->name);
+       g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
 }
 
 static MonoExceptionFunc ex_handler = default_ex_handler;
@@ -487,3 +551,31 @@ mono_raise_exception (MonoException *ex)
        ex_handler (ex);
 }
 
+MonoWaitHandle *
+mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
+{
+       MonoWaitHandle *res;
+
+       res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
+
+       res->handle = handle;
+
+       return res;
+}
+
+MonoAsyncResult *
+mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
+{
+       MonoAsyncResult *res;
+
+       res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
+
+       res->data = data;
+       res->async_state = state;
+       res->handle = mono_wait_handle_new (domain, handle);
+       res->sync_completed = FALSE;
+       res->completed = FALSE;
+
+       return res;
+}
+