grammar updates
[mono.git] / mono / metadata / metadata.c
index a3435b293a86e29ca8e6bc474b4d40ce9cede671..0ee805fcc95f6e66015baf7158554294502f5e99 100644 (file)
@@ -1056,8 +1056,10 @@ mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
 {
        int i;
        MonoArrayType *array = g_new0 (MonoArrayType, 1);
+       MonoType *etype;
        
-       array->type = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
+       etype = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
+       array->eklass = mono_class_from_mono_type (etype);
        array->rank = mono_metadata_decode_value (ptr, &ptr);
 
        array->numsizes = mono_metadata_decode_value (ptr, &ptr);
@@ -1086,7 +1088,6 @@ mono_metadata_parse_array (MonoImage *m, const char *ptr, const char **rptr)
 void
 mono_metadata_free_array (MonoArrayType *array)
 {
-       mono_metadata_free_type (array->type);
        g_free (array->sizes);
        g_free (array->lobounds);
        g_free (array);
@@ -1164,6 +1165,22 @@ mono_type_equal (gconstpointer ka, gconstpointer kb)
        return 1;
 }
 
+/**
+ * mono_metadata_init:
+ *
+ *  Initialize the global variables of this module.
+ */
+void
+mono_metadata_init (void)
+{
+       int i;
+
+       type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
+
+       for (i = 0; i < NBUILTIN_TYPES (); ++i)
+               g_hash_table_insert (type_cache, &builtin_types [i], &builtin_types [i]);
+}
+
 /*
  * mono_metadata_parse_type:
  * @m: metadata context
@@ -1185,14 +1202,6 @@ mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
 {
        MonoType *type, *cached;
 
-       if (!type_cache) {
-               int i;
-               type_cache = g_hash_table_new (mono_type_hash, mono_type_equal);
-
-               for (i = 0; i < NBUILTIN_TYPES (); ++i)
-                       g_hash_table_insert (type_cache, &builtin_types [i], &builtin_types [i]);
-       }
-
        switch (mode) {
        case MONO_PARSE_MOD_TYPE:
        case MONO_PARSE_PARAM:
@@ -1252,6 +1261,8 @@ mono_metadata_parse_type (MonoImage *m, MonoParseTypeMode mode, short opt_attrs,
        }
        if (rptr)
                *rptr = ptr;
+
+       /* No need to use locking since nobody is modifying the hash table */
        if (mode != MONO_PARSE_PARAM && !type->num_mods && (cached = g_hash_table_lookup (type_cache, type))) {
                mono_metadata_free_type (type);
                return cached;
@@ -1356,6 +1367,7 @@ mono_metadata_parse_method_signature (MonoImage *m, int def, const char *ptr, co
        method->hasthis = hasthis;
        method->explicit_this = explicit_this;
        method->call_convention = call_convention;
+       method->generic_param_count = gen_param_count;
        if (call_convention != 0xa)
                method->ret = mono_metadata_parse_type (m, MONO_PARSE_RET, ret_attrs, ptr, &ptr);
 
@@ -1399,23 +1411,46 @@ mono_metadata_free_method_signature (MonoMethodSignature *sig)
        g_free (sig);
 }
 
-static MonoGenericInst *
-mono_metadata_parse_generic_inst (MonoImage *m, const char *ptr, const char **rptr)
+static void
+do_mono_metadata_parse_generic_inst (MonoType *type, MonoImage *m, const char *ptr, const char **rptr)
 {
        MonoGenericInst *generic_inst = g_new0 (MonoGenericInst, 1);
        int i, count;
+
+       type->data.generic_inst = generic_inst;
        
        generic_inst->generic_type = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
        generic_inst->type_argc = count = mono_metadata_decode_value (ptr, &ptr);
        generic_inst->type_argv = g_new0 (MonoType*, count);
 
+       /*
+        * Create the klass before parsing the type arguments.
+        * This is required to support "recursive" definitions.
+        * See mcs/tests/gen-23.cs for an example.
+        */
+
+       generic_inst->klass = mono_class_create_from_generic (m, type);
+
        for (i = 0; i < generic_inst->type_argc; i++)
                generic_inst->type_argv [i] = mono_metadata_parse_type (m, MONO_PARSE_TYPE, 0, ptr, &ptr);
        
+       mono_class_initialize_generic (generic_inst->klass, TRUE);
+       
        if (rptr)
                *rptr = ptr;
+}
 
-       return generic_inst;
+static MonoGenericParam *
+mono_metadata_parse_generic_param (MonoImage *m, const char *ptr, const char **rptr)
+{
+       MonoGenericParam *generic_param = g_new0 (MonoGenericParam, 1);
+       
+       generic_param->num = mono_metadata_decode_value (ptr, &ptr);
+
+       if (rptr)
+               *rptr = ptr;
+
+       return generic_param;
 }
 
 /* 
@@ -1464,7 +1499,11 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, const char *ptr, cons
                type->data.klass = mono_class_get (m, token);
                break;
        }
-       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_SZARRAY: {
+               MonoType *etype = mono_metadata_parse_type (m, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr);
+               type->data.klass = mono_class_from_mono_type (etype);
+               break;
+       }
        case MONO_TYPE_PTR:
                type->data.type = mono_metadata_parse_type (m, MONO_PARSE_MOD_TYPE, 0, ptr, &ptr);
                break;
@@ -1477,11 +1516,11 @@ do_mono_metadata_parse_type (MonoType *type, MonoImage *m, const char *ptr, cons
 
        case MONO_TYPE_MVAR:
        case MONO_TYPE_VAR:
-               type->data.type_param = mono_metadata_decode_value (ptr, &ptr);
+               type->data.generic_param = mono_metadata_parse_generic_param (m, ptr, &ptr);
                break;
 
        case MONO_TYPE_GENERICINST:
-               type->data.generic_inst = mono_metadata_parse_generic_inst (m, ptr, &ptr);
+               do_mono_metadata_parse_generic_inst (type, m, ptr, &ptr);
                break;
                
        default:
@@ -1504,7 +1543,6 @@ mono_metadata_free_type (MonoType *type)
        if (type >= builtin_types && type < builtin_types + NBUILTIN_TYPES ())
                return;
        switch (type->type){
-       case MONO_TYPE_SZARRAY:
        case MONO_TYPE_PTR:
                mono_metadata_free_type (type->data.type);
                break;
@@ -2118,6 +2156,55 @@ mono_metadata_packing_from_typedef (MonoImage *meta, guint32 index, guint32 *pac
        return loc.result + 1;
 }
 
+/*
+ * mono_metadata_custom_attrs_from_index:
+ * @meta: metadata context
+ * @index: token representing the parent
+ * 
+ * Returns: the 1-based index into the CustomAttribute table of the first 
+ * attribute which belongs to the metadata object described by @index.
+ * Returns 0 if no such attribute is found.
+ */
+guint32
+mono_metadata_custom_attrs_from_index (MonoImage *meta, guint32 index)
+{
+       MonoTableInfo *tdef = &meta->tables [MONO_TABLE_CUSTOMATTRIBUTE];
+       locator_t loc;
+       
+       if (!tdef->base)
+               return 0;
+
+       loc.idx = index;
+       loc.col_idx = MONO_CUSTOM_ATTR_PARENT;
+       loc.t = tdef;
+
+       if (!bsearch (&loc, tdef->base, tdef->rows, tdef->row_size, table_locator))
+               return 0;
+
+       /* Find the first entry by searching backwards */
+       while ((loc.result > 0) && (mono_metadata_decode_row_col (tdef, loc.result - 1, MONO_CUSTOM_ATTR_PARENT) == index))
+               loc.result --;
+
+       /* loc_result is 0..1, needs to be mapped to table index (that is +1) */
+       return loc.result + 1;
+}
+
+#ifdef DEBUG
+static void
+mono_backtrace (int limit)
+{
+       void *array[limit];
+       char **names;
+       int i;
+       backtrace (array, limit);
+       names = backtrace_symbols (array, limit);
+       for (i =0; i < limit; ++i) {
+               g_print ("\t%s\n", names [i]);
+       }
+       g_free (names);
+}
+#endif
+
 #ifndef __GNUC__
 /*#define __alignof__(a) sizeof(a)*/
 #define __alignof__(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
@@ -2196,8 +2283,15 @@ mono_type_size (MonoType *t, gint *align)
                *align = __alignof__(gpointer);
                return sizeof (gpointer);
        case MONO_TYPE_TYPEDBYREF:
+               return mono_class_value_size (mono_defaults.typed_reference_class, align);
+       case MONO_TYPE_GENERICINST: {
+               MonoClass *iclass = mono_class_from_mono_type (t);
+               return mono_type_size (&iclass->byval_arg, align);
+       }
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
                *align = __alignof__(gpointer);
-               return sizeof (gpointer) * 2;
+               return sizeof (gpointer);
        default:
                g_error ("mono_type_size: type 0x%02x unknown", t->type);
        }
@@ -2276,6 +2370,10 @@ mono_type_stack_size (MonoType *t, gint *align)
                        return size;
                }
        }
