X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fclass.c;h=1d5f21049c86afb332aa871b6fb0e247e488f095;hb=6de2b94648409d1eff3e5b8d3765e9b6936e87c3;hp=858c601c634c00c6798c6cb977d72bd98c09a730;hpb=adfe85ff804a7dcc36407d039840c3f6d1f1e450;p=mono.git diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 858c601c634..1d5f21049c8 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -34,17 +34,29 @@ #include #include #include +#include #include MonoStats mono_stats; gboolean mono_print_vtable = FALSE; +/* + * Controls whenever mono_class_init () constructs a generic vtable. This is TRUE by + * default to avoid breaking embedding apps, but set to FALSE by the runtime executable + * startup code. + */ +gboolean mono_setup_vtable_in_class_init = TRUE; + /* Function supplied by the runtime to find classes by name using information from the AOT file */ static MonoGetClassFromName get_class_from_name = NULL; static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token); static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res); +static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass); +static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags); +static int generic_array_methods (MonoClass *class); +static void setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos); void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL; void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL; @@ -100,7 +112,7 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) MonoClass *enclosing = mono_class_from_typeref (image, MONO_TOKEN_TYPE_REF | idx); GList *tmp; - if (enclosing->inited) { + if (enclosing->nested_classes_inited) { /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */ for (tmp = enclosing->nested_classes; tmp; tmp = tmp->next) { res = tmp->data; @@ -121,7 +133,7 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1); } } - g_warning ("TypeRef ResolutionScope not yet handled (%d)", idx); + g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name); return NULL; } case MONO_RESOLTION_SCOPE_ASSEMBLYREF: @@ -148,29 +160,48 @@ mono_class_from_typeref (MonoImage *image, guint32 type_token) return mono_class_from_name (image->references [idx - 1]->image, nspace, name); } + +static void * +mono_mempool_dup (MonoMemPool *mp, void *data, guint size) +{ + void *res = mono_mempool_alloc (mp, size); + memcpy (res, data, size); + return res; +} + /* Copy everything mono_metadata_free_array free. */ MonoArrayType * -mono_dup_array_type (MonoArrayType *a) +mono_dup_array_type (MonoMemPool *mp, MonoArrayType *a) { - a = g_memdup (a, sizeof (MonoArrayType)); - if (a->sizes) - a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int)); - if (a->lobounds) - a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int)); + if (mp) { + mono_loader_lock (); + a = mono_mempool_dup (mp, a, sizeof (MonoArrayType)); + if (a->sizes) + a->sizes = mono_mempool_dup (mp, a->sizes, a->numsizes * sizeof (int)); + if (a->lobounds) + a->lobounds = mono_mempool_dup (mp, a->lobounds, a->numlobounds * sizeof (int)); + mono_loader_unlock (); + } else { + a = g_memdup (a, sizeof (MonoArrayType)); + if (a->sizes) + a->sizes = g_memdup (a->sizes, a->numsizes * sizeof (int)); + if (a->lobounds) + a->lobounds = g_memdup (a->lobounds, a->numlobounds * sizeof (int)); + } return a; } /* Copy everything mono_metadata_free_method_signature free. */ MonoMethodSignature* -mono_metadata_signature_deep_dup (MonoMethodSignature *sig) +mono_metadata_signature_deep_dup (MonoMemPool *mp, MonoMethodSignature *sig) { int i; - sig = mono_metadata_signature_dup (sig); + sig = mono_metadata_signature_dup_full (mp, sig); - sig->ret = mono_metadata_type_dup (NULL, sig->ret); + sig->ret = mono_metadata_type_dup (mp, sig->ret); for (i = 0; i < sig->param_count; ++i) - sig->params [i] = mono_metadata_type_dup (NULL, sig->params [i]); + sig->params [i] = mono_metadata_type_dup (mp, sig->params [i]); return sig; } @@ -181,11 +212,12 @@ _mono_type_get_assembly_name (MonoClass *klass, GString *str) MonoAssembly *ta = klass->image->assembly; g_string_append_printf ( - str, ", %s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s", + str, ", %s, Version=%d.%d.%d.%d, Culture=%s, PublicKeyToken=%s%s", ta->aname.name, ta->aname.major, ta->aname.minor, ta->aname.build, ta->aname.revision, ta->aname.culture && *ta->aname.culture? ta->aname.culture: "neutral", - ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null"); + ta->aname.public_key_token [0] ? (char *)ta->aname.public_key_token : "null", + (ta->aname.flags & ASSEMBLYREF_RETARGETABLE_FLAG) ? ", Retargetable=Yes" : ""); } static inline void @@ -447,7 +479,7 @@ mono_class_is_open_constructed_type (MonoType *t) } static MonoType* -inflate_generic_type (MonoType *type, MonoGenericContext *context) +inflate_generic_type (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context) { switch (type->type) { case MONO_TYPE_MVAR: { @@ -464,7 +496,7 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context) * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the * ->byref and ->attrs from @type are propagated to the returned type. */ - nt = mono_metadata_type_dup (NULL, inst->type_argv [num]); + nt = mono_metadata_type_dup (mempool, inst->type_argv [num]); nt->byref = type->byref; nt->attrs = type->attrs; return nt; @@ -477,27 +509,27 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context) return NULL; if (num >= inst->type_argc) g_error ("VAR %d (%s) cannot be expanded in this context with %d instantiations", num, type->data.generic_param->name, inst->type_argc); - nt = mono_metadata_type_dup (NULL, inst->type_argv [num]); + nt = mono_metadata_type_dup (mempool, inst->type_argv [num]); nt->byref = type->byref; nt->attrs = type->attrs; return nt; } case MONO_TYPE_SZARRAY: { MonoClass *eclass = type->data.klass; - MonoType *nt, *inflated = inflate_generic_type (&eclass->byval_arg, context); + MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context); if (!inflated) return NULL; - nt = mono_metadata_type_dup (NULL, type); + nt = mono_metadata_type_dup (mempool, type); nt->data.klass = mono_class_from_mono_type (inflated); mono_metadata_free_type (inflated); return nt; } case MONO_TYPE_ARRAY: { MonoClass *eclass = type->data.array->eklass; - MonoType *nt, *inflated = inflate_generic_type (&eclass->byval_arg, context); + MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context); if (!inflated) return NULL; - nt = mono_metadata_type_dup (NULL, type); + nt = mono_metadata_type_dup (mempool, type); nt->data.array = g_memdup (nt->data.array, sizeof (MonoArrayType)); nt->data.array->eklass = mono_class_from_mono_type (inflated); mono_metadata_free_type (inflated); @@ -517,7 +549,7 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context) if (gclass == type->data.generic_class) return NULL; - nt = mono_metadata_type_dup (NULL, type); + nt = mono_metadata_type_dup (mempool, type); nt->data.generic_class = gclass; return nt; } @@ -539,7 +571,7 @@ inflate_generic_type (MonoType *type, MonoGenericContext *context) gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic); - nt = mono_metadata_type_dup (NULL, type); + nt = mono_metadata_type_dup (mempool, type); nt->type = MONO_TYPE_GENERICINST; nt->data.generic_class = gclass; return nt; @@ -563,27 +595,48 @@ mono_class_get_context (MonoClass *class) } /* - * mono_class_inflate_generic_type: + * mono_class_inflate_generic_type_with_mempool: + * @mempool: a mempool * @type: a type * @context: a generics context * - * Instantiate the generic type @type, using the generics context @context. - * - * Returns: the instantiated type. The returned MonoType is allocated on the heap and is - * owned by the caller. + * The same as mono_class_inflate_generic_type, but allocates the MonoType + * from mempool if it is non-NULL. If it is NULL, the MonoType is + * allocated on the heap and is owned by the caller. */ MonoType* -mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context) +mono_class_inflate_generic_type_with_mempool (MonoMemPool *mempool, MonoType *type, MonoGenericContext *context) { - MonoType *inflated = inflate_generic_type (type, context); + MonoType *inflated = NULL; + + if (context) + inflated = inflate_generic_type (mempool, type, context); if (!inflated) - return mono_metadata_type_dup (NULL, type); + return mono_metadata_type_dup (mempool, type); mono_stats.inflated_type_count++; return inflated; } +/* + * mono_class_inflate_generic_type: + * @type: a type + * @context: a generics context + * + * If @type is a generic type and @context is not NULL, instantiate it using the + * generics context @context. + * + * Returns: the instantiated type or a copy of @type. The returned MonoType is allocated + * on the heap and is owned by the caller. + */ +MonoType* +mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context) +{ + return mono_class_inflate_generic_type_with_mempool (NULL, type, context); +} + + static MonoGenericContext inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with) { @@ -632,6 +685,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin MonoMethodInflated *iresult, *cached; MonoMethodSignature *sig; MonoGenericContext tmp_context; + gboolean is_mb_open = FALSE; /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */ while (method->is_inflated) { @@ -647,16 +701,58 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin method = imethod->declaring; } - if (!method->generic_container && !method->klass->generic_container) + if (!method->is_generic && !method->klass->generic_container) return method; - mono_stats.inflated_method_count++; + /* + * The reason for this hack is to fix the behavior of inflating generic methods that come from a MethodBuilder. + * What happens is that instantiating a generic MethodBuilder with its own arguments should create a diferent object. + * This is opposite to the way non-SRE MethodInfos behave. + * + * This happens, for example, when we want to emit a recursive generic method. Given the following C# code: + * + * void Example () { + * Example (); + * } + * + * In Example, the method token must be encoded as: "void Example()" + * + * The reference to the first generic argument, "!!0", must be explicit otherwise it won't be inflated + * properly. To get that we need to inflate the MethodBuilder with its own arguments. + * + * On the other hand, inflating a non-SRE generic method with its own arguments should + * return itself. For example: + * + * MethodInfo m = ... //m is a generic method definition + * MethodInfo res = m.MakeGenericMethod (m.GetGenericArguments ()); + * res == m + * + * To allow such scenarios we must allow inflation of MethodBuilder to happen in a diferent way than + * what happens with regular methods. + * + * There is one last touch to this madness, once a TypeBuilder is finished, IOW CreateType() is called, + * everything should behave like a regular type or method. + * + */ + is_mb_open = method->is_generic && + method->klass->image->dynamic && !method->klass->wastypebuilder && /* that is a MethodBuilder from an unfinished TypeBuilder */ + context->method_inst == mono_method_get_generic_container (method)->context.method_inst; /* and it's been instantiated with its own arguments. */ + iresult = g_new0 (MonoMethodInflated, 1); iresult->context = *context; iresult->declaring = method; + iresult->is_mb_open = is_mb_open; - if (!context->method_inst && method->generic_container) - iresult->context.method_inst = method->generic_container->context.method_inst; + if (!context->method_inst && method->is_generic) + iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst; + + if (!context->class_inst) { + g_assert (!iresult->declaring->klass->generic_class); + if (iresult->declaring->klass->generic_container) + iresult->context.class_inst = iresult->declaring->klass->generic_container->context.class_inst; + else if (iresult->declaring->klass->generic_class) + iresult->context.class_inst = iresult->declaring->klass->generic_class->context.class_inst; + } mono_loader_lock (); cached = mono_method_inflated_lookup (iresult, FALSE); @@ -666,6 +762,8 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin return (MonoMethod*)cached; } + mono_stats.inflated_method_count++; + sig = mono_method_signature (method); if (sig->pinvoke) { memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke)); @@ -675,13 +773,19 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin } result = (MonoMethod *) iresult; - result->is_inflated = 1; + result->is_inflated = TRUE; + result->is_generic = FALSE; result->signature = NULL; - if (context->method_inst) - result->generic_container = NULL; + if (!context->method_inst) { + /* Set the generic_container of the result to the generic_container of method */ + MonoGenericContainer *generic_container = mono_method_get_generic_container (method); - /* Due to the memcpy above, !context->method_inst => result->generic_container == method->generic_container */ + if (generic_container) { + result->is_generic = 1; + mono_method_set_generic_container (result, generic_container); + } + } if (!klass_hint || !klass_hint->generic_class || klass_hint->generic_class->container_class != method->klass || @@ -692,7 +796,7 @@ mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hin result->klass = klass_hint; if (!result->klass) { - MonoType *inflated = inflate_generic_type (&method->klass->byval_arg, context); + MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context); result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass; if (inflated) mono_metadata_free_type (inflated); @@ -724,6 +828,45 @@ mono_method_get_context (MonoMethod *method) return &imethod->context; } +/* + * mono_method_get_generic_container: + * + * Returns the generic container of METHOD, which should be a generic method definition. + * Returns NULL if METHOD is not a generic method definition. + * LOCKING: Acquires the loader lock. + */ +MonoGenericContainer* +mono_method_get_generic_container (MonoMethod *method) +{ + MonoGenericContainer *container; + + if (!method->is_generic) + return NULL; + + mono_loader_lock (); + container = mono_property_hash_lookup (method->klass->image->property_hash, method, MONO_METHOD_PROP_GENERIC_CONTAINER); + mono_loader_unlock (); + g_assert (container); + + return container; +} + +/* + * mono_method_set_generic_container: + * + * Sets the generic container of METHOD to CONTAINER. + * LOCKING: Acquires the loader lock. + */ +void +mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container) +{ + g_assert (method->is_generic); + + mono_loader_lock (); + mono_property_hash_insert (method->klass->image->property_hash, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container); + mono_loader_unlock (); +} + /** * mono_class_find_enum_basetype: * @class: The enum class @@ -768,6 +911,7 @@ mono_class_find_enum_basetype (MonoClass *class) if (!ftype) return NULL; if (class->generic_class) { + //FIXME do we leak here? ftype = mono_class_inflate_generic_type (ftype, mono_class_get_context (class)); ftype->attrs = cols [MONO_FIELD_FLAGS]; } @@ -803,6 +947,16 @@ mono_class_setup_fields (MonoClass *class) if (class->size_inited) return; + if (class->generic_class && class->generic_class->container_class->image->dynamic && !class->generic_class->container_class->wastypebuilder) { + /* + * This happens when a generic instance of an unfinished generic typebuilder + * is used as an element type for creating an array type. We can't initialize + * the fields of this class using the fields of gklass, since gklass is not + * finished yet, fields could be added to it later. + */ + return; + } + if (class->generic_class) { MonoClass *gklass = class->generic_class->container_class; mono_class_setup_fields (gklass); @@ -853,7 +1007,7 @@ mono_class_setup_fields (MonoClass *class) /* Prevent infinite loops if the class references itself */ class->size_inited = 1; - class->fields = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassField) * top); + class->fields = mono_image_alloc0 (class->image, sizeof (MonoClassField) * top); if (class->generic_container) { container = class->generic_container; @@ -881,7 +1035,8 @@ mono_class_setup_fields (MonoClass *class) ifield->generic_type = gfield->type; field->name = gfield->name; field->generic_info = ifield; - field->type = mono_class_inflate_generic_type (gfield->type, mono_class_get_context (class)); + /*This memory must come from the image mempool as we don't have a chance to free it.*/ + field->type = mono_class_inflate_generic_type_with_mempool (class->image->mempool, gfield->type, mono_class_get_context (class)); field->type->attrs = gfield->type->attrs; if (mono_field_is_deleted (field)) continue; @@ -930,6 +1085,8 @@ mono_class_setup_fields (MonoClass *class) blittable = FALSE; } else { MonoClass *field_class = mono_class_from_mono_type (field->type); + if (field_class) + mono_class_setup_fields (field_class); if (!field_class || !field_class->blittable) blittable = FALSE; } @@ -1212,7 +1369,8 @@ mono_class_layout_fields (MonoClass *class) continue; size = mono_type_size (field->type, &align); - + class->min_align = MAX (align, class->min_align); + /* * When we get here, field->offset is already set by the * loader (for either runtime fields or fields loaded from metadata). @@ -1237,18 +1395,15 @@ mono_class_layout_fields (MonoClass *class) break; } -#if NO_UNALIGNED_ACCESS if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { /* - * For small structs, set min_align to at least the struct size, since the - * JIT memset/memcpy code assumes this and generates unaligned accesses - * otherwise. See #78990 for a testcase. - * FIXME: Fix the memset/memcpy code instead. + * For small structs, set min_align to at least the struct size to improve + * performance, and since the JIT memset/memcpy code assumes this and generates + * unaligned accesses otherwise. See #78990 for a testcase. */ if (class->instance_size <= sizeof (MonoObject) + sizeof (gpointer)) class->min_align = MAX (class->min_align, class->instance_size - sizeof (MonoObject)); } -#endif class->size_inited = 1; @@ -1274,6 +1429,27 @@ mono_class_layout_fields (MonoClass *class) } } +static MonoMethod* +create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig) +{ + MonoMethod *method; + + method = (MonoMethod *) mono_image_alloc0 (class->image, sizeof (MonoMethodPInvoke)); + method->klass = class; + method->flags = METHOD_ATTRIBUTE_PUBLIC; + method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL; + method->signature = sig; + method->name = name; + method->slot = -1; + /* .ctor */ + if (name [0] == '.') { + method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME; + } else { + method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME; + } + return method; +} + /* * mono_class_setup_methods: * @class: a class @@ -1314,13 +1490,78 @@ mono_class_setup_methods (MonoClass *class) methods [i] = mono_class_inflate_generic_method_full ( gklass->methods [i], class, mono_class_get_context (class)); } + } else if (class->rank) { + MonoMethod *amethod; + MonoMethodSignature *sig; + int count_generic = 0, first_generic = 0; + int method_num = 0; + + class->method.count = 3 + (class->rank > 1? 2: 1); + + if (class->interface_count) { + count_generic = generic_array_methods (class); + first_generic = class->method.count; + class->method.count += class->interface_count * count_generic; + } + + methods = mono_image_alloc0 (class->image, sizeof (MonoMethod*) * class->method.count); + + sig = mono_metadata_signature_alloc (class->image, class->rank); + sig->ret = &mono_defaults.void_class->byval_arg; + sig->pinvoke = TRUE; + sig->hasthis = TRUE; + for (i = 0; i < class->rank; ++i) + sig->params [i] = &mono_defaults.int32_class->byval_arg; + + amethod = create_array_method (class, ".ctor", sig); + methods [method_num++] = amethod; + if (class->rank > 1) { + sig = mono_metadata_signature_alloc (class->image, class->rank * 2); + sig->ret = &mono_defaults.void_class->byval_arg; + sig->pinvoke = TRUE; + sig->hasthis = TRUE; + for (i = 0; i < class->rank * 2; ++i) + sig->params [i] = &mono_defaults.int32_class->byval_arg; + + amethod = create_array_method (class, ".ctor", sig); + methods [method_num++] = amethod; + } + /* element Get (idx11, [idx2, ...]) */ + sig = mono_metadata_signature_alloc (class->image, class->rank); + sig->ret = &class->element_class->byval_arg; + sig->pinvoke = TRUE; + sig->hasthis = TRUE; + for (i = 0; i < class->rank; ++i) + sig->params [i] = &mono_defaults.int32_class->byval_arg; + amethod = create_array_method (class, "Get", sig); + methods [method_num++] = amethod; + /* element& Address (idx11, [idx2, ...]) */ + sig = mono_metadata_signature_alloc (class->image, class->rank); + sig->ret = &class->element_class->this_arg; + sig->pinvoke = TRUE; + sig->hasthis = TRUE; + for (i = 0; i < class->rank; ++i) + sig->params [i] = &mono_defaults.int32_class->byval_arg; + amethod = create_array_method (class, "Address", sig); + methods [method_num++] = amethod; + /* void Set (idx11, [idx2, ...], element) */ + sig = mono_metadata_signature_alloc (class->image, class->rank + 1); + sig->ret = &mono_defaults.void_class->byval_arg; + sig->pinvoke = TRUE; + sig->hasthis = TRUE; + for (i = 0; i < class->rank; ++i) + sig->params [i] = &mono_defaults.int32_class->byval_arg; + sig->params [i] = &class->element_class->byval_arg; + amethod = create_array_method (class, "Set", sig); + methods [method_num++] = amethod; + + for (i = 0; i < class->interface_count; i++) + setup_generic_array_ifaces (class, class->interfaces [i], methods, first_generic + i * count_generic); } else { - methods = mono_mempool_alloc (class->image->mempool, sizeof (MonoMethod*) * class->method.count); + methods = mono_image_alloc (class->image, sizeof (MonoMethod*) * class->method.count); for (i = 0; i < class->method.count; ++i) { int idx = mono_metadata_translate_token_index (class->image, MONO_TABLE_METHOD, class->method.first + i + 1); methods [i] = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | idx, class); - if (class->valuetype && methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED && !(methods [i]->flags & MONO_METHOD_ATTR_STATIC)) - mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); } } @@ -1328,7 +1569,9 @@ mono_class_setup_methods (MonoClass *class) for (i = 0; i < class->method.count; ++i) methods [i]->slot = i; - /* Leave this assignment as the last op in this function */ + /* Needed because of the double-checking locking pattern */ + mono_memory_barrier (); + class->methods = methods; if (mono_debugger_class_loaded_methods_func) @@ -1337,6 +1580,39 @@ mono_class_setup_methods (MonoClass *class) mono_loader_unlock (); } +/* + * mono_class_get_method_by_index: + * + * Returns class->methods [index], initializing class->methods if neccesary. + * + * LOCKING: Acquires the loader lock. + */ +MonoMethod* +mono_class_get_method_by_index (MonoClass *class, int index) +{ + /* Avoid calling setup_methods () if possible */ + if (class->generic_class && !class->methods) { + MonoClass *gklass = class->generic_class->container_class; + MonoMethod *m; + + m = mono_class_inflate_generic_method_full ( + gklass->methods [index], class, mono_class_get_context (class)); + /* + * If setup_methods () is called later for this class, no duplicates are created, + * since inflate_generic_method guarantees that only one instance of a method + * is created for each context. + */ + /* + mono_class_setup_methods (class); + g_assert (m == class->methods [index]); + */ + return m; + } else { + mono_class_setup_methods (class); + g_assert (index >= 0 && index < class->method.count); + return class->methods [index]; + } +} static void mono_class_setup_properties (MonoClass *class) @@ -1388,7 +1664,7 @@ mono_class_setup_properties (MonoClass *class) if (class->property.count) mono_class_setup_methods (class); - properties = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoProperty) * class->property.count); + properties = mono_image_alloc0 (class->image, sizeof (MonoProperty) * class->property.count); for (i = class->property.first; i < last; ++i) { mono_metadata_decode_table_row (class->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE); properties [i - class->property.first].parent = class; @@ -1420,6 +1696,8 @@ mono_class_setup_properties (MonoClass *class) } } } + /*Flush any pending writes as we do double checked locking on class->properties */ + mono_memory_barrier (); /* Leave this assignment as the last op in the function */ class->properties = properties; @@ -1498,7 +1776,7 @@ mono_class_setup_events (MonoClass *class) if (class->event.count) mono_class_setup_methods (class); - events = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoEvent) * class->event.count); + events = mono_image_alloc0 (class->image, sizeof (MonoEvent) * class->event.count); for (i = class->event.first; i < last; ++i) { MonoEvent *event = &events [i - class->event.first]; @@ -1549,6 +1827,9 @@ mono_class_setup_events (MonoClass *class) } } } + /*Flush any pending writes as we do double checked locking on class->properties */ + mono_memory_barrier (); + /* Leave this assignment as the last op in the function */ class->events = events; @@ -1662,73 +1943,6 @@ mono_class_get_implemented_interfaces (MonoClass *klass) return res; } -typedef struct _IOffsetInfo IOffsetInfo; -struct _IOffsetInfo { - IOffsetInfo *next; - int size; - int next_free; - int data [MONO_ZERO_LEN_ARRAY]; -}; - -static IOffsetInfo *cached_offset_info = NULL; -static int next_offset_info_size = 128; - -static int* -cache_interface_offsets (int max_iid, int *data) -{ - IOffsetInfo *cached_info; - int *cached; - int new_size; - for (cached_info = cached_offset_info; cached_info; cached_info = cached_info->next) { - cached = cached_info->data; - while (cached < cached_info->data + cached_info->size && *cached) { - if (*cached == max_iid) { - int i, matched = TRUE; - cached++; - for (i = 0; i < max_iid; ++i) { - if (cached [i] != data [i]) { - matched = FALSE; - break; - } - } - if (matched) - return cached; - cached += max_iid; - } else { - cached += *cached + 1; - } - } - } - /* find a free slot */ - for (cached_info = cached_offset_info; cached_info; cached_info = cached_info->next) { - if (cached_info->size - cached_info->next_free >= max_iid + 1) { - cached = &cached_info->data [cached_info->next_free]; - *cached++ = max_iid; - memcpy (cached, data, max_iid * sizeof (int)); - cached_info->next_free += max_iid + 1; - return cached; - } - } - /* allocate a new chunk */ - if (max_iid + 1 < next_offset_info_size) { - new_size = next_offset_info_size; - if (next_offset_info_size < 4096) - next_offset_info_size += next_offset_info_size >> 2; - } else { - new_size = max_iid + 1; - } - cached_info = g_malloc0 (sizeof (IOffsetInfo) + sizeof (int) * new_size); - cached_info->size = new_size; - /*g_print ("allocated %d offset entries at %p (total: %d)\n", new_size, cached_info->data, offset_info_total_size);*/ - cached = &cached_info->data [0]; - *cached++ = max_iid; - memcpy (cached, data, max_iid * sizeof (int)); - cached_info->next_free += max_iid + 1; - cached_info->next = cached_offset_info; - cached_offset_info = cached_info; - return cached; -} - static int compare_interface_ids (const void *p_key, const void *p_element) { const MonoClass *key = p_key; @@ -1852,6 +2066,8 @@ get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enume "System.Collections.Generic", "IEnumerator`1"); } + mono_class_init (eclass); + /* * Arrays in 2.0 need to implement a number of generic interfaces * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending @@ -2005,8 +2221,8 @@ setup_interface_offsets (MonoClass *class, int cur_slot) /* * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator - * implicit innterfaces have the property that they are assigned the same slot in the vtables - * for compatible interfaces + * implicit interfaces have the property that they are assigned the same slot in the + * vtables for compatible interfaces */ array_interfaces = get_implicit_generic_array_interfaces (class, &num_array_interfaces, &is_enumerator); @@ -2132,18 +2348,27 @@ setup_interface_offsets (MonoClass *class, int cur_slot) interface_offsets_count ++; } } - class->interface_offsets_count = interface_offsets_count; - class->interfaces_packed = mono_mempool_alloc (class->image->mempool, sizeof (MonoClass*) * interface_offsets_count); - class->interface_offsets_packed = mono_mempool_alloc (class->image->mempool, sizeof (int) * interface_offsets_count); - class->interface_bitmap = mono_mempool_alloc0 (class->image->mempool, (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0)); - for (interface_offsets_count = 0, i = 0; i <= max_iid; i++) { - if (interface_offsets_full [i] != -1) { - class->interface_bitmap [i >> 3] |= (1 << (i & 7)); - class->interfaces_packed [interface_offsets_count] = interfaces_full [i]; - class->interface_offsets_packed [interface_offsets_count] = interface_offsets_full [i]; - /*if (num_array_interfaces) - g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/ - interface_offsets_count ++; + + /* + * We might get called twice: once from mono_class_init () then once from + * mono_class_setup_vtable (). + */ + if (class->interfaces_packed) { + g_assert (class->interface_offsets_count == interface_offsets_count); + } else { + class->interface_offsets_count = interface_offsets_count; + class->interfaces_packed = mono_image_alloc (class->image, sizeof (MonoClass*) * interface_offsets_count); + class->interface_offsets_packed = mono_image_alloc (class->image, sizeof (guint16) * interface_offsets_count); + class->interface_bitmap = mono_image_alloc0 (class->image, (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0)); + for (interface_offsets_count = 0, i = 0; i <= max_iid; i++) { + if (interface_offsets_full [i] != -1) { + class->interface_bitmap [i >> 3] |= (1 << (i & 7)); + class->interfaces_packed [interface_offsets_count] = interfaces_full [i]; + class->interface_offsets_packed [interface_offsets_count] = interface_offsets_full [i]; + /*if (num_array_interfaces) + g_print ("type %s has %s offset at %d\n", mono_type_get_name_full (&class->byval_arg, 0), mono_type_get_name_full (&interfaces_full [i]->byval_arg, 0), interface_offsets_full [i]);*/ + interface_offsets_count ++; + } } } @@ -2169,7 +2394,19 @@ mono_class_setup_interface_offsets (MonoClass *class) mono_loader_unlock (); } - + +/* + * mono_class_setup_vtable: + * + * Creates the generic vtable of CLASS. + * Initializes the following fields in MonoClass: + * - vtable + * - vtable_size + * Plus all the fields initialized by setup_interface_offsets (). + * If there is an error during vtable construction, class->exception_type is set. + * + * LOCKING: Acquires the loader lock. + */ void mono_class_setup_vtable (MonoClass *class) { @@ -2183,6 +2420,7 @@ mono_class_setup_vtable (MonoClass *class) if (class->vtable) return; + /* This sets method->slot for all methods if this is an interface */ mono_class_setup_methods (class); if (MONO_CLASS_IS_INTERFACE (class)) @@ -2249,10 +2487,8 @@ check_core_clr_override_method (MonoClass *class, MonoMethod *override, MonoMeth MonoSecurityCoreCLRLevel override_level = mono_security_core_clr_method_level (override, FALSE); MonoSecurityCoreCLRLevel base_level = mono_security_core_clr_method_level (base, FALSE); - if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL) { - class->exception_type = MONO_EXCEPTION_TYPE_LOAD; - class->exception_data = NULL; - } + if (override_level != base_level && base_level == MONO_SECURITY_CORE_CLR_CRITICAL) + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); } @@ -2260,9 +2496,9 @@ static int __use_new_interface_vtable_code = -1; static gboolean use_new_interface_vtable_code (void) { if (__use_new_interface_vtable_code == -1) { - char *env_var = getenv ("USE_NEW_INTERFACE_VTABLE_CODE"); + char *env_var = getenv ("MONO_USE_NEW_INTERFACE_VTABLE_CODE"); if (env_var == NULL) { - __use_new_interface_vtable_code = FALSE; + __use_new_interface_vtable_code = TRUE; } else { if ((strcmp (env_var, "0") == 0) || (strcmp (env_var, "false") == 0) || (strcmp (env_var, "FALSE") == 0)) { __use_new_interface_vtable_code = FALSE; @@ -2632,6 +2868,8 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o ic = class->interfaces_packed [i]; ic_offset = mono_class_interface_offset (class, ic); + + mono_class_setup_methods (ic); // Check if this interface is explicitly implemented (instead of just inherited) if (parent != NULL) { @@ -2653,6 +2891,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o int im_slot = ic_offset + im->slot; MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL; + if (im->flags & METHOD_ATTRIBUTE_STATIC) + continue; + // If there is an explicit implementation, just use it right away, // otherwise look for a matching method if (override_im == NULL) { @@ -2717,6 +2958,9 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o MonoMethod *im = ic->methods [im_index]; int im_slot = ic_offset + im->slot; + if (im->flags & METHOD_ATTRIBUTE_STATIC) + continue; + TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n", im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL))); if (vtable [im_slot] == NULL) { @@ -3071,15 +3315,31 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o mono_class_init (gklass); class->vtable_size = MAX (gklass->vtable_size, cur_slot); - } else + } else { + /* Check that the vtable_size value computed in mono_class_init () is correct */ + if (class->vtable_size) + g_assert (cur_slot == class->vtable_size); class->vtable_size = cur_slot; + } + + /* FIXME: only do this if the class is actually sharable */ + if (class->valuetype && (class->generic_class || class->generic_container) && + mono_class_generic_sharing_enabled (class)) { + for (i = 0; i < max_vtsize; ++i) { + if (vtable [i] && vtable [i]->wrapper_type == MONO_WRAPPER_NONE) + vtable [i] = mono_marshal_get_static_rgctx_invoke (vtable [i]); + } + } /* Try to share the vtable with our parent. */ if (class->parent && (class->parent->vtable_size == class->vtable_size) && (memcmp (class->parent->vtable, vtable, sizeof (gpointer) * class->vtable_size) == 0)) { + mono_memory_barrier (); class->vtable = class->parent->vtable; } else { - class->vtable = mono_mempool_alloc0 (class->image->mempool, sizeof (gpointer) * class->vtable_size); - memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size); + MonoMethod **tmp = mono_image_alloc0 (class->image, sizeof (gpointer) * class->vtable_size); + memcpy (tmp, vtable, sizeof (gpointer) * class->vtable_size); + mono_memory_barrier (); + class->vtable = tmp; } DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE)); @@ -3129,6 +3389,25 @@ mono_class_setup_vtable_general (MonoClass *class, MonoMethod **overrides, int o } } +/** + * mono_method_get_vtable_index: + * @method: a method + * + * Returns the index into the runtime vtable to access the method or, + * in the case of a virtual generic method, the virtual generic method + * thunk. + */ +int +mono_method_get_vtable_index (MonoMethod *method) +{ + if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) { + MonoMethodInflated *imethod = (MonoMethodInflated*)method; + if (imethod->declaring->is_generic) + return imethod->declaring->slot; + } + return method->slot; +} + static MonoMethod *default_ghc = NULL; static MonoMethod *default_finalize = NULL; static int finalize_slot = -1; @@ -3213,7 +3492,7 @@ generic_array_methods (MonoClass *class) g_assert_not_reached (); } - name = mono_mempool_alloc (mono_defaults.corlib->mempool, strlen (iname) + strlen (mname) + 1); + name = mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1); strcpy (name, iname); strcpy (name + strlen (iname), mname); generic_array_method_info [i].name = name; @@ -3226,7 +3505,7 @@ generic_array_methods (MonoClass *class) } static void -setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos) +setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, MonoMethod **methods, int pos) { MonoGenericContext tmp_context; int i; @@ -3240,36 +3519,15 @@ setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos) MonoMethod *inflated; inflated = mono_class_inflate_generic_method (m, &tmp_context); - class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated); + methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated); } } -static MonoMethod* -create_array_method (MonoClass *class, const char *name, MonoMethodSignature *sig) -{ - MonoMethod *method; - - method = (MonoMethod *) mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethodPInvoke)); - method->klass = class; - method->flags = METHOD_ATTRIBUTE_PUBLIC; - method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL; - method->signature = sig; - method->name = name; - method->slot = -1; - /* .ctor */ - if (name [0] == '.') { - method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME; - } else { - method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME; - } - return method; -} - static char* -concat_two_strings_with_zero (MonoMemPool *pool, const char *s1, const char *s2) +concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2) { int len = strlen (s1) + strlen (s2) + 2; - char *s = mono_mempool_alloc (pool, len); + char *s = mono_image_alloc (image, len); int result; result = g_snprintf (s, len, "%s%c%s", s1, '\0', s2); @@ -3281,15 +3539,15 @@ concat_two_strings_with_zero (MonoMemPool *pool, const char *s1, const char *s2) static void set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error) { - class->exception_type = error->exception_type; + gpointer exception_data = NULL; switch (error->exception_type) { case MONO_EXCEPTION_TYPE_LOAD: - class->exception_data = concat_two_strings_with_zero (class->image->mempool, error->class_name, error->assembly_name); + exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->assembly_name); break; case MONO_EXCEPTION_MISSING_METHOD: - class->exception_data = concat_two_strings_with_zero (class->image->mempool, error->class_name, error->member_name); + exception_data = concat_two_strings_with_zero (class->image, error->class_name, error->member_name); break; case MONO_EXCEPTION_MISSING_FIELD: { @@ -3301,7 +3559,7 @@ set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error) else class_name = error->klass->name; - class->exception_data = concat_two_strings_with_zero (class->image->mempool, class_name, error->member_name); + exception_data = concat_two_strings_with_zero (class->image, class_name, error->member_name); if (name_space) g_free ((void*)class_name); @@ -3316,17 +3574,19 @@ set_failure_from_loader_error (MonoClass *class, MonoLoaderError *error) else msg = "Could not load file or assembly '%s' or one of its dependencies."; - class->exception_data = concat_two_strings_with_zero (class->image->mempool, msg, error->assembly_name); + exception_data = concat_two_strings_with_zero (class->image, msg, error->assembly_name); break; } case MONO_EXCEPTION_BAD_IMAGE: - class->exception_data = error->msg; + exception_data = error->msg; break; default : g_assert_not_reached (); } + + mono_class_set_failure (class, error->exception_type, exception_data); } static void @@ -3341,23 +3601,20 @@ check_core_clr_inheritance (MonoClass *class) class_level = mono_security_core_clr_class_level (class); parent_level = mono_security_core_clr_class_level (parent); - if (class_level < parent_level) { - class->exception_type = MONO_EXCEPTION_TYPE_LOAD; - class->exception_data = NULL; - } + if (class_level < parent_level) + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); } /** * mono_class_init: * @class: the class to initialize * - * compute the instance_size, class_size and other infos that cannot be - * computed at mono_class_get() time. Also compute a generic vtable and - * the method slot numbers. We use this infos later to create a domain - * specific vtable. - * + * Compute the instance_size, class_size and other infos that cannot be + * computed at mono_class_get() time. Also compute vtable_size if possible. * Returns TRUE on success or FALSE if there was a problem in loading * the type (incorrect assemblies, missing assemblies, methods, etc). + * + * LOCKING: Acquires the loader lock. */ gboolean mono_class_init (MonoClass *class) @@ -3369,6 +3626,7 @@ mono_class_init (MonoClass *class) g_assert (class); + /* Double-checking locking pattern */ if (class->inited) return class->exception_type == MONO_EXCEPTION_NONE; @@ -3424,18 +3682,8 @@ mono_class_init (MonoClass *class) has_cached_info = mono_class_get_cached_class_info (class, &cached_info); - if (!class->generic_class && !class->image->dynamic && (!has_cached_info || (has_cached_info && cached_info.has_nested_classes))) { - i = mono_metadata_nesting_typedef (class->image, class->type_token, 1); - while (i) { - MonoClass* nclass; - guint32 cols [MONO_NESTED_CLASS_SIZE]; - mono_metadata_decode_row (&class->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE); - nclass = mono_class_create_from_typedef (class->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]); - class->nested_classes = g_list_prepend_mempool (class->nested_classes, class->image->mempool, nclass); - - i = mono_metadata_nesting_typedef (class->image, class->type_token, i + 1); - } - } + if (class->generic_class || class->image->dynamic || !class->type_token || (has_cached_info && !cached_info.has_nested_classes)) + class->nested_classes_inited = TRUE; /* * Computes the size used by the fields, and their locations @@ -3459,74 +3707,14 @@ mono_class_init (MonoClass *class) } } - - /* initialize method pointers */ + /* Initialize arrays */ if (class->rank) { - MonoMethod *amethod; - MonoMethodSignature *sig; - int count_generic = 0, first_generic = 0; - int method_num = 0; - class->method.count = 3 + (class->rank > 1? 2: 1); if (class->interface_count) { - count_generic = generic_array_methods (class); - first_generic = class->method.count; + int count_generic = generic_array_methods (class); class->method.count += class->interface_count * count_generic; } - - sig = mono_metadata_signature_alloc (class->image, class->rank); - sig->ret = &mono_defaults.void_class->byval_arg; - sig->pinvoke = TRUE; - sig->hasthis = TRUE; - for (i = 0; i < class->rank; ++i) - sig->params [i] = &mono_defaults.int32_class->byval_arg; - - amethod = create_array_method (class, ".ctor", sig); - class->methods = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoMethod*) * class->method.count); - class->methods [method_num++] = amethod; - if (class->rank > 1) { - sig = mono_metadata_signature_alloc (class->image, class->rank * 2); - sig->ret = &mono_defaults.void_class->byval_arg; - sig->pinvoke = TRUE; - sig->hasthis = TRUE; - for (i = 0; i < class->rank * 2; ++i) - sig->params [i] = &mono_defaults.int32_class->byval_arg; - - amethod = create_array_method (class, ".ctor", sig); - class->methods [method_num++] = amethod; - } - /* element Get (idx11, [idx2, ...]) */ - sig = mono_metadata_signature_alloc (class->image, class->rank); - sig->ret = &class->element_class->byval_arg; - sig->pinvoke = TRUE; - sig->hasthis = TRUE; - for (i = 0; i < class->rank; ++i) - sig->params [i] = &mono_defaults.int32_class->byval_arg; - amethod = create_array_method (class, "Get", sig); - class->methods [method_num++] = amethod; - /* element& Address (idx11, [idx2, ...]) */ - sig = mono_metadata_signature_alloc (class->image, class->rank); - sig->ret = &class->element_class->this_arg; - sig->pinvoke = TRUE; - sig->hasthis = TRUE; - for (i = 0; i < class->rank; ++i) - sig->params [i] = &mono_defaults.int32_class->byval_arg; - amethod = create_array_method (class, "Address", sig); - class->methods [method_num++] = amethod; - /* void Set (idx11, [idx2, ...], element) */ - sig = mono_metadata_signature_alloc (class->image, class->rank + 1); - sig->ret = &mono_defaults.void_class->byval_arg; - sig->pinvoke = TRUE; - sig->hasthis = TRUE; - for (i = 0; i < class->rank; ++i) - sig->params [i] = &mono_defaults.int32_class->byval_arg; - sig->params [i] = &class->element_class->byval_arg; - amethod = create_array_method (class, "Set", sig); - class->methods [method_num++] = amethod; - - for (i = 0; i < class->interface_count; i++) - setup_generic_array_ifaces (class, class->interfaces [i], first_generic + i * count_generic); } mono_class_setup_supertypes (class); @@ -3534,33 +3722,44 @@ mono_class_init (MonoClass *class) if (!default_ghc) initialize_object_slots (class); - /* - * If possible, avoid the creation of the generic vtable by requesting - * cached info from the runtime. + /* + * Initialize the rest of the data without creating a generic vtable if possible. + * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can + * also avoid computing a generic vtable. */ if (has_cached_info) { - guint32 cur_slot = 0; - + /* AOT case */ class->vtable_size = cached_info.vtable_size; class->has_finalize = cached_info.has_finalize; class->ghcimpl = cached_info.ghcimpl; class->has_cctor = cached_info.has_cctor; + } else if (class->rank == 1 && class->byval_arg.type == MONO_TYPE_SZARRAY) { + static int szarray_vtable_size = 0; - if (class->parent) { - mono_class_init (class->parent); - cur_slot = class->parent->vtable_size; + /* SZARRAY case */ + if (!szarray_vtable_size) { + mono_class_setup_vtable (class); + szarray_vtable_size = class->vtable_size; + } else { + class->vtable_size = szarray_vtable_size; } + } else if (class->generic_class && !MONO_CLASS_IS_INTERFACE (class)) { + MonoClass *gklass = class->generic_class->container_class; - setup_interface_offsets (class, cur_slot); - } - else { - mono_class_setup_vtable (class); + /* Generic instance case */ + class->ghcimpl = gklass->ghcimpl; + class->has_finalize = gklass->has_finalize; + class->has_cctor = gklass->has_cctor; - if (class->exception_type || mono_loader_get_last_error ()){ - class_init_ok = FALSE; - goto leave; - } + mono_class_setup_vtable (gklass); + if (gklass->exception_type) + goto fail; + + class->vtable_size = gklass->vtable_size; + } else { + /* General case */ + /* ghcimpl is not currently used class->ghcimpl = 1; if (class->parent) { MonoMethod *cmethod = class->vtable [ghc_slot]; @@ -3570,37 +3769,104 @@ mono_class_init (MonoClass *class) class->ghcimpl = 0; } } + */ + + /* Interfaces and valuetypes are not supposed to have finalizers */ + if (!(MONO_CLASS_IS_INTERFACE (class) || class->valuetype)) { + MonoMethod *cmethod = NULL; + + if (class->parent) { + /* FIXME: Optimize this */ + mono_class_setup_vtable (class); + if (class->exception_type || mono_loader_get_last_error ()) + goto fail; + cmethod = class->vtable [finalize_slot]; + } + + if (cmethod) { + /* Check that this is really the finalizer method */ + mono_class_setup_vtable (class); + if (class->exception_type || mono_loader_get_last_error ()) + goto fail; + + class->has_finalize = 0; + if (class->parent) { + cmethod = class->vtable [finalize_slot]; + if (cmethod->is_inflated) + cmethod = ((MonoMethodInflated*)cmethod)->declaring; + if (cmethod != default_finalize) { + class->has_finalize = 1; + } + } + } + } + + /* C# doesn't allow interfaces to have cctors */ + if (!MONO_CLASS_IS_INTERFACE (class) || class->image != mono_defaults.corlib) { + MonoMethod *cmethod = NULL; + + if (class->type_token) { + cmethod = find_method_in_metadata (class, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME); + /* The find_method function ignores the 'flags' argument */ + if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME)) + class->has_cctor = 1; + } else { + mono_class_setup_methods (class); + + for (i = 0; i < class->method.count; ++i) { + MonoMethod *method = class->methods [i]; + if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && + (strcmp (".cctor", method->name) == 0)) { + class->has_cctor = 1; + break; + } + } + } + } + } - /* Object::Finalize should have empty implemenatation */ - class->has_finalize = 0; - if (class->parent) { - MonoMethod *cmethod = class->vtable [finalize_slot]; - if (cmethod->is_inflated) - cmethod = ((MonoMethodInflated*)cmethod)->declaring; - if (cmethod != default_finalize) { - class->has_finalize = 1; + if (!mono_setup_vtable_in_class_init) { + /* + * This is an embedding API break, since the caller might assume that + * mono_class_init () constructs a generic vtable, so vtable construction errors + * are visible right after the mono_class_init (), and not after + * mono_class_vtable (). + */ + if (class->parent) { + /* This will compute class->parent->vtable_size for some classes */ + mono_class_init (class->parent); + if (class->parent->exception_type || mono_loader_get_last_error ()) + goto fail; + if (!class->parent->vtable_size) { + /* FIXME: Get rid of this somehow */ + mono_class_setup_vtable (class->parent); + if (class->parent->exception_type || mono_loader_get_last_error ()) + goto fail; } + setup_interface_offsets (class, class->parent->vtable_size); + } else { + setup_interface_offsets (class, 0); } + } else { + mono_class_setup_vtable (class); - for (i = 0; i < class->method.count; ++i) { - MonoMethod *method = class->methods [i]; - if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && - (strcmp (".cctor", method->name) == 0)) { - class->has_cctor = 1; - break; - } - } + if (MONO_CLASS_IS_INTERFACE (class)) + setup_interface_offsets (class, 0); } - if (MONO_CLASS_IS_INTERFACE (class)) { - /* - * knowledge of interface offsets is needed for the castclass/isinst code, so - * we have to setup them for interfaces, too. - */ - setup_interface_offsets (class, 0); + if (mono_verifier_is_enabled_for_class (class) && !mono_verifier_verify_class (class)) { + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, concat_two_strings_with_zero (class->image, class->name, class->image->assembly_name)); + class_init_ok = FALSE; } + goto leave; + + fail: + class_init_ok = FALSE; + leave: + /* Because of the double-checking locking pattern */ + mono_memory_barrier (); class->inited = 1; class->init_pending = 0; @@ -3619,6 +3885,16 @@ mono_class_init (MonoClass *class) return class_init_ok; } +static gboolean +is_corlib_image (MonoImage *image) +{ + /* FIXME: allow the dynamic case for our compilers and with full trust */ + if (image->dynamic) + return image->assembly && !strcmp (image->assembly->aname.name, "mscorlib"); + else + return image == mono_defaults.corlib; +} + /* * LOCKING: this assumes the loader lock is held */ @@ -3627,6 +3903,7 @@ mono_class_setup_mono_type (MonoClass *class) { const char *name = class->name; const char *nspace = class->name_space; + gboolean is_corlib = is_corlib_image (class->image); class->this_arg.byref = 1; class->this_arg.data.klass = class; @@ -3634,7 +3911,7 @@ mono_class_setup_mono_type (MonoClass *class) class->byval_arg.data.klass = class; class->byval_arg.type = MONO_TYPE_CLASS; - if (!strcmp (nspace, "System")) { + if (is_corlib && !strcmp (nspace, "System")) { if (!strcmp (name, "ValueType")) { /* * do not set the valuetype bit for System.ValueType. @@ -3656,10 +3933,11 @@ mono_class_setup_mono_type (MonoClass *class) class->this_arg.type = class->byval_arg.type = MONO_TYPE_TYPEDBYREF; } } - + if (class->valuetype) { int t = MONO_TYPE_VALUETYPE; - if (!strcmp (nspace, "System")) { + + if (is_corlib && !strcmp (nspace, "System")) { switch (*name) { case 'B': if (!strcmp (name, "Boolean")) { @@ -3749,8 +4027,9 @@ void mono_class_setup_parent (MonoClass *class, MonoClass *parent) { gboolean system_namespace; + gboolean is_corlib = is_corlib_image (class->image); - system_namespace = !strcmp (class->name_space, "System"); + system_namespace = !strcmp (class->name_space, "System") && is_corlib; /* if root of the hierarchy */ if (system_namespace && !strcmp (class->name, "Object")) { @@ -3771,11 +4050,13 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) if (parent == mono_defaults.object_class) parent = mono_defaults.com_object_class; } - class->parent = parent; - + if (!parent) { + /* set the parent to something useful and safe, but mark the type as broken */ + parent = mono_defaults.object_class; + mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL); + } - if (!parent) - g_assert_not_reached (); /* FIXME */ + class->parent = parent; if (parent->generic_class && !parent->name) { /* @@ -3805,10 +4086,10 @@ mono_class_setup_parent (MonoClass *class, MonoClass *parent) class->delegate = 1; } - if (class->parent->enumtype || ((strcmp (class->parent->name, "ValueType") == 0) && + if (class->parent->enumtype || (is_corlib_image (class->parent->image) && (strcmp (class->parent->name, "ValueType") == 0) && (strcmp (class->parent->name_space, "System") == 0))) class->valuetype = 1; - if (((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) { + if (is_corlib_image (class->parent->image) && ((strcmp (class->parent->name, "Enum") == 0) && (strcmp (class->parent->name_space, "System") == 0))) { class->valuetype = class->enumtype = 1; } /*class->enumtype = class->parent->enumtype; */ @@ -3851,7 +4132,7 @@ mono_class_setup_supertypes (MonoClass *class) class->idepth = 1; ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, class->idepth); - class->supertypes = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClass *) * ms); + class->supertypes = mono_image_alloc0 (class->image, sizeof (MonoClass *) * ms); if (class->parent) { class->supertypes [class->idepth - 1] = class; @@ -3898,7 +4179,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]); nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]); - class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass)); + class = mono_image_alloc0 (image, sizeof (MonoClass)); class->name = name; class->name_space = nspace; @@ -4015,6 +4296,11 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token) mono_metadata_load_generic_param_constraints ( image, type_token, class->generic_container); + if (class->image->assembly_name && !strcmp (class->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) { + if (!strncmp (name, "Vector", 6)) + class->simd_type = !strcmp (name + 6, "4f") || !strcmp (name + 6, "4u") || !strcmp (name + 6, "8u") || !strcmp (name + 6, "16u"); + } + mono_loader_unlock (); mono_profiler_class_loaded (class, MONO_PROFILE_OK); @@ -4144,9 +4430,6 @@ mono_generic_class_get_class (MonoGenericClass *gclass) } } - if (MONO_CLASS_IS_INTERFACE (klass)) - setup_interface_offsets (klass, 0); - mono_profiler_class_loaded (klass, MONO_PROFILE_OK); mono_loader_unlock (); @@ -4182,12 +4465,12 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb /* FIXME: */ image = mono_defaults.corlib; - klass = param->pklass = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass)); + klass = param->pklass = mono_image_alloc0 (image, sizeof (MonoClass)); if (param->name) klass->name = param->name; else { - klass->name = mono_mempool_alloc0 (image->mempool, 16); + klass->name = mono_image_alloc0 (image, 16); sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num); } klass->name_space = ""; @@ -4207,7 +4490,7 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb if (count - pos > 0) { klass->interface_count = count - pos; - klass->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass *) * (count - pos)); + klass->interfaces = mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)); for (i = pos; i < count; i++) klass->interfaces [i - pos] = param->constraints [i]; } @@ -4226,6 +4509,31 @@ mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *image, gb klass->this_arg.data.generic_param = klass->byval_arg.data.generic_param = param; klass->this_arg.byref = TRUE; + if (param->owner) { + guint32 owner; + guint32 cols [MONO_GENERICPARAM_SIZE]; + MonoTableInfo *tdef = &image->tables [MONO_TABLE_GENERICPARAM]; + i = 0; + + if (is_mvar && param->owner->owner.method) + i = mono_metadata_get_generic_param_row (image, param->owner->owner.method->token, &owner); + else if (!is_mvar && param->owner->owner.klass) + i = mono_metadata_get_generic_param_row (image, param->owner->owner.klass->type_token, &owner); + + if (i) { + mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE); + do { + if (cols [MONO_GENERICPARAM_NUMBER] == param->num) { + klass->sizes.generic_param_token = i | MONO_TOKEN_GENERIC_PARAM; + break; + } + if (++i > tdef->rows) + break; + mono_metadata_decode_row (tdef, i - 1, cols, MONO_GENERICPARAM_SIZE); + } while (cols [MONO_GENERICPARAM_OWNER] == owner); + } + } + mono_class_setup_supertypes (klass); mono_loader_unlock (); @@ -4255,12 +4563,12 @@ mono_ptr_class_get (MonoType *type) mono_loader_unlock (); return result; } - result = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass)); + result = mono_image_alloc0 (image, sizeof (MonoClass)); result->parent = NULL; /* no parent for PTR types */ result->name_space = el_class->name_space; name = g_strdup_printf ("%s*", el_class->name); - result->name = mono_mempool_strdup (image->mempool, name); + result->name = mono_image_strdup (image, name); g_free (name); mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); @@ -4411,15 +4719,17 @@ mono_class_from_mono_type (MonoType *type) * @context: the generic context used to evaluate generic instantiations in */ static MonoType * -mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context) +mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate) { MonoType *t = mono_type_create_from_typespec (image, type_spec); if (!t) return NULL; if (context && (context->class_inst || context->method_inst)) { - MonoType *inflated = inflate_generic_type (t, context); - if (inflated) + MonoType *inflated = inflate_generic_type (NULL, t, context); + if (inflated) { t = inflated; + *did_inflate = TRUE; + } } return t; } @@ -4433,10 +4743,15 @@ mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGener static MonoClass * mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context) { - MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context); + MonoClass *ret; + gboolean inflated = FALSE; + MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated); if (!t) return NULL; - return mono_class_from_mono_type (t); + ret = mono_class_from_mono_type (t); + if (inflated) + mono_metadata_free_type (t); + return ret; } /** @@ -4492,19 +4807,21 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_class_init (parent); } - class = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass)); + class = mono_image_alloc0 (image, sizeof (MonoClass)); class->image = image; class->name_space = eclass->name_space; nsize = strlen (eclass->name); - name = g_malloc (nsize + 2 + rank); + name = g_malloc (nsize + 2 + rank + 1); memcpy (name, eclass->name, nsize); name [nsize] = '['; if (rank > 1) memset (name + nsize + 1, ',', rank - 1); - name [nsize + rank] = ']'; - name [nsize + rank + 1] = 0; - class->name = mono_mempool_strdup (image->mempool, name); + if (bounded) + name [nsize + rank] = '*'; + name [nsize + rank + bounded] = ']'; + name [nsize + rank + bounded + 1] = 0; + class->name = mono_image_strdup (image, name); g_free (name); mono_profiler_class_event (class, MONO_PROFILE_START_LOAD); @@ -4533,7 +4850,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) /* generic IList, ICollection, IEnumerable */ class->interface_count = 1; - class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count); + class->interfaces = mono_image_alloc0 (image, sizeof (MonoClass*) * class->interface_count); args [0] = &eclass->byval_arg; class->interfaces [0] = mono_class_bind_generic_parameters ( @@ -4556,7 +4873,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) class->element_class = eclass; if ((rank > 1) || bounded) { - MonoArrayType *at = mono_mempool_alloc0 (image->mempool, sizeof (MonoArrayType)); + MonoArrayType *at = mono_image_alloc0 (image, sizeof (MonoArrayType)); class->byval_arg.type = MONO_TYPE_ARRAY; class->byval_arg.data.array = at; at->eklass = eclass; @@ -4801,7 +5118,7 @@ mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_typ g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT); if (!field->data) { - cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), cindex + 1); + cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0); g_assert (cindex); g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)); @@ -5021,6 +5338,7 @@ MonoType * mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context) { MonoType *type = NULL; + gboolean inflated = FALSE; //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then? if (image->dynamic) @@ -5031,14 +5349,30 @@ mono_type_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *co return class ? mono_class_get_type (class) : NULL; } - type = mono_type_retrieve_from_typespec (image, type_token, context); + type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated); if (!type) { char *name = mono_class_name_from_token (image, type_token); char *assembly = mono_assembly_name_from_token (image, type_token); + if (inflated) + mono_metadata_free_type (type); mono_loader_set_error_type_load (name, assembly); } + if (inflated) { + MonoType *tmp = type; + type = mono_class_get_type (mono_class_from_mono_type (type)); + /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition. + * A MonoClass::byval_arg of a generic type definion has type CLASS. + * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg. + * + * The long term solution is to chaise this places and make then set MonoType::type correctly. + * */ + if (type->type != tmp->type) + type = tmp; + else + mono_metadata_free_type (tmp); + } return type; } @@ -5238,17 +5572,18 @@ mono_class_from_name_case (MonoImage *image, const char* name_space, const char } static MonoClass* -return_nested_in (MonoClass *class, char *nested) { +return_nested_in (MonoClass *class, char *nested) +{ MonoClass *found; char *s = strchr (nested, '/'); - GList *tmp; + gpointer iter = NULL; if (s) { *s = 0; s++; } - for (tmp = class->nested_classes; tmp; tmp = tmp->next) { - found = tmp->data; + + while ((found = mono_class_get_nested_types (class, &iter))) { if (strcmp (found->name, nested) == 0) { if (s) return return_nested_in (found, s); @@ -5258,6 +5593,36 @@ return_nested_in (MonoClass *class, char *nested) { return NULL; } +static MonoClass* +search_modules (MonoImage *image, const char *name_space, const char *name) +{ + MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE]; + MonoImage *file_image; + MonoClass *class; + int i; + + /* + * The EXPORTEDTYPES table only contains public types, so have to search the + * modules as well. + * Note: image->modules contains the contents of the MODULEREF table, while + * the real module list is in the FILE table. + */ + for (i = 0; i < file_table->rows; i++) { + guint32 cols [MONO_FILE_SIZE]; + mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE); + if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA) + continue; + + file_image = mono_image_load_file_for_image (image, i + 1); + if (file_image) { + class = mono_class_from_name (file_image, name_space, name); + if (class) + return class; + } + } + + return NULL; +} /** * mono_class_from_name: @@ -5293,6 +5658,8 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name if (get_class_from_name) { gboolean res = get_class_from_name (image, name_space, name, &class); if (res) { + if (!class) + class = search_modules (image, name_space, name); if (nested) return class ? return_nested_in (class, nested) : NULL; else @@ -5323,6 +5690,12 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name } } + if (!token) { + class = search_modules (image, name_space, name); + if (class) + return class; + } + if (!token) return NULL; @@ -5346,15 +5719,19 @@ mono_class_from_name (MonoImage *image, const char* name_space, const char *name return class; } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) { MonoAssembly **references = image->references; - if (!references [idx - 1]) - mono_assembly_load_reference (image, idx - 1); + guint32 assembly_idx; + + assembly_idx = impl >> MONO_IMPLEMENTATION_BITS; + + if (!references [assembly_idx - 1]) + mono_assembly_load_reference (image, assembly_idx - 1); g_assert (references == image->references); - g_assert (references [idx - 1]); - if (references [idx - 1] == (gpointer)-1) + g_assert (references [assembly_idx - 1]); + if (references [assembly_idx - 1] == (gpointer)-1) return NULL; else /* FIXME: Cycle detection */ - return mono_class_from_name (references [idx - 1]->image, name_space, name); + return mono_class_from_name (references [assembly_idx - 1]->image, name_space, name); } else { g_error ("not yet implemented"); } @@ -5448,7 +5825,9 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) * interface_offsets set. */ return mono_reflection_call_is_assignable_to (oklass, klass); - + if (!oklass->interface_bitmap) + /* Happens with generic instances of not-yet created dynamic types */ + return FALSE; if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id)) return TRUE; @@ -5478,6 +5857,10 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) MonoClass *param1_class = mono_class_from_mono_type (klass->generic_class->context.class_inst->type_argv [i]); MonoClass *param2_class = mono_class_from_mono_type (oklass->generic_class->context.class_inst->type_argv [i]); + if (param1_class->valuetype != param2_class->valuetype) { + match = FALSE; + break; + } /* * The _VARIANT and _COVARIANT constants should read _COVARIANT and * _CONTRAVARIANT, but they are in a public header so we can't fix it. @@ -5487,8 +5870,10 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) ; else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class))) ; - else + else { match = FALSE; + break; + } } } @@ -5523,9 +5908,12 @@ mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass) } return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class); - } else if (mono_class_is_nullable (klass)) - return (mono_class_is_assignable_from (klass->cast_class, oklass)); - else if (klass == mono_defaults.object_class) + } else if (mono_class_is_nullable (klass)) { + if (mono_class_is_nullable (oklass)) + return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class); + else + return mono_class_is_assignable_from (klass->cast_class, oklass); + } else if (klass == mono_defaults.object_class) return TRUE; return mono_class_has_parent (oklass, klass); @@ -6033,8 +6421,8 @@ mono_class_get_fields (MonoClass* klass, gpointer *iter) MonoClassField* field; if (!iter) return NULL; - mono_class_setup_fields_locking (klass); if (!*iter) { + mono_class_setup_fields_locking (klass); /* start from the first */ if (klass->field.count) { return *iter = &klass->fields [0]; @@ -6223,10 +6611,33 @@ MonoClass* mono_class_get_nested_types (MonoClass* klass, gpointer *iter) { GList *item; + int i; + if (!iter) return NULL; if (!klass->inited) mono_class_init (klass); + if (!klass->nested_classes_inited) { + if (!klass->type_token) + klass->nested_classes_inited = TRUE; + mono_loader_lock (); + if (!klass->nested_classes_inited) { + i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1); + while (i) { + MonoClass* nclass; + guint32 cols [MONO_NESTED_CLASS_SIZE]; + mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE); + nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED]); + klass->nested_classes = g_list_prepend_mempool (klass->nested_classes, klass->image->mempool, nclass); + + i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1); + } + } + mono_memory_barrier (); + klass->nested_classes_inited = TRUE; + mono_loader_unlock (); + } + if (!*iter) { /* start from the first */ if (klass->nested_classes) { @@ -6475,6 +6886,32 @@ mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_c return mono_class_get_method_from_name_flags (klass, name, param_count, 0); } +static MonoMethod* +find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags) +{ + MonoMethod *res = NULL; + int i; + + /* Search directly in the metadata to avoid calling setup_methods () */ + for (i = 0; i < klass->method.count; ++i) { + guint32 cols [MONO_METHOD_SIZE]; + MonoMethod *method; + + /* class->method.first points into the methodptr table */ + mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE); + + if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) { + method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass); + if ((param_count == -1) || mono_method_signature (method)->param_count == param_count) { + res = method; + break; + } + } + } + + return res; +} + /** * mono_class_get_method_from_name_flags: * @klass: where to look for the method @@ -6493,7 +6930,7 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p mono_class_init (klass); - if (klass->methods) { + if (klass->methods || klass->generic_class) { mono_class_setup_methods (klass); for (i = 0; i < klass->method.count; ++i) { MonoMethod *method = klass->methods [i]; @@ -6508,22 +6945,7 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p } } else { - /* Search directly in the metadata to avoid calling setup_methods () */ - for (i = 0; i < klass->method.count; ++i) { - guint32 cols [MONO_METHOD_SIZE]; - MonoMethod *method; - - /* class->method.first points into the methodptr table */ - mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, klass->method.first + i, cols, MONO_METHOD_SIZE); - - if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) { - method = mono_get_method (klass->image, MONO_TOKEN_METHOD_DEF | (klass->method.first + i + 1), klass); - if ((param_count == -1) || mono_method_signature (method)->param_count == param_count) { - res = method; - break; - } - } - } + res = find_method_in_metadata (klass, name, param_count, flags); } return res; @@ -6537,17 +6959,42 @@ mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int p * * Keep a detected failure informations in the class for later processing. * Note that only the first failure is kept. + * + * LOCKING: Acquires the loader lock. */ gboolean mono_class_set_failure (MonoClass *klass, guint32 ex_type, void *ex_data) { if (klass->exception_type) return FALSE; + + mono_loader_lock (); klass->exception_type = ex_type; - klass->exception_data = ex_data; + if (ex_data) + mono_property_hash_insert (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA, ex_data); + mono_loader_unlock (); + return TRUE; } +/* + * mono_class_get_exception_data: + * + * Return the exception_data property of KLASS. + * + * LOCKING: Acquires the loader lock. + */ +gpointer +mono_class_get_exception_data (MonoClass *klass) +{ + gpointer res; + + mono_loader_lock (); + res = mono_property_hash_lookup (klass->image->property_hash, klass, MONO_CLASS_PROP_EXCEPTION_DATA); + mono_loader_unlock (); + return res; +} + /** * mono_classes_init: * @@ -6566,17 +7013,8 @@ mono_classes_init (void) void mono_classes_cleanup (void) { - IOffsetInfo *cached_info, *next; - if (global_interface_bitset) mono_bitset_free (global_interface_bitset); - - for (cached_info = cached_offset_info; cached_info;) { - next = cached_info->next; - - g_free (cached_info); - cached_info = next; - } } /** @@ -6590,11 +7028,13 @@ mono_classes_cleanup (void) MonoException* mono_class_get_exception_for_failure (MonoClass *klass) { + gpointer exception_data = mono_class_get_exception_data (klass); + switch (klass->exception_type) { case MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND: { MonoDomain *domain = mono_domain_get (); MonoSecurityManager* secman = mono_security_manager_get_methods (); - MonoMethod *method = klass->exception_data; + MonoMethod *method = exception_data; guint32 error = (method) ? MONO_METADATA_INHERITANCEDEMAND_METHOD : MONO_METADATA_INHERITANCEDEMAND_CLASS; MonoObject *exc = NULL; gpointer args [4]; @@ -6619,19 +7059,19 @@ mono_class_get_exception_for_failure (MonoClass *klass) return ex; } case MONO_EXCEPTION_MISSING_METHOD: { - char *class_name = klass->exception_data; + char *class_name = exception_data; char *assembly_name = class_name + strlen (class_name) + 1; return mono_get_exception_missing_method (class_name, assembly_name); } case MONO_EXCEPTION_MISSING_FIELD: { - char *class_name = klass->exception_data; + char *class_name = exception_data; char *member_name = class_name + strlen (class_name) + 1; return mono_get_exception_missing_field (class_name, member_name); } case MONO_EXCEPTION_FILE_NOT_FOUND: { - char *msg_format = klass->exception_data; + char *msg_format = exception_data; char *assembly_name = msg_format + strlen (msg_format) + 1; char *msg = g_strdup_printf (msg_format, assembly_name); MonoException *ex; @@ -6643,7 +7083,7 @@ mono_class_get_exception_for_failure (MonoClass *klass) return ex; } case MONO_EXCEPTION_BAD_IMAGE: { - return mono_get_exception_bad_image_format (klass->exception_data); + return mono_get_exception_bad_image_format (exception_data); } default: { MonoLoaderError *error; @@ -6661,6 +7101,74 @@ mono_class_get_exception_for_failure (MonoClass *klass) } } +static gboolean +is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass) + { + outer_klass = mono_class_get_generic_type_definition (outer_klass); + inner_klass = mono_class_get_generic_type_definition (inner_klass); + do { + if (outer_klass == inner_klass) + return TRUE; + inner_klass = inner_klass->nested_in; + } while (inner_klass); + return FALSE; +} + +MonoClass * +mono_class_get_generic_type_definition (MonoClass *klass) +{ + return klass->generic_class ? klass->generic_class->container_class : klass; +} + +/* + * Check if @klass is a subtype of @parent ignoring generic instantiations. + * + * Generic instantiations are ignored for all super types of @klass. + * + * Visibility checks ignoring generic instantiations. + */ +static gboolean +mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent) +{ + int i; + klass = mono_class_get_generic_type_definition (klass); + parent = mono_class_get_generic_type_definition (parent); + + for (i = 0; i < klass->idepth; ++i) { + if (parent == mono_class_get_generic_type_definition (klass->supertypes [i])) + return TRUE; + } + return FALSE; +} +/* + * Subtype can only access parent members with family protection if the site object + * is subclass of Subtype. For example: + * class A { protected int x; } + * class B : A { + * void valid_access () { + * B b; + * b.x = 0; + * } + * void invalid_access () { + * A a; + * a.x = 0; + * } + * } + * */ +static gboolean +is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass) +{ + if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass)) + return FALSE; + + if (context_klass == NULL) + return TRUE; + /*if access_klass is not member_klass context_klass must be type compat*/ + if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass)) + return FALSE; + return TRUE; +} + static gboolean can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed) { @@ -6669,6 +7177,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed) return TRUE; if (!accessed || !accessing) return FALSE; + mono_assembly_load_friends (accessed); for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) { MonoAssemblyName *friend = tmp->data; /* Be conservative with checks */ @@ -6679,7 +7188,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed) if (friend->public_key_token [0]) { if (!accessing->aname.public_key_token [0]) continue; - if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token)) + if (!mono_public_tokens_are_equal (friend->public_key_token, accessing->aname.public_key_token)) continue; } return TRUE; @@ -6703,9 +7212,67 @@ get_generic_definition_class (MonoClass *klass) return NULL; } +static gboolean +can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst) +{ + int i; + for (i = 0; i < ginst->type_argc; ++i) { + MonoType *type = ginst->type_argv[i]; + if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) + continue; + if (!can_access_type (access_klass, mono_class_from_mono_type (type))) + return FALSE; + } + return TRUE; +} + +static gboolean +can_access_type (MonoClass *access_klass, MonoClass *member_klass) +{ + int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK; + + if (member_klass->generic_class && !can_access_instantiation (access_klass, member_klass->generic_class->context.class_inst)) + return FALSE; + + if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass))) + return TRUE; + + if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in)) + return FALSE; + + switch (access_level) { + case TYPE_ATTRIBUTE_NOT_PUBLIC: + return can_access_internals (access_klass->image->assembly, member_klass->image->assembly); + + case TYPE_ATTRIBUTE_PUBLIC: + return TRUE; + + case TYPE_ATTRIBUTE_NESTED_PUBLIC: + return TRUE; + + case TYPE_ATTRIBUTE_NESTED_PRIVATE: + return is_nesting_type (member_klass, access_klass); + + case TYPE_ATTRIBUTE_NESTED_FAMILY: + return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in); + + case TYPE_ATTRIBUTE_NESTED_ASSEMBLY: + return can_access_internals (access_klass->image->assembly, member_klass->image->assembly); + + case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM: + return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) && + mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in); + + case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM: + return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) || + mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in); + } + return FALSE; +} + /* FIXME: check visibility of type, too */ static gboolean -can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level) +can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level) { MonoClass *member_generic_def; if (((access_klass->generic_class && access_klass->generic_class->container_class) || @@ -6718,7 +7285,7 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_ else access_container = access_klass->generic_class->container_class; - if (can_access_member (access_container, member_generic_def, access_level)) + if (can_access_member (access_container, member_generic_def, context_klass, access_level)) return TRUE; } @@ -6731,18 +7298,18 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_ case FIELD_ATTRIBUTE_PRIVATE: return access_klass == member_klass; case FIELD_ATTRIBUTE_FAM_AND_ASSEM: - if (mono_class_has_parent (access_klass, member_klass) && + if (is_valid_family_access (access_klass, member_klass, context_klass) && can_access_internals (access_klass->image->assembly, member_klass->image->assembly)) return TRUE; return FALSE; case FIELD_ATTRIBUTE_ASSEMBLY: return can_access_internals (access_klass->image->assembly, member_klass->image->assembly); case FIELD_ATTRIBUTE_FAMILY: - if (mono_class_has_parent (access_klass, member_klass)) + if (is_valid_family_access (access_klass, member_klass, context_klass)) return TRUE; return FALSE; case FIELD_ATTRIBUTE_FAM_OR_ASSEM: - if (mono_class_has_parent (access_klass, member_klass)) + if (is_valid_family_access (access_klass, member_klass, context_klass)) return TRUE; return can_access_internals (access_klass->image->assembly, member_klass->image->assembly); case FIELD_ATTRIBUTE_PUBLIC: @@ -6755,11 +7322,11 @@ gboolean mono_method_can_access_field (MonoMethod *method, MonoClassField *field) { /* FIXME: check all overlapping fields */ - int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK); + int can = can_access_member (method->klass, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK); if (!can) { MonoClass *nested = method->klass->nested_in; while (nested) { - can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK); + can = can_access_member (nested, field->parent, NULL, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK); if (can) return TRUE; nested = nested->nested_in; @@ -6771,11 +7338,11 @@ mono_method_can_access_field (MonoMethod *method, MonoClassField *field) gboolean mono_method_can_access_method (MonoMethod *method, MonoMethod *called) { - int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK); + int can = can_access_member (method->klass, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK); if (!can) { MonoClass *nested = method->klass->nested_in; while (nested) { - can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK); + can = can_access_member (nested, called->klass, NULL, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK); if (can) return TRUE; nested = nested->nested_in; @@ -6793,6 +7360,85 @@ mono_method_can_access_method (MonoMethod *method, MonoMethod *called) return can; } +/* + * mono_method_can_access_method_with_context: + * @method: The caller method + * @called: The called method + * @context_klass:TThe static type on stack of the owner @called object used + * + * This function must be used with instance calls, as they have more strict family accessibility. + * It can be used with static mehthod, but context_klass should be NULL. + * + * Returns: TRUE if caller have proper visibility and acessibility to @called + */ +gboolean +mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass) +{ + MonoClass *access_class = method->klass; + MonoClass *member_class = called->klass; + int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK); + if (!can) { + MonoClass *nested = access_class->nested_in; + while (nested) { + can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK); + if (can) + break; + nested = nested->nested_in; + } + } + + if (!can) + return FALSE; + + if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class))) + return FALSE; + + if (called->is_inflated) { + MonoMethodInflated * infl = (MonoMethodInflated*)called; + if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst)) + return FALSE; + } + + return TRUE; +} + + +/* + * mono_method_can_access_method_with_context: + * @method: The caller method + * @field: The accessed field + * @context_klass: The static type on stack of the owner @field object used + * + * This function must be used with instance fields, as they have more strict family accessibility. + * It can be used with static fields, but context_klass should be NULL. + * + * Returns: TRUE if caller have proper visibility and acessibility to @field + */ +gboolean +mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass) +{ + MonoClass *access_class = method->klass; + MonoClass *member_class = field->parent; + /* FIXME: check all overlapping fields */ + int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK); + if (!can) { + MonoClass *nested = access_class->nested_in; + while (nested) { + can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK); + if (can) + break; + nested = nested->nested_in; + } + } + + if (!can) + return FALSE; + + if (!can_access_type (access_class, member_class) && (!access_class->nested_in || !can_access_type (access_class->nested_in, member_class))) + return FALSE; + return TRUE; +} + /** * mono_type_is_valid_enum_basetype: * @type: The MonoType to check @@ -6882,15 +7528,28 @@ mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass) gboolean mono_class_generic_sharing_enabled (MonoClass *class) { - static int generic_sharing = MONO_GENERIC_SHARING_CORLIB; +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__ppc__) || defined(__powerpc__) + static gboolean supported = TRUE; +#else + /* Not supported by the JIT backends */ + static gboolean supported = FALSE; +#endif + static int generic_sharing = MONO_GENERIC_SHARING_NONE; static gboolean inited = FALSE; if (!inited) { const char *option; + if (supported) + generic_sharing = MONO_GENERIC_SHARING_ALL; + else + generic_sharing = MONO_GENERIC_SHARING_NONE; + if ((option = g_getenv ("MONO_GENERIC_SHARING"))) { if (strcmp (option, "corlib") == 0) generic_sharing = MONO_GENERIC_SHARING_CORLIB; + else if (strcmp (option, "collections") == 0) + generic_sharing = MONO_GENERIC_SHARING_COLLECTIONS; else if (strcmp (option, "all") == 0) generic_sharing = MONO_GENERIC_SHARING_ALL; else if (strcmp (option, "none") == 0) @@ -6899,6 +7558,9 @@ mono_class_generic_sharing_enabled (MonoClass *class) g_warning ("Unknown generic sharing option `%s'.", option); } + if (!supported) + generic_sharing = MONO_GENERIC_SHARING_NONE; + inited = TRUE; } @@ -6909,6 +7571,12 @@ mono_class_generic_sharing_enabled (MonoClass *class) return TRUE; case MONO_GENERIC_SHARING_CORLIB : return class->image == mono_defaults.corlib; + case MONO_GENERIC_SHARING_COLLECTIONS: + if (class->image != mono_defaults.corlib) + return FALSE; + while (class->nested_in) + class = class->nested_in; + return g_str_has_prefix (class->name_space, "System.Collections.Generic"); default: g_assert_not_reached (); }