X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=6b8d75728face562a7abdf015799acb7d0a052bf;hb=88e4fcdd9a3a68aaacccbacd45522bbea4eb5e23;hp=72d73a6a9e33f08a032e27e77b4ce0ec110b96f2;hpb=ac3283997b3e4259138c8c61200c3eaee1b9d29a;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 72d73a6a9e3..6b8d75728fa 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -32,17 +33,6 @@ #include #include -/* - * Uncomment this to enable GC aware auto layout: in this mode, reference - * fields are grouped together inside objects, increasing collector - * performance. - * Requires that all classes whose layout is known to the runtime be annotated - * with [StructLayout (LayoutKind.Sequential)] - */ -//#define GC_AWARE_AUTO_LAYOUT - -#define CSIZE(x) (sizeof (x) / 4) - MonoStats mono_stats; gboolean mono_print_vtable = FALSE; @@ -60,7 +50,6 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) const char *name, *nspace; MonoClass *res; MonoAssembly **references; - MonoImageOpenStatus status; mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE); @@ -92,7 +81,6 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) break; } - mono_image_load_references (image, &status); references = image->references; if (!references || !references [idx-1]) { /* @@ -115,6 +103,224 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) return mono_class_from_name (image, nspace, name); } +static MonoType* +dup_type (MonoType* t) +{ + MonoType *r = g_new0 (MonoType, 1); + *r = *t; + return r; +} + +static void +mono_type_get_name_recurse (MonoType *type, GString *str) +{ + MonoClass *klass; + + switch (type->type) { + case MONO_TYPE_ARRAY: { + int i, rank = type->data.array->rank; + + mono_type_get_name_recurse (&type->data.array->eklass->byval_arg, str); + g_string_append_c (str, '['); + for (i = 1; i < rank; i++) + g_string_append_c (str, ','); + g_string_append_c (str, ']'); + break; + } + case MONO_TYPE_SZARRAY: + mono_type_get_name_recurse (&type->data.klass->byval_arg, str); + g_string_append (str, "[]"); + break; + case MONO_TYPE_PTR: + mono_type_get_name_recurse (type->data.type, str); + g_string_append_c (str, '*'); + break; + default: + klass = mono_class_from_mono_type (type); + if (klass->nested_in) { + mono_type_get_name_recurse (&klass->nested_in->byval_arg, str); + g_string_append_c (str, '+'); + } + if (*klass->name_space) { + g_string_append (str, klass->name_space); + g_string_append_c (str, '.'); + } + g_string_append (str, klass->name); + break; + } +} + +/* + * mono_type_get_name: + * @type: a type + * + * Returns the string representation for type as required by System.Reflection. + * The inverse of mono_reflection_parse_type (). + */ +char* +mono_type_get_name (MonoType *type) +{ + GString* result = g_string_new (""); + mono_type_get_name_recurse (type, result); + + if (type->byref) + g_string_append_c (result, '&'); + + return g_string_free (result, FALSE); +} + +gboolean +mono_class_is_open_constructed_type (MonoType *t) +{ + switch (t->type) { + case MONO_TYPE_VAR: + case MONO_TYPE_MVAR: + return TRUE; + case MONO_TYPE_SZARRAY: + return mono_class_is_open_constructed_type (&t->data.klass->byval_arg); + case MONO_TYPE_ARRAY: + return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg); + case MONO_TYPE_PTR: + return mono_class_is_open_constructed_type (t->data.type); + case MONO_TYPE_GENERICINST: { + MonoGenericInst *ginst = t->data.generic_inst; + int i; + + if (mono_class_is_open_constructed_type (ginst->generic_type)) + return TRUE; + for (i = 0; i < ginst->type_argc; i++) + if (mono_class_is_open_constructed_type (ginst->type_argv [i])) + return TRUE; + return FALSE; + } + default: + return FALSE; + } +} + +MonoType* +mono_class_inflate_generic_type (MonoType *type, MonoGenericInst *ginst, + MonoGenericMethod *gmethod) +{ + switch (type->type) { + case MONO_TYPE_MVAR: + if (gmethod && gmethod->mtype_argv) + return dup_type (gmethod->mtype_argv [type->data.generic_param->num]); + else + return type; + case MONO_TYPE_VAR: + if (ginst) { + MonoType *t = ginst->type_argv [type->data.generic_param->num]; + + if ((t->type == MONO_TYPE_VAR) || (t->type == MONO_TYPE_MVAR)) + return type; + else + return dup_type (t); + } else + return type; + case MONO_TYPE_SZARRAY: { + MonoClass *eclass = type->data.klass; + MonoClass *nclass; + MonoType *nt; + if ((eclass->byval_arg.type == MONO_TYPE_MVAR) && gmethod) { + nclass = mono_class_from_mono_type (gmethod->mtype_argv [eclass->byval_arg.data.generic_param->num]); + } else if ((eclass->byval_arg.type == MONO_TYPE_VAR) && ginst) { + nclass = mono_class_from_mono_type (ginst->type_argv [eclass->byval_arg.data.generic_param->num]); + } else { + return type; + } + nt = dup_type (type); + nt->data.klass = nclass; + return nt; + } + case MONO_TYPE_GENERICINST: { + MonoGenericInst *oginst = type->data.generic_inst; + MonoGenericInst *nginst; + MonoType *nt; + int i; + + nginst = g_new0 (MonoGenericInst, 1); + *nginst = *oginst; + + nginst->type_argv = g_new0 (MonoType *, oginst->type_argc); + + for (i = 0; i < oginst->type_argc; i++) { + MonoType *t = oginst->type_argv [i]; + nginst->type_argv [i] = mono_class_inflate_generic_type (t, ginst, gmethod); + }; + + nt = dup_type (type); + nt->data.generic_inst = nginst; + return nt; + } + default: + return type; + } + return type; +} + +static MonoMethodSignature* +inflate_generic_signature (MonoImage *image, MonoMethodSignature *sig, + MonoGenericMethod *gmethod) +{ + MonoMethodSignature *res; + int i; + res = mono_metadata_signature_alloc (image, sig->param_count); + res->ret = mono_class_inflate_generic_type (sig->ret, gmethod->generic_inst, gmethod); + for (i = 0; i < sig->param_count; ++i) + res->params [i] = mono_class_inflate_generic_type (sig->params [i], + gmethod->generic_inst, + gmethod); + res->hasthis = sig->hasthis; + res->explicit_this = sig->explicit_this; + res->call_convention = sig->call_convention; + res->generic_param_count = sig->generic_param_count; + return res; +} + +static MonoMethodHeader* +inflate_generic_header (MonoMethodHeader *header, MonoGenericMethod *gmethod) +{ + MonoMethodHeader *res; + int i; + res = g_malloc0 (sizeof (MonoMethodHeader) + sizeof (gpointer) * header->num_locals); + res->code = header->code; + res->code_size = header->code_size; + res->max_stack = header->max_stack; + res->num_clauses = header->num_clauses; + res->init_locals = header->init_locals; + res->num_locals = header->num_locals; + res->clauses = header->clauses; + res->gen_params = header->gen_params; + res->gen_method = gmethod; + for (i = 0; i < header->num_locals; ++i) + res->locals [i] = mono_class_inflate_generic_type (header->locals [i], + gmethod->generic_inst, + gmethod); + return res; +} + +MonoMethod* +mono_class_inflate_generic_method (MonoMethod *method, MonoGenericMethod *gmethod) +{ + MonoMethod *result; + if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)) { + MonoMethodPInvoke *nmethod = g_new0 (MonoMethodPInvoke, 1); + *nmethod = *(MonoMethodPInvoke*)method; + result = (MonoMethod*)nmethod; + } else { + MonoMethodNormal *nmethod = g_new0 (MonoMethodNormal, 1); + *nmethod = *(MonoMethodNormal*)method; + result = (MonoMethod*)nmethod; + if (nmethod->header) + nmethod->header = inflate_generic_header (nmethod->header, gmethod); + } + result->klass = gmethod->klass; + result->signature = inflate_generic_signature ( + method->klass->image, result->signature, gmethod); + return result; +} + /** * class_compute_field_layout: * @m: pointer to the metadata. @@ -136,6 +342,7 @@ class_compute_field_layout (MonoClass *class) guint32 rva; guint32 packing_size = 0; gboolean explicit_size; + MonoClassField *field; if (class->size_inited) return; @@ -176,62 +383,56 @@ class_compute_field_layout (MonoClass *class) for (i = 0; i < top; i++){ const char *sig; guint32 cols [MONO_FIELD_SIZE]; - guint32 constant_cols [MONO_CONSTANT_SIZE]; - guint32 cindex; int idx = class->field.first + i; - - mono_metadata_decode_row (t, idx, cols, CSIZE (cols)); + + field = &class->fields [i]; + mono_metadata_decode_row (t, idx, cols, MONO_FIELD_SIZE); /* The name is needed for fieldrefs */ - class->fields [i].name = mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]); + field->name = mono_metadata_string_heap (m, cols [MONO_FIELD_NAME]); sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]); mono_metadata_decode_value (sig, &sig); /* FIELD signature == 0x06 */ g_assert (*sig == 0x06); - class->fields [i].type = mono_metadata_parse_field_type ( + field->type = mono_metadata_parse_field_type ( m, cols [MONO_FIELD_FLAGS], sig + 1, &sig); + if (mono_field_is_deleted (field)) + continue; + if (class->generic_inst) { + field->type = mono_class_inflate_generic_type (field->type, class->generic_inst, NULL); + field->type->attrs = cols [MONO_FIELD_FLAGS]; + } - class->fields [i].parent = class; + field->parent = class; - if (!(class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)) { - if (class->fields [i].type->byref) { + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) { + if (field->type->byref) { blittable = FALSE; } else { - MonoClass *field_class = mono_class_from_mono_type (class->fields [i].type); + MonoClass *field_class = mono_class_from_mono_type (field->type); if (!field_class || !field_class->blittable) blittable = FALSE; } } if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { - mono_metadata_field_info (m, idx, &class->fields [i].offset, NULL, NULL); - if (class->fields [i].offset == (guint32)-1) - g_warning ("%s not initialized correctly (missing field layout info for %s)", class->name, class->fields [i].name); + mono_metadata_field_info (m, idx, &field->offset, NULL, NULL); + if (field->offset == (guint32)-1) + g_warning ("%s not initialized correctly (missing field layout info for %s)", class->name, field->name); } if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_HAS_FIELD_RVA) { mono_metadata_field_info (m, idx, NULL, &rva, NULL); if (!rva) - g_warning ("field %s in %s should have RVA data, but hasn't", class->fields [i].name, class->name); - class->fields [i].data = mono_cli_rva_map (class->image->image_info, rva); + g_warning ("field %s in %s should have RVA data, but hasn't", field->name, class->name); + field->data = mono_cli_rva_map (class->image->image_info, rva); } if (class->enumtype && !(cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC)) { - class->enum_basetype = class->fields [i].type; + class->enum_basetype = field->type; class->cast_class = class->element_class = mono_class_from_mono_type (class->enum_basetype); blittable = class->element_class->blittable; } - if ((class->fields [i].type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) && - (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)) { - cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (class->field.first + i + 1)); - if (!cindex) { - g_warning ("constant for field %s:%s not found", class->name, class->fields [i].name); - continue; - } - mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE); - class->fields [i].def_value = g_new0 (MonoConstant, 1); - class->fields [i].def_value->type = constant_cols [MONO_CONSTANT_TYPE]; - class->fields [i].def_value->value = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]); - } + /* The def_value of fields is compute lazily during vtable creation */ } if (class == mono_defaults.string_class) @@ -247,6 +448,9 @@ class_compute_field_layout (MonoClass *class) class->instance_size = MAX (real_size, class->instance_size); } + if (class->gen_params) + return; + mono_class_layout_fields (class); } @@ -256,7 +460,22 @@ mono_class_layout_fields (MonoClass *class) int i; const int top = class->field.count; guint32 layout = class->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; - guint32 pass, passes; + guint32 pass, passes, real_size; + gboolean gc_aware_layout = FALSE; + MonoClassField *field; + + /* + * Enable GC aware auto layout: in this mode, reference + * fields are grouped together inside objects, increasing collector + * performance. + * Requires that all classes whose layout is known to native code be annotated + * with [StructLayout (LayoutKind.Sequential)] + */ + /* corlib is missing [StructLayout] directives in many places */ + if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + if (class->image != mono_defaults.corlib) + gc_aware_layout = TRUE; + } /* * Compute field layout and total size (not considering static fields) @@ -266,24 +485,30 @@ mono_class_layout_fields (MonoClass *class) case TYPE_ATTRIBUTE_AUTO_LAYOUT: case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT: -#ifdef GC_AWARE_AUTO_LAYOUT - passes = 2; -#else - passes = 1; -#endif + if (gc_aware_layout) + passes = 2; + else + passes = 1; + if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) passes = 1; + if (class->parent) + real_size = class->parent->instance_size; + else + real_size = sizeof (MonoObject); + for (pass = 0; pass < passes; ++pass) { for (i = 0; i < top; i++){ int size, align; + field = &class->fields [i]; - if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC) + if (mono_field_is_deleted (field)) + continue; + if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) continue; -#ifdef GC_AWARE_AUTO_LAYOUT - /* FIXME: Fix mono_marshal_load_type_info () too */ - if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + if (gc_aware_layout) { /* * We process fields with reference type in the first pass, * and fields with non-reference type in the second pass. @@ -291,7 +516,7 @@ mono_class_layout_fields (MonoClass *class) * some internal structures, we store GC_MALLOCed memory * in IntPtr fields... */ - if (MONO_TYPE_IS_POINTER (class->fields [i].type)) { + if (MONO_TYPE_IS_POINTER (field->type)) { if (pass == 1) continue; } else { @@ -299,18 +524,25 @@ mono_class_layout_fields (MonoClass *class) continue; } } -#endif - size = mono_type_size (class->fields [i].type, &align); + if ((top == 1) && (class->instance_size == sizeof (MonoObject)) && + (strcmp (field->name, "$PRIVATE$") == 0)) { + /* This field is a hack inserted by MCS to empty structures */ + continue; + } + + size = mono_type_size (field->type, &align); /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */ align = class->packing_size ? MIN (class->packing_size, align): align; class->min_align = MAX (align, class->min_align); - class->fields [i].offset = class->instance_size; - class->fields [i].offset += align - 1; - class->fields [i].offset &= ~(align - 1); - class->instance_size = class->fields [i].offset + size; + field->offset = real_size; + field->offset += align - 1; + field->offset &= ~(align - 1); + real_size = field->offset + size; } + + class->instance_size = MAX (real_size, class->instance_size); if (class->instance_size & (class->min_align - 1)) { class->instance_size += class->min_align - 1; @@ -319,32 +551,37 @@ mono_class_layout_fields (MonoClass *class) } break; case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: + real_size = 0; for (i = 0; i < top; i++) { int size, align; + field = &class->fields [i]; /* * There must be info about all the fields in a type if it * uses explicit layout. */ - if (class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC) + if (mono_field_is_deleted (field)) + continue; + if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) continue; - size = mono_type_size (class->fields [i].type, &align); + size = mono_type_size (field->type, &align); /* - * When we get here, class->fields [i].offset is already set by the + * When we get here, field->offset is already set by the * loader (for either runtime fields or fields loaded from metadata). * The offset is from the start of the object: this works for both * classes and valuetypes. */ - class->fields [i].offset += sizeof (MonoObject); + field->offset += sizeof (MonoObject); /* * Calc max size. */ - class->instance_size = MAX (class->instance_size, size + class->fields [i].offset); + real_size = MAX (real_size, size + field->offset); } + class->instance_size = MAX (real_size, class->instance_size); break; } @@ -355,15 +592,18 @@ mono_class_layout_fields (MonoClass *class) */ for (i = 0; i < top; i++){ int size, align; + field = &class->fields [i]; - if (!(class->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)) + if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) + continue; + if (mono_field_is_deleted (field)) continue; - size = mono_type_size (class->fields [i].type, &align); - class->fields [i].offset = class->class_size; - class->fields [i].offset += align - 1; - class->fields [i].offset &= ~(align - 1); - class->class_size = class->fields [i].offset + size; + size = mono_type_size (field->type, &align); + field->offset = class->class_size; + field->offset += align - 1; + field->offset &= ~(align - 1); + class->class_size = field->offset + size; } } @@ -450,12 +690,15 @@ mono_get_unique_iid (MonoClass *class) g_assert (class->flags & TYPE_ATTRIBUTE_INTERFACE); + mono_loader_lock (); + if (!iid_hash) iid_hash = g_hash_table_new (g_str_hash, g_str_equal); str = g_strdup_printf ("%s|%s.%s\n", class->image->name, class->name_space, class->name); if (g_hash_table_lookup_extended (iid_hash, str, NULL, &value)) { + mono_loader_unlock (); g_free (str); return (guint)value; } else { @@ -463,11 +706,13 @@ mono_get_unique_iid (MonoClass *class) ++iid; } + mono_loader_unlock (); + return iid - 1; } static void -collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray *res) +collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res) { int i; MonoClass *ic; @@ -475,18 +720,20 @@ collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray *res) for (i = 0; i < klass->interface_count; i++) { ic = klass->interfaces [i]; - g_ptr_array_add (res, ic); + if (*res == NULL) + *res = g_ptr_array_new (); + g_ptr_array_add (*res, ic); collect_implemented_interfaces_aux (ic, res); } } -static GPtrArray* +static inline GPtrArray* collect_implemented_interfaces (MonoClass *klass) { - GPtrArray *res = g_ptr_array_new (); + GPtrArray *res = NULL; - collect_implemented_interfaces_aux (klass, res); + collect_implemented_interfaces_aux (klass, &res); return res; } @@ -523,28 +770,36 @@ setup_interface_offsets (MonoClass *class, int cur_slot) class->interface_offsets [i] = -1; ifaces = collect_implemented_interfaces (class); - for (i = 0; i < ifaces->len; ++i) { - ic = g_ptr_array_index (ifaces, i); - class->interface_offsets [ic->interface_id] = cur_slot; - cur_slot += ic->method.count; + if (ifaces) { + for (i = 0; i < ifaces->len; ++i) { + ic = g_ptr_array_index (ifaces, i); + class->interface_offsets [ic->interface_id] = cur_slot; + cur_slot += ic->method.count; + } + g_ptr_array_free (ifaces, TRUE); } - g_ptr_array_free (ifaces, TRUE); for (k = class->parent; k ; k = k->parent) { ifaces = collect_implemented_interfaces (k); - for (i = 0; i < ifaces->len; ++i) { - ic = g_ptr_array_index (ifaces, i); + if (ifaces) { + for (i = 0; i < ifaces->len; ++i) { + ic = g_ptr_array_index (ifaces, i); - if (class->interface_offsets [ic->interface_id] == -1) { - int io = k->interface_offsets [ic->interface_id]; + if (class->interface_offsets [ic->interface_id] == -1) { + int io = k->interface_offsets [ic->interface_id]; - g_assert (io >= 0); + g_assert (io >= 0); - class->interface_offsets [ic->interface_id] = io; + class->interface_offsets [ic->interface_id] = io; + } } + g_ptr_array_free (ifaces, TRUE); } - g_ptr_array_free (ifaces, TRUE); } + + if (class->flags & TYPE_ATTRIBUTE_INTERFACE) + class->interface_offsets [class->interface_id] = cur_slot; + return cur_slot; } @@ -555,7 +810,7 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) MonoMethod **vtable; int i, max_vtsize = 0, max_iid, cur_slot = 0; GPtrArray *ifaces; - MonoGHashTable *override_map; + MonoGHashTable *override_map = NULL; /* setup_vtable() must be called only once on the type */ if (class->interface_offsets) { @@ -564,11 +819,13 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) } ifaces = collect_implemented_interfaces (class); - for (i = 0; i < ifaces->len; i++) { - MonoClass *ic = g_ptr_array_index (ifaces, i); - max_vtsize += ic->method.count; + if (ifaces) { + for (i = 0; i < ifaces->len; i++) { + MonoClass *ic = g_ptr_array_index (ifaces, i); + max_vtsize += ic->method.count; + } + g_ptr_array_free (ifaces, TRUE); } - g_ptr_array_free (ifaces, TRUE); if (class->parent) { max_vtsize += class->parent->vtable_size; @@ -588,8 +845,6 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) if (class->parent && class->parent->vtable_size) memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size); - override_map = mono_g_hash_table_new (NULL, NULL); - /* override interface methods */ for (i = 0; i < onum; i++) { MonoMethod *decl = overrides [i*2]; @@ -599,13 +854,19 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) dslot = decl->slot + class->interface_offsets [decl->klass->interface_id]; vtable [dslot] = overrides [i*2 + 1]; vtable [dslot]->slot = dslot; + if (!override_map) + override_map = mono_g_hash_table_new (NULL, NULL); + mono_g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]); } } for (k = class; k ; k = k->parent) { + int nifaces = 0; ifaces = collect_implemented_interfaces (k); - for (i = 0; i < ifaces->len; i++) { + if (ifaces) + nifaces = ifaces->len; + for (i = 0; i < nifaces; i++) { int j, l, io; ic = g_ptr_array_index (ifaces, i); @@ -712,6 +973,20 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) if (im->flags & METHOD_ATTRIBUTE_STATIC) continue; g_assert (io + l <= max_vtsize); + + /* + * If one of our parents already implements this interface + * we can inherit the implementation. + */ + if (!(vtable [io + l])) { + MonoClass *parent = class->parent; + + if ((ic->interface_id <= parent->max_interface_id) && + (parent->interface_offsets [ic->interface_id]) && + parent->vtable) + vtable [io + l] = parent->vtable [parent->interface_offsets [ic->interface_id] + l]; + } + if (!(vtable [io + l])) { for (j = 0; j < onum; ++j) { g_print (" at slot %d: %s (%d) overrides %s (%d)\n", io+l, overrides [j*2+1]->name, @@ -746,7 +1021,8 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) } } } - g_ptr_array_free (ifaces, TRUE); + if (ifaces) + g_ptr_array_free (ifaces, TRUE); } for (i = 0; i < class->method.count; ++i) { @@ -766,6 +1042,8 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) mono_metadata_signature_equal (cm->signature, m1->signature)) { slot = k->methods [j]->slot; g_assert (cm->slot < max_vtsize); + if (!override_map) + override_map = mono_g_hash_table_new (NULL, NULL); mono_g_hash_table_insert (override_map, m1, cm); break; } @@ -780,7 +1058,7 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) if (cm->slot < 0) cm->slot = cur_slot++; - if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT)) + if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT) && !cm->signature->generic_param_count) vtable [cm->slot] = cm; } @@ -791,6 +1069,8 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) g_assert (decl->slot != -1); vtable [decl->slot] = overrides [i*2 + 1]; overrides [i * 2 + 1]->slot = decl->slot; + if (!override_map) + override_map = mono_g_hash_table_new (NULL, NULL); mono_g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]); } } @@ -799,14 +1079,16 @@ mono_class_setup_vtable (MonoClass *class, MonoMethod **overrides, int onum) * If a method occupies more than one place in the vtable, and it is * overriden, then change the other occurances too. */ - for (i = 0; i < max_vtsize; ++i) - if (vtable [i]) { - MonoMethod *cm = mono_g_hash_table_lookup (override_map, vtable [i]); - if (cm) - vtable [i] = cm; - } - mono_g_hash_table_destroy (override_map); + if (override_map) { + for (i = 0; i < max_vtsize; ++i) + if (vtable [i]) { + MonoMethod *cm = mono_g_hash_table_lookup (override_map, vtable [i]); + if (cm) + vtable [i] = cm; + } + mono_g_hash_table_destroy (override_map); + } class->vtable_size = cur_slot; class->vtable = g_malloc0 (sizeof (gpointer) * class->vtable_size); @@ -882,6 +1164,17 @@ mono_class_init (MonoClass *class) if (class->inited) return; + /*g_print ("Init class %s\n", class->name);*/ + + /* We do everything inside the lock to prevent races */ + mono_loader_lock (); + + if (class->inited) { + mono_loader_unlock (); + /* Somebody might have gotten in before us */ + return; + } + if (class->init_pending) { /* this indicates a cyclic dependency */ g_error ("pending init %s.%s\n", class->name_space, class->name); @@ -917,6 +1210,7 @@ mono_class_init (MonoClass *class) ctor->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL; ctor->signature = sig; ctor->name = ".ctor"; + ctor->slot = -1; class->methods = g_new (MonoMethod*, class->method.count); class->methods [0] = ctor; if (class->rank > 1) { @@ -932,13 +1226,16 @@ mono_class_init (MonoClass *class) ctor->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL; ctor->signature = sig; ctor->name = ".ctor"; + ctor->slot = -1; class->methods [1] = ctor; } } else { - class->methods = g_new (MonoMethod*, class->method.count); - for (i = 0; i < class->method.count; ++i) { - class->methods [i] = mono_get_method (class->image, - MONO_TOKEN_METHOD_DEF | (i + class->method.first + 1), class); + if (!class->generic_inst && !class->methods) { + class->methods = g_new (MonoMethod*, class->method.count); + for (i = 0; i < class->method.count; ++i) { + class->methods [i] = mono_get_method (class->image, + MONO_TOKEN_METHOD_DEF | (i + class->method.first + 1), class); + } } } @@ -968,6 +1265,7 @@ mono_class_init (MonoClass *class) * we have to setup them for interfaces, too. */ setup_interface_offsets (class, 0); + mono_loader_unlock (); return; } @@ -1029,6 +1327,8 @@ mono_class_init (MonoClass *class) class->has_finalize = 1; } + mono_loader_unlock (); + if (mono_debugger_class_init_func) mono_debugger_class_init_func (class); } @@ -1177,6 +1477,15 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) if (!parent) g_assert_not_reached (); /* FIXME */ + if (parent->generic_inst && !parent->name) { + /* + * If the parent is a generic instance, we may get + * called before it is fully initialized, especially + * before it has its name. + */ + return; + } + class->marshalbyref = parent->marshalbyref; class->contextbound = parent->contextbound; class->delegate = parent->delegate; @@ -1199,7 +1508,6 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) class->valuetype = class->enumtype = 1; } /*class->enumtype = class->parent->enumtype; */ - class->parent->subclasses = g_list_prepend (class->parent->subclasses, class); mono_class_setup_supertypes (class); } else { class->parent = NULL; @@ -1248,8 +1556,12 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) guint icount = 0; MonoClass **interfaces; - if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token)))) + mono_loader_lock (); + + if ((class = g_hash_table_lookup (image->class_cache, GUINT_TO_POINTER (type_token)))) { + mono_loader_unlock (); return class; + } g_assert (mono_metadata_token_table (type_token) == MONO_TABLE_TYPEDEF); @@ -1285,7 +1597,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) class->cast_class = class->element_class = class; - /*g_print ("Init class %s\n", name);*/ + /*g_print ("Load class %s\n", name);*/ mono_class_setup_parent (class, parent); @@ -1298,7 +1610,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) class->method.first = cols [MONO_TYPEDEF_METHOD_LIST] - 1; if (tt->rows > tidx){ - mono_metadata_decode_row (tt, tidx, cols_next, CSIZE (cols_next)); + mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE); class->field.last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1; class->method.last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1; } else { @@ -1329,9 +1641,182 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) if ((type_token = mono_metadata_nested_in_typedef (image, type_token))) class->nested_in = mono_class_create_from_typedef (image, type_token); + class->gen_params = mono_metadata_load_generic_params (image, class->type_token, &icount); + class->num_gen_params = icount; + + mono_loader_unlock (); + + return class; +} + +static char* +get_instantiation_name (const char *name, MonoGenericInst *ginst) +{ + GString *res = g_string_new (name); + const char *p; + int i; + MonoClass *argclass; + + p = strchr (name, '<'); + if (p) { + g_string_truncate (res, (p - name) + 1); + } else { + g_string_append_c (res, '<'); + } + for (i = 0; i < ginst->type_argc; ++i) { + if (i > 0) + g_string_append_c (res, ','); + argclass = mono_class_from_mono_type (ginst->type_argv [i]); + g_string_append (res, argclass->name); + } + g_string_append_c (res, '>'); + return g_string_free (res, FALSE); +} + +static void +mono_class_initialize_generic (MonoGenericInst *ginst, gboolean inflate_methods) +{ + MonoClass *klass, *gklass, *pklass; + + if (ginst->initialized || ginst->init_pending) + return; + + gklass = mono_class_from_mono_type (ginst->generic_type); + mono_class_init (gklass); + + klass = ginst->klass; + klass->name = get_instantiation_name (gklass->name, ginst); + + if (ginst->parent) + pklass = mono_class_from_mono_type (ginst->parent); + else + pklass = gklass->parent; + + mono_class_setup_parent (klass, pklass); + mono_class_setup_mono_type (klass); + + if (inflate_methods) { + int i; + + klass->field = gklass->field; + klass->method = gklass->method; + klass->methods = g_new0 (MonoMethod *, klass->method.count); + + for (i = 0; i < klass->method.count; i++) { + MonoGenericMethod *gmethod = g_new0 (MonoGenericMethod, 1); + + gmethod->klass = klass; + gmethod->generic_method = gklass->methods [i]; + gmethod->generic_inst = ginst; + + klass->methods [i] = mono_class_inflate_generic_method ( + gklass->methods [i], gmethod); + } + } + + ginst->initialized = TRUE; +} + +MonoClass* +mono_class_from_generic (MonoGenericInst *ginst) +{ + MonoClass *class, *gklass, *pklass; + + if (ginst->klass) { + mono_class_initialize_generic (ginst, TRUE); + return ginst->klass; + } + + mono_loader_lock (); + + gklass = mono_class_from_mono_type (ginst->generic_type); + mono_class_init (gklass); + + class = ginst->klass = g_malloc0 (sizeof (MonoClass)); + class->name_space = gklass->name_space; + class->name = get_instantiation_name (gklass->name, ginst); + class->image = gklass->image; + class->flags = gklass->flags; + + class->generic_inst = ginst; + + class->cast_class = class->element_class = class; + + mono_loader_unlock (); + return class; } +MonoClass * +mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gboolean is_mvar) +{ + MonoClass *klass, **ptr; + int count, pos, i; + + if (param->pklass) + return param->pklass; + + klass = param->pklass = g_new0 (MonoClass, 1); + + for (count = 0, ptr = param->constraints; ptr && *ptr; ptr++, count++) + ; + + pos = 0; + if ((count > 0) && !(param->constraints [0]->flags & TYPE_ATTRIBUTE_INTERFACE)) { + klass->parent = param->constraints [0]; + pos++; + } else + klass->parent = mono_defaults.object_class; + + if (count - pos > 0) { + klass->interface_count = count - pos; + klass->interfaces = g_new0 (MonoClass *, count - pos); + for (i = pos; i < count; i++) + klass->interfaces [i - pos] = param->constraints [i]; + } + + klass->name = g_strdup_printf (is_mvar ? "!!%d" : "!%d", param->num); + klass->name_space = ""; + klass->image = image; + klass->cast_class = klass->element_class = klass; + klass->enum_basetype = &klass->element_class->byval_arg; + klass->flags = TYPE_ATTRIBUTE_INTERFACE | TYPE_ATTRIBUTE_PUBLIC; + + klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR; + klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param; + klass->this_arg.byref = TRUE; + + mono_class_init (klass); + + return klass; +} + +static MonoClass * +my_mono_class_from_generic_parameter (MonoGenericParam *param, gboolean is_mvar) +{ + MonoClass *klass; + + if (param->pklass) + return param->pklass; + + klass = g_new0 (MonoClass, 1); + + klass->name = g_strdup_printf (is_mvar ? "!!%d" : "!%d", param->num); + klass->name_space = ""; + klass->image = mono_defaults.corlib; + klass->cast_class = klass->element_class = klass; + klass->enum_basetype = &klass->element_class->byval_arg; + klass->flags = TYPE_ATTRIBUTE_INTERFACE | TYPE_ATTRIBUTE_PUBLIC; + + klass->this_arg.type = klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR; + klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param; + klass->this_arg.byref = TRUE; + + mono_class_init (klass); + + return klass; +} + MonoClass * mono_ptr_class_get (MonoType *type) { @@ -1339,11 +1824,15 @@ mono_ptr_class_get (MonoType *type) MonoClass *el_class; static GHashTable *ptr_hash = NULL; + mono_loader_lock (); + if (!ptr_hash) - ptr_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + ptr_hash = g_hash_table_new (NULL, NULL); el_class = mono_class_from_mono_type (type); - if ((result = g_hash_table_lookup (ptr_hash, el_class))) + if ((result = g_hash_table_lookup (ptr_hash, el_class))) { + mono_loader_unlock (); return result; + } result = g_new0 (MonoClass, 1); result->parent = NULL; /* no parent for PTR types */ @@ -1365,6 +1854,8 @@ mono_ptr_class_get (MonoType *type) g_hash_table_insert (ptr_hash, el_class, result); + mono_loader_unlock (); + return result; } @@ -1374,11 +1865,15 @@ mono_fnptr_class_get (MonoMethodSignature *sig) MonoClass *result; static GHashTable *ptr_hash = NULL; + mono_loader_lock (); + if (!ptr_hash) - ptr_hash = g_hash_table_new (g_direct_hash, g_direct_equal); + ptr_hash = g_hash_table_new (NULL, NULL); - if ((result = g_hash_table_lookup (ptr_hash, sig))) + if ((result = g_hash_table_lookup (ptr_hash, sig))) { + mono_loader_unlock (); return result; + } result = g_new0 (MonoClass, 1); result->parent = NULL; /* no parent for PTR types */ @@ -1400,6 +1895,8 @@ mono_fnptr_class_get (MonoMethodSignature *sig) g_hash_table_insert (ptr_hash, sig, result); + mono_loader_unlock (); + return result; } @@ -1408,65 +1905,58 @@ mono_class_from_mono_type (MonoType *type) { switch (type->type) { case MONO_TYPE_OBJECT: - return mono_defaults.object_class; + return type->data.klass? type->data.klass: mono_defaults.object_class; case MONO_TYPE_VOID: - return mono_defaults.void_class; + return type->data.klass? type->data.klass: mono_defaults.void_class; case MONO_TYPE_BOOLEAN: - return mono_defaults.boolean_class; + return type->data.klass? type->data.klass: mono_defaults.boolean_class; case MONO_TYPE_CHAR: - return mono_defaults.char_class; + return type->data.klass? type->data.klass: mono_defaults.char_class; case MONO_TYPE_I1: - return mono_defaults.sbyte_class; + return type->data.klass? type->data.klass: mono_defaults.sbyte_class; case MONO_TYPE_U1: - return mono_defaults.byte_class; + return type->data.klass? type->data.klass: mono_defaults.byte_class; case MONO_TYPE_I2: - return mono_defaults.int16_class; + return type->data.klass? type->data.klass: mono_defaults.int16_class; case MONO_TYPE_U2: - return mono_defaults.uint16_class; + return type->data.klass? type->data.klass: mono_defaults.uint16_class; case MONO_TYPE_I4: - return mono_defaults.int32_class; + return type->data.klass? type->data.klass: mono_defaults.int32_class; case MONO_TYPE_U4: - return mono_defaults.uint32_class; + return type->data.klass? type->data.klass: mono_defaults.uint32_class; case MONO_TYPE_I: - return mono_defaults.int_class; + return type->data.klass? type->data.klass: mono_defaults.int_class; case MONO_TYPE_U: - return mono_defaults.uint_class; + return type->data.klass? type->data.klass: mono_defaults.uint_class; case MONO_TYPE_I8: - return mono_defaults.int64_class; + return type->data.klass? type->data.klass: mono_defaults.int64_class; case MONO_TYPE_U8: - return mono_defaults.uint64_class; + return type->data.klass? type->data.klass: mono_defaults.uint64_class; case MONO_TYPE_R4: - return mono_defaults.single_class; + return type->data.klass? type->data.klass: mono_defaults.single_class; case MONO_TYPE_R8: - return mono_defaults.double_class; + return type->data.klass? type->data.klass: mono_defaults.double_class; case MONO_TYPE_STRING: - return mono_defaults.string_class; + return type->data.klass? type->data.klass: mono_defaults.string_class; case MONO_TYPE_TYPEDBYREF: - return mono_defaults.typed_reference_class; + return type->data.klass? type->data.klass: mono_defaults.typed_reference_class; case MONO_TYPE_ARRAY: - return mono_array_class_get (type->data.array->type, type->data.array->rank); + return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE); case MONO_TYPE_PTR: return mono_ptr_class_get (type->data.type); case MONO_TYPE_FNPTR: return mono_fnptr_class_get (type->data.method); case MONO_TYPE_SZARRAY: - return mono_array_class_get (type->data.type, 1); + return mono_array_class_get (type->data.klass, 1); case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: return type->data.klass; - case MONO_TYPE_GENERICINST: - g_warning ("mono_class_from_type: implement me MONO_TYPE_GENERICINST"); - g_assert_not_reached (); - + return mono_class_from_generic (type->data.generic_inst); case MONO_TYPE_VAR: - g_warning ("mono_class_from_type: implement me MONO_TYPE_VAR"); - g_assert_not_reached (); - + return my_mono_class_from_generic_parameter (type->data.generic_param, FALSE); case MONO_TYPE_MVAR: - g_warning ("mono_class_from_type: implement me MONO_TYPE_MVAR"); - g_assert_not_reached (); - + return my_mono_class_from_generic_parameter (type->data.generic_param, TRUE); default: g_warning ("implement me 0x%02x\n", type->type); g_assert_not_reached (); @@ -1489,63 +1979,77 @@ mono_class_create_from_typespec (MonoImage *image, guint32 type_spec) switch (type->type) { case MONO_TYPE_ARRAY: - class = mono_array_class_get (type->data.array->type, type->data.array->rank); + class = mono_array_class_get (type->data.array->eklass, type->data.array->rank); break; case MONO_TYPE_SZARRAY: - class = mono_array_class_get (type->data.type, 1); + class = mono_array_class_get (type->data.klass, 1); break; case MONO_TYPE_PTR: class = mono_class_from_mono_type (type->data.type); break; + case MONO_TYPE_GENERICINST: + class = mono_class_from_generic (type->data.generic_inst); + break; default: /* it seems any type can be stored in TypeSpec as well */ class = mono_class_from_mono_type (type); break; } - mono_metadata_free_type (type); - return class; } /** - * mono_array_class_get: - * @element_type: element type + * mono_bounded_array_class_get: + * @element_class: element class * @rank: the dimension of the array class + * @bounded: whenever the array has non-zero bounds * * Returns: a class object describing the array with element type @element_type and * dimension @rank. */ MonoClass * -mono_array_class_get (MonoType *element_type, guint32 rank) +mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) { - MonoClass *eclass; MonoImage *image; MonoClass *class; MonoClass *parent = NULL; - GSList *list; + GSList *list, *rootlist; int nsize; char *name; + gboolean corlib_type = FALSE; - eclass = mono_class_from_mono_type (element_type); g_assert (rank <= 255); - parent = mono_defaults.array_class; - - if (!parent->inited) - mono_class_init (parent); + if (rank > 1) + /* bounded only matters for one-dimensional arrays */ + bounded = FALSE; image = eclass->image; - if ((list = g_hash_table_lookup (image->array_cache, element_type))) { + mono_loader_lock (); + + if ((rootlist = list = g_hash_table_lookup (image->array_cache, eclass))) { for (; list; list = list->next) { class = list->data; - if (class->rank == rank) + if ((class->rank == rank) && (class->byval_arg.type == (bounded ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) { + mono_loader_unlock (); return class; + } } } - - class = g_malloc0 (sizeof (MonoClass) + parent->vtable_size * sizeof (gpointer)); + + /* for the building corlib use System.Array from it */ + if (image->assembly && image->assembly->dynamic && strcmp (image->assembly_name, "mscorlib") == 0) { + parent = mono_class_from_name (image, "System", "Array"); + corlib_type = TRUE; + } else { + parent = mono_defaults.array_class; + if (!parent->inited) + mono_class_init (parent); + } + + class = g_malloc0 (sizeof (MonoClass)); class->image = image; class->name_space = eclass->name_space; @@ -1565,8 +2069,6 @@ mono_array_class_get (MonoType *element_type, guint32 rank) class->parent = parent; class->instance_size = mono_class_instance_size (class->parent); class->class_size = 0; - class->vtable_size = parent->vtable_size; - class->parent->subclasses = g_list_prepend (class->parent->subclasses, class); mono_class_setup_supertypes (class); class->rank = rank; @@ -1578,26 +2080,45 @@ mono_array_class_get (MonoType *element_type, guint32 rank) class->element_class = eclass; - if (rank > 1) { + if ((rank > 1) || bounded) { MonoArrayType *at = g_new0 (MonoArrayType, 1); class->byval_arg.type = MONO_TYPE_ARRAY; class->byval_arg.data.array = at; - at->type = &eclass->byval_arg; + at->eklass = eclass; at->rank = rank; /* FIXME: complete.... */ } else { - /* FIXME: this is not correct. the lbound could be >0 */ class->byval_arg.type = MONO_TYPE_SZARRAY; - class->byval_arg.data.type = &eclass->byval_arg; + class->byval_arg.data.klass = eclass; } class->this_arg = class->byval_arg; class->this_arg.byref = 1; + if (corlib_type) { + class->inited = 1; + } + + list = g_slist_append (rootlist, class); + g_hash_table_insert (image->array_cache, eclass, list); + + mono_loader_unlock (); - list = g_slist_append (list, class); - g_hash_table_insert (image->array_cache, &class->element_class->byval_arg, list); return class; } +/** + * mono_array_class_get: + * @element_class: element class + * @rank: the dimension of the array class + * + * Returns: a class object describing the array with element type @element_type and + * dimension @rank. + */ +MonoClass * +mono_array_class_get (MonoClass *eclass, guint32 rank) +{ + return mono_bounded_array_class_get (eclass, rank, FALSE); +} + /** * mono_class_instance_size: * @klass: a class @@ -1606,8 +2127,7 @@ mono_array_class_get (MonoType *element_type, guint32 rank) */ gint32 mono_class_instance_size (MonoClass *klass) -{ - +{ if (!klass->size_inited) mono_class_init (klass); @@ -1622,8 +2142,7 @@ mono_class_instance_size (MonoClass *klass) */ gint32 mono_class_min_align (MonoClass *klass) -{ - +{ if (!klass->size_inited) mono_class_init (klass); @@ -1665,8 +2184,7 @@ mono_class_value_size (MonoClass *klass, guint32 *align) */ gint32 mono_class_data_size (MonoClass *klass) -{ - +{ if (!klass->inited) mono_class_init (klass); @@ -1753,9 +2271,9 @@ mono_class_get_property_from_name (MonoClass *klass, const char *name) MonoClass * mono_class_get (MonoImage *image, guint32 type_token) { - MonoClass *class; + MonoClass *class = NULL; - if (image->assembly->dynamic) + if (image->dynamic) return mono_lookup_dynamic_token (image, type_token); switch (type_token & 0xff000000){ @@ -1803,38 +2321,6 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char return NULL; } -static MonoImage* -load_file_for_image (MonoImage *image, int fileidx) -{ - char *base_dir, *name; - MonoImage *res; - MonoTableInfo *t = &image->tables [MONO_TABLE_FILE]; - const char *fname; - guint32 fname_id; - - if (fileidx < 1 || fileidx > t->rows) - return NULL; - fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME); - fname = mono_metadata_string_heap (image, fname_id); - base_dir = g_path_get_dirname (image->name); - name = g_build_filename (base_dir, fname, NULL); - res = mono_image_open (name, NULL); - if (res) { - int i; - t = &res->tables [MONO_TABLE_MODULEREF]; - //g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); - res->assembly = image->assembly; - for (i = 0; i < t->rows; ++i) { - if (res->modules [i] && !res->modules [i]->assembly) - res->modules [i]->assembly = image->assembly; - } - mono_image_load_references (image, NULL); - } - g_free (name); - g_free (base_dir); - return res; -} - static MonoClass* return_nested_in (MonoClass *class, char *nested) { MonoClass *found; @@ -1861,7 +2347,7 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name { GHashTable *nspace_table; MonoImage *loaded_image; - guint32 token; + guint32 token = 0; MonoClass *class; char *nested; char buf [1024]; @@ -1877,36 +2363,39 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name name = buf; } + mono_loader_lock (); + nspace_table = g_hash_table_lookup (image->name_cache, name_space); - - if (!nspace_table || !(token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name)))) { + + if (nspace_table) + token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name)); + + mono_loader_unlock (); + + if (!token) + return NULL; + + if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) { MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE]; guint32 cols [MONO_EXP_TYPE_SIZE]; - int i; - - for (i = 0; i < t->rows; ++i) { - const char *ename, *enspace; - mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE); - ename = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]); - enspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]); - - if (strcmp (name, ename) == 0 && strcmp (name_space, enspace) == 0) { - guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION]; - if ((impl & IMPLEMENTATION_MASK) == IMPLEMENTATION_FILE) { - loaded_image = load_file_for_image (image, impl >> IMPLEMENTATION_BITS); - if (!loaded_image) - return NULL; - class = mono_class_from_name (loaded_image, name_space, name); - if (nested) - return return_nested_in (class, nested); - return class; - } else { - g_error ("not yet implemented"); - } - } + guint32 idx, impl; + + idx = mono_metadata_token_index (token); + + mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE); + + impl = cols [MONO_EXP_TYPE_IMPLEMENTATION]; + if ((impl & IMPLEMENTATION_MASK) == IMPLEMENTATION_FILE) { + loaded_image = mono_assembly_load_module (image->assembly, impl >> IMPLEMENTATION_BITS); + if (!loaded_image) + return NULL; + class = mono_class_from_name (loaded_image, name_space, name); + if (nested) + return return_nested_in (class, nested); + return class; + } else { + g_error ("not yet implemented"); } - /*g_warning ("token not found for %s.%s in image %s", name_space, name, image->name);*/ - return NULL; } token = MONO_TOKEN_TYPE_DEF | token; @@ -1937,7 +2426,87 @@ mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc, if (!(klass->flags & TYPE_ATTRIBUTE_INTERFACE) && mono_class_has_parent (klass, klassc)) return TRUE; } + + /* + * MS.NET thinks interfaces are a subclass of Object, so we think it as + * well. + */ + if (klassc == mono_defaults.object_class) + return TRUE; + + return FALSE; +} + +gboolean +mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) +{ + if (!klass->inited) + mono_class_init (klass); + + if (!oklass->inited) + mono_class_init (oklass); + + if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) { + if ((klass->interface_id <= oklass->max_interface_id) && + (oklass->interface_offsets [klass->interface_id] != -1)) + return TRUE; + } else + if (klass->rank) { + MonoClass *eclass, *eoclass; + + if (oklass->rank != klass->rank) + return FALSE; + + /* vectors vs. one dimensional arrays */ + if (oklass->byval_arg.type != klass->byval_arg.type) + return FALSE; + + eclass = klass->cast_class; + eoclass = oklass->cast_class; + + + /* + * a is b does not imply a[] is b[] when a is a valuetype, and + * b is a reference type. + */ + + if (eoclass->valuetype) { + if ((eclass == mono_defaults.enum_class) || + (eclass == mono_defaults.enum_class->parent) || + (eclass == mono_defaults.object_class)) + return FALSE; + } + + return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class); + } + else + if (klass == mono_defaults.object_class) + return TRUE; + + return mono_class_has_parent (oklass, klass); +} + +/* + * mono_class_needs_cctor_run: + * + * Determines whenever the class has a static constructor and whenever it + * needs to be called when executing CALLER. + */ +gboolean +mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller) +{ + int i; + MonoMethod *method; + for (i = 0; i < klass->method.count; ++i) { + method = klass->methods [i]; + if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && + (strcmp (".cctor", method->name) == 0)) { + if (caller == method) + return FALSE; + return TRUE; + } + } return FALSE; } @@ -1971,7 +2540,9 @@ handle_enum: case MONO_TYPE_STRING: case MONO_TYPE_OBJECT: case MONO_TYPE_SZARRAY: - case MONO_TYPE_ARRAY: + case MONO_TYPE_ARRAY: + case MONO_TYPE_VAR: + case MONO_TYPE_MVAR: return sizeof (gpointer); case MONO_TYPE_I8: case MONO_TYPE_U8: @@ -2004,7 +2575,7 @@ mono_array_element_size (MonoClass *ac) gpointer mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class) { - if (image->assembly->dynamic) { + if (image->dynamic) { gpointer obj = mono_lookup_dynamic_token (image, token); switch (token & 0xff000000) { @@ -2052,11 +2623,37 @@ mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class) class = mono_class_get (image, MONO_TOKEN_TYPE_DEF | type); mono_class_init (class); if (handle_class) - *handle_class = mono_defaults.fieldhandle_class; + *handle_class = mono_defaults.fieldhandle_class; return mono_class_get_field (class, token); } - case MONO_TOKEN_METHOD_DEF: - case MONO_TOKEN_MEMBER_REF: + case MONO_TOKEN_METHOD_DEF: { + MonoMethod *meth; + meth = mono_get_method (image, token, NULL); + if (handle_class) + *handle_class = mono_defaults.methodhandle_class; + return meth; + } + case MONO_TOKEN_MEMBER_REF: { + guint32 cols [MONO_MEMBERREF_SIZE]; + const char *sig; + mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE); + sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]); + mono_metadata_decode_blob_size (sig, &sig); + if (*sig == 0x6) { /* it's a field */ + MonoClass *klass; + MonoClassField *field; + field = mono_field_from_token (image, token, &klass); + if (handle_class) + *handle_class = mono_defaults.fieldhandle_class; + return field; + } else { + MonoMethod *meth; + meth = mono_get_method (image, token, NULL); + if (handle_class) + *handle_class = mono_defaults.methodhandle_class; + return meth; + } + } default: g_warning ("Unknown token 0x%08x in ldtoken", token); break; @@ -2081,3 +2678,6 @@ mono_lookup_dynamic_token (MonoImage *image, guint32 token) { return lookup_dynamic (image, token); } + + +