+       case MONO_TYPE_GENERICINST: {
+               MonoClass *iclass = mono_class_from_mono_type (t);
+               return mono_type_stack_size (&iclass->byval_arg, align);
+       }
        default:
                g_error ("type 0x%02x unknown", t->type);
        }
@@ -2297,16 +2395,15 @@ mono_metadata_type_hash (MonoType *t1)
        switch (t1->type) {
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_CLASS:
+       case MONO_TYPE_SZARRAY:
                /* check if the distribution is good enough */
                return ((hash << 5) - hash) ^ g_str_hash (t1->data.klass->name);
        case MONO_TYPE_PTR:
                return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.type);
-       case MONO_TYPE_SZARRAY:
-               if (t1->data.type->type == MONO_TYPE_OBJECT)
-                       return ((hash << 5) - hash);
-               return ((hash << 5) - hash) ^ (gint32)(t1->data.type->data.klass);
        case MONO_TYPE_ARRAY:
-               return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.array->type);
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (&t1->data.array->eklass->byval_arg);
+       case MONO_TYPE_GENERICINST:
+               return ((hash << 5) - hash) ^ mono_metadata_type_hash (t1->data.generic_inst->generic_type);
        }
        return hash;
 }
@@ -2348,25 +2445,29 @@ mono_metadata_type_equal (MonoType *t1, MonoType *t2)
                return TRUE;
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_CLASS:
+       case MONO_TYPE_SZARRAY:
                return t1->data.klass == t2->data.klass;
        case MONO_TYPE_PTR:
                return mono_metadata_type_equal (t1->data.type, t2->data.type);
-       case MONO_TYPE_SZARRAY:
-retry_sz:
-               if (t1->data.type->type != t2->data.type->type)
-                       return FALSE;
-               if (t1->data.type->type == MONO_TYPE_CLASS || t1->data.type->type == MONO_TYPE_VALUETYPE)
-                       return t1->data.type->data.klass == t2->data.type->data.klass;
-               if (t1->data.type->type == MONO_TYPE_SZARRAY) {
-                       t1 = t1->data.type;
-                       t2 = t2->data.type;
-                       goto retry_sz;
-               }
-               return mono_metadata_type_equal (t1->data.type, t2->data.type);
        case MONO_TYPE_ARRAY:
                if (t1->data.array->rank != t2->data.array->rank)
                        return FALSE;
-               return mono_metadata_type_equal (t1->data.array->type, t2->data.array->type);
+               return t1->data.array->eklass == t2->data.array->eklass;
+       case MONO_TYPE_GENERICINST: {
+               int i;
+               if (t1->data.generic_inst->type_argc != t2->data.generic_inst->type_argc)
+                       return FALSE;
+               if (!mono_metadata_type_equal (t1->data.generic_inst->generic_type, t2->data.generic_inst->generic_type))
+                       return FALSE;
+               for (i = 0; i < t1->data.generic_inst->type_argc; ++i) {
+                       if (!mono_metadata_type_equal (t1->data.generic_inst->type_argv [i], t2->data.generic_inst->type_argv [i]))
+                               return FALSE;
+               }
+               return TRUE;
+       }
+       case MONO_TYPE_VAR:
+       case MONO_TYPE_MVAR:
+               return t1->data.generic_param->num == t2->data.generic_param->num;
        default:
                g_error ("implement type compare for %0x!", t1->type);
                return FALSE;
@@ -2767,12 +2868,31 @@ mono_type_create_from_typespec (MonoImage *image, guint32 type_spec)
        guint32 len;
        MonoType *type;
 
+       mono_loader_lock ();
+
+       if ((type = g_hash_table_lookup (image->typespec_cache, GUINT_TO_POINTER (type_spec)))) {
+               mono_loader_unlock ();
+               return type;
+       }
+
        t = &image->tables [MONO_TABLE_TYPESPEC];
        
        mono_metadata_decode_row (t, idx-1, cols, MONO_TYPESPEC_SIZE);
        ptr = mono_metadata_blob_heap (image, cols [MONO_TYPESPEC_SIGNATURE]);
        len = mono_metadata_decode_value (ptr, &ptr);
-       type = mono_metadata_parse_type (image, MONO_PARSE_TYPE, 0, ptr, &ptr);
+
+       type = g_new0 (MonoType, 1);
+
+       g_hash_table_insert (image->typespec_cache, GUINT_TO_POINTER (type_spec), type);
+
+       if (*ptr == MONO_TYPE_BYREF) {
+               type->byref = 1; 
+               ptr++;
+       }
+
+       do_mono_metadata_parse_type (type, image, ptr, &ptr);
+
+       mono_loader_unlock ();
 
        return type;
 }
@@ -2855,8 +2975,9 @@ handle_enum:
                        case MONO_NATIVE_BOOLEAN:
                                *conv = MONO_MARSHAL_CONV_BOOL_I4;
                                return MONO_NATIVE_BOOLEAN;
+                       case MONO_NATIVE_I1:
                        case MONO_NATIVE_U1:
-                               return MONO_NATIVE_U1;
+                               return mspec->native;
                        default:
                                g_error ("cant marshal bool to native type %02x", mspec->native);
                        }
@@ -3075,3 +3196,87 @@ mono_guid_to_string (const guint8 *guid)
                                guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]);
 }
 
+static MonoClass**
+get_constraints (MonoImage *image, int owner)
+{
+       MonoTableInfo *tdef  = &image->tables [MONO_TABLE_GENERICPARAMCONSTRAINT];
+       guint32 cols [MONO_GENPARCONSTRAINT_SIZE];
+       guint32 i, token, found;
+       MonoClass *klass, **res;
+       GList *cons = NULL, *tmp;
+       
+
+       found = 0;
+       for (i = 0; i < tdef->rows; ++i) {
+               mono_metadata_decode_row (tdef, i, cols, MONO_GENPARCONSTRAINT_SIZE);
+               if (cols [MONO_GENPARCONSTRAINT_GENERICPAR] == owner) {
+                       token = mono_metadata_token_from_dor (cols [MONO_GENPARCONSTRAINT_CONSTRAINT]);
+                       klass = mono_class_get (image, token);
+                       cons = g_list_append (cons, klass);
+                       ++found;
+               } else {
+                       /* contiguous list finished */
+                       if (found)
+                               break;
+               }
+       }
+       if (!found)
+               return NULL;
+       res = g_new0 (MonoClass*, found + 1);
+       for (i = 0, tmp = cons; i < found; ++i, tmp = tmp->next) {
+               res [i] = tmp->data;
+       }
+       g_list_free (cons);
+       return res;
+}
+
+MonoGenericParam *
+mono_metadata_load_generic_params (MonoImage *image, guint32 token, guint32 *num)
+{
+       MonoTableInfo *tdef  = &image->tables [MONO_TABLE_GENERICPARAM];
+       guint32 cols [MONO_GENERICPARAM_SIZE];
+       guint32 i, owner, last_num, n;
+       MonoGenericParam *params;
+
+       if (mono_metadata_token_table (token) == MONO_TABLE_TYPEDEF)
+               owner = MONO_TYPEORMETHOD_TYPE;
+       else if (mono_metadata_token_table (token) == MONO_TABLE_METHOD)
+               owner = MONO_TYPEORMETHOD_METHOD;
+       else {
+               g_error ("wrong token %x to load_generics_params", token);
+       }
+       owner |= mono_metadata_token_index (token) << MONO_TYPEORMETHOD_BITS;
+       if (num)
+               *num = 0;
+       if (!tdef->base)
+               return NULL;
+
+       for (i = 0; i < tdef->rows; ++i) {
+               mono_metadata_decode_row (tdef, i, cols, MONO_GENERICPARAM_SIZE);
+               if (cols [MONO_GENERICPARAM_OWNER] == owner)
+                       break;
+       }
+       last_num = 0;
+       if (i >= tdef->rows)
+               return NULL;
+       params = NULL;
+       n = 1;
+       do {
+               params = g_realloc (params, sizeof (MonoGenericParam) * n);
+               params [n - 1].pklass = NULL;
+               params [n - 1].method = NULL;
+               params [n - 1].flags = cols [MONO_GENERICPARAM_FLAGS];
+               params [n - 1].num = cols [MONO_GENERICPARAM_NUMBER];
+               params [n - 1].name = mono_metadata_string_heap (image, cols [MONO_GENERICPARAM_NAME]);
+               params [n - 1].constraints = get_constraints (image, i + 1);
+               if (++i >= tdef->rows)
+                       break;
+               mono_metadata_decode_row (tdef, i, cols, MONO_GENERICPARAM_SIZE);
+               n++;
+       } while (cols [MONO_GENERICPARAM_OWNER] == owner);
+       
+       if (num)
+               *num = n;
+       return params;
+}
+