#endif
#include <mono/metadata/image.h>
#include <mono/metadata/assembly.h>
-#include <mono/metadata/cil-coff.h>
#include <mono/metadata/metadata.h>
#include <mono/metadata/metadata-internals.h>
+#include <mono/metadata/profiler-private.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/tokentype.h>
#include <mono/metadata/class-internals.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/security-manager.h>
#include <mono/metadata/security-core-clr.h>
-#include <mono/os/gc_wrapper.h>
+#include <mono/metadata/attrdefs.h>
+#include <mono/metadata/gc-internal.h>
#include <mono/utils/mono-counters.h>
MonoStats mono_stats;
static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token);
static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
-void (*mono_debugger_start_class_init_func) (MonoClass *klass) = NULL;
void (*mono_debugger_class_init_func) (MonoClass *klass) = NULL;
+void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass) = NULL;
/*
* mono_class_from_typeref:
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
return NULL;
nt = mono_metadata_type_dup (NULL, type);
nt->data.klass = mono_class_from_mono_type (inflated);
+ mono_metadata_free_type (inflated);
return nt;
}
case MONO_TYPE_ARRAY: {
nt = mono_metadata_type_dup (NULL, 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);
return nt;
}
case MONO_TYPE_GENERICINST: {
/* We can't use context->class_inst directly, since it can have more elements */
inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context);
+ if (inst == container->context.class_inst)
+ return NULL;
+
gclass = mono_metadata_lookup_generic_class (klass, inst, klass->image->dynamic);
nt = mono_metadata_type_dup (NULL, type);
*
* Instantiate the generic type @type, using the generics context @context.
*
- * Returns: the instantiated type
+ * Returns: the instantiated 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)
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) {
if (!method->generic_container && !method->klass->generic_container)
return method;
+ /*
+ * 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.
+ *
+ * FIXME: express this better, somehow!
+ */
+ is_mb_open = method->generic_container &&
+ method->klass->image->dynamic && !method->klass->wastypebuilder &&
+ context->method_inst == method->generic_container->context.method_inst;
+
mono_stats.inflated_method_count++;
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;
mono_loader_lock ();
cached = mono_method_inflated_lookup (iresult, FALSE);
sig = mono_method_signature (method);
if (sig->pinvoke) {
- iresult->method.pinvoke = *(MonoMethodPInvoke*)method;
+ memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
} else {
- iresult->method.normal = *(MonoMethodNormal*)method;
+ memcpy (&iresult->method.normal, method, sizeof (MonoMethodNormal));
iresult->method.normal.header = NULL;
}
result = (MonoMethod *) iresult;
result->is_inflated = 1;
- /* result->generic_container = NULL; */
result->signature = NULL;
+ if (context->method_inst)
+ result->generic_container = NULL;
+
+ /* Due to the memcpy above, !context->method_inst => result->generic_container == method->generic_container */
+
if (!klass_hint || !klass_hint->generic_class ||
klass_hint->generic_class->container_class != method->klass ||
klass_hint->generic_class->context.class_inst != context->class_inst)
if (!result->klass) {
MonoType *inflated = inflate_generic_type (&method->klass->byval_arg, context);
result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
+ if (inflated)
+ mono_metadata_free_type (inflated);
}
- if (context->method_inst)
- result->generic_container = NULL;
- else if (method->generic_container)
- iresult->context.method_inst = method->generic_container->context.method_inst;
-
mono_method_inflated_lookup (iresult, TRUE);
mono_loader_unlock ();
return result;
MonoClass *gklass = class->generic_class->container_class;
mono_class_setup_fields (gklass);
top = gklass->field.count;
+ class->field.count = gklass->field.count;
}
class->instance_size = 0;
#define IS_GC_REFERENCE(t) ((t)->type == MONO_TYPE_U && class->image == mono_defaults.corlib)
#endif
+/*
+ * mono_type_get_basic_type_from_generic:
+ * @type: a type
+ *
+ * Returns a closed type corresponding to the possibly open type
+ * passed to it.
+ */
+MonoType*
+mono_type_get_basic_type_from_generic (MonoType *type)
+{
+ /* When we do generic sharing we let type variables stand for reference types. */
+ if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
+ return &mono_defaults.object_class->byval_arg;
+ return type;
+}
+
/*
* mono_class_layout_fields:
* @class: a class
gboolean gc_aware_layout = FALSE;
MonoClassField *field;
- if (class->generic_container ||
- (class->generic_class && class->generic_class->context.class_inst->is_open))
- return;
+ /*
+ * When we do generic sharing we need to have layout
+ * information for open generic classes (either with a generic
+ * context containing type variables or with a generic
+ * container), so we don't return in that case anymore.
+ */
/*
* Enable GC aware auto layout: in this mode, reference
if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
class->has_references = TRUE;
}
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype)))))
class->has_static_refs = TRUE;
}
field = &class->fields [i];
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
class->has_static_refs = TRUE;
continue;
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (gc_aware_layout) {
if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
if (pass == 1)
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).
*/
field->offset += sizeof (MonoObject);
ftype = mono_type_get_underlying_type (field->type);
+ ftype = mono_type_get_basic_type_from_generic (ftype);
if (MONO_TYPE_IS_REFERENCE (ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && mono_class_has_references (mono_class_from_mono_type (ftype))))) {
if (field->offset % sizeof (gpointer)) {
mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
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.
*/
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;
return;
}
- //printf ("INIT: %s.%s\n", class->name_space, class->name);
+ if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
+
+ mono_class_init (gklass);
+ mono_class_setup_methods (gklass);
+
+ /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
+ class->method.count = gklass->method.count;
+ methods = g_new0 (MonoMethod *, class->method.count + 1);
- if (!class->methods) {
+ for (i = 0; i < class->method.count; i++) {
+ methods [i] = mono_class_inflate_generic_method_full (
+ gklass->methods [i], class, mono_class_get_context (class));
+ }
+ } else {
methods = mono_mempool_alloc (class->image->mempool, 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);
/* Leave this assignment as the last op in this function */
class->methods = methods;
+ if (mono_debugger_class_loaded_methods_func)
+ mono_debugger_class_loaded_methods_func (class);
+
mono_loader_unlock ();
}
return;
}
- class->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
- class->property.count = last - class->property.first;
+ if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
- if (class->property.count)
- mono_class_setup_methods (class);
+ class->property = gklass->property;
- properties = mono_mempool_alloc0 (class->image->mempool, 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;
- properties [i - class->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
- properties [i - class->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
+ mono_class_init (gklass);
+ mono_class_setup_properties (gklass);
- startm = mono_metadata_methods_from_property (class->image, i, &endm);
- for (j = startm; j < endm; ++j) {
- MonoMethod *method;
+ properties = g_new0 (MonoProperty, class->property.count + 1);
- mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
+ for (i = 0; i < class->property.count; i++) {
+ MonoProperty *prop = &properties [i];
- if (class->image->uncompressed_metadata)
- /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
- method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
- else
- method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
+ *prop = gklass->properties [i];
- switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
- case METHOD_SEMANTIC_SETTER:
- properties [i - class->property.first].set = method;
- break;
- case METHOD_SEMANTIC_GETTER:
- properties [i - class->property.first].get = method;
- break;
- default:
- break;
+ if (prop->get)
+ prop->get = mono_class_inflate_generic_method_full (
+ prop->get, class, mono_class_get_context (class));
+ if (prop->set)
+ prop->set = mono_class_inflate_generic_method_full (
+ prop->set, class, mono_class_get_context (class));
+
+ prop->parent = class;
+ }
+ } else {
+ class->property.first = mono_metadata_properties_from_typedef (class->image, mono_metadata_token_index (class->type_token) - 1, &last);
+ class->property.count = last - class->property.first;
+
+ if (class->property.count)
+ mono_class_setup_methods (class);
+
+ properties = mono_mempool_alloc0 (class->image->mempool, 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;
+ properties [i - class->property.first].attrs = cols [MONO_PROPERTY_FLAGS];
+ properties [i - class->property.first].name = mono_metadata_string_heap (class->image, cols [MONO_PROPERTY_NAME]);
+
+ startm = mono_metadata_methods_from_property (class->image, i, &endm);
+ for (j = startm; j < endm; ++j) {
+ MonoMethod *method;
+
+ mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
+
+ if (class->image->uncompressed_metadata)
+ /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
+ method = mono_get_method (class->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], class);
+ else
+ method = class->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - class->method.first];
+
+ switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
+ case METHOD_SEMANTIC_SETTER:
+ properties [i - class->property.first].set = method;
+ break;
+ case METHOD_SEMANTIC_GETTER:
+ properties [i - class->property.first].get = method;
+ break;
+ default:
+ break;
+ }
}
}
}
printf ("Packed interface table for class %s has size %d\n", klass->name, klass->interface_offsets_count);
for (i = 0; i < klass->interface_offsets_count; i++)
- printf (" [%d][UUID %d][SLOT %d] interface %s\n", i,
+ printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
klass->interfaces_packed [i]->interface_id,
klass->interface_offsets_packed [i],
+ klass->interfaces_packed [i]->method.count,
+ klass->interfaces_packed [i]->name_space,
klass->interfaces_packed [i]->name );
printf ("Interface flags: ");
for (i = 0; i <= klass->max_interface_id; i++)
for (i = 0; i < ifaces->len; i++) {
MonoClass *ic = g_ptr_array_index (ifaces, i);
printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
+ printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
+ ic->interface_id,
+ mono_class_interface_offset (klass, ic),
+ ic->method.count,
+ ic->name_space,
+ ic->name );
}
g_ptr_array_free (ifaces, TRUE);
}
}
}
+/* this won't be needed once bug #325495 is completely fixed
+ * though we'll need something similar to know which interfaces to allow
+ * in arrays when they'll be lazyly created
+ */
+static MonoClass**
+get_implicit_generic_array_interfaces (MonoClass *class, int *num, int *is_enumerator)
+{
+ MonoClass *eclass = class->element_class;
+ static MonoClass* generic_icollection_class = NULL;
+ static MonoClass* generic_ienumerable_class = NULL;
+ static MonoClass* generic_ienumerator_class = NULL;
+ MonoClass *fclass = NULL;
+ MonoClass **interfaces = NULL;
+ int i, interface_count, real_count;
+ int all_interfaces;
+ gboolean internal_enumerator;
+ gboolean eclass_is_valuetype;
+
+ if (!mono_defaults.generic_ilist_class) {
+ *num = 0;
+ return NULL;
+ }
+ internal_enumerator = FALSE;
+ eclass_is_valuetype = FALSE;
+ if (class->byval_arg.type != MONO_TYPE_SZARRAY) {
+ if (class->generic_class && class->nested_in == mono_defaults.array_class && strcmp (class->name, "InternalEnumerator`1") == 0) {
+ /*
+ * For a Enumerator<T[]> we need to get the list of interfaces for T.
+ */
+ eclass = mono_class_from_mono_type (class->generic_class->context.class_inst->type_argv [0]);
+ eclass = eclass->element_class;
+ internal_enumerator = TRUE;
+ *is_enumerator = TRUE;
+ } else {
+ *num = 0;
+ return NULL;
+ }
+ }
+
+ /*
+ * with this non-lazy impl we can't implement all the interfaces so we do just the minimal stuff
+ * for deep levels of arrays of arrays (string[][] has all the interfaces, string[][][] doesn't)
+ */
+ all_interfaces = eclass->rank && eclass->element_class->rank? FALSE: TRUE;
+
+ if (!generic_icollection_class) {
+ generic_icollection_class = mono_class_from_name (mono_defaults.corlib,
+ "System.Collections.Generic", "ICollection`1");
+ generic_ienumerable_class = mono_class_from_name (mono_defaults.corlib,
+ "System.Collections.Generic", "IEnumerable`1");
+ generic_ienumerator_class = mono_class_from_name (mono_defaults.corlib,
+ "System.Collections.Generic", "IEnumerator`1");
+ }
+
+ /*
+ * Arrays in 2.0 need to implement a number of generic interfaces
+ * (IList`1, ICollection`1, IEnumerable`1 for a number of types depending
+ * on the element class). We collect the types needed to build the
+ * instantiations in interfaces at intervals of 3, because 3 are
+ * the generic interfaces needed to implement.
+ */
+ if (eclass->valuetype) {
+ if (eclass == mono_defaults.int16_class)
+ fclass = mono_defaults.uint16_class;
+ else if (eclass == mono_defaults.uint16_class)
+ fclass = mono_defaults.int16_class;
+ else if (eclass == mono_defaults.int32_class)
+ fclass = mono_defaults.uint32_class;
+ else if (eclass == mono_defaults.uint32_class)
+ fclass = mono_defaults.int32_class;
+ else if (eclass == mono_defaults.int64_class)
+ fclass = mono_defaults.uint64_class;
+ else if (eclass == mono_defaults.uint64_class)
+ fclass = mono_defaults.int64_class;
+ else if (eclass == mono_defaults.byte_class)
+ fclass = mono_defaults.sbyte_class;
+ else if (eclass == mono_defaults.sbyte_class)
+ fclass = mono_defaults.byte_class;
+ else {
+ /* No additional interfaces for other value types */
+ *num = 0;
+ return NULL;
+ }
+
+ /* IList, ICollection, IEnumerable */
+ real_count = interface_count = 3;
+ interfaces = g_malloc0 (sizeof (MonoClass*) * interface_count);
+ interfaces [0] = fclass;
+ eclass_is_valuetype = TRUE;
+ } else {
+ int j;
+ int idepth = eclass->idepth;
+ if (!internal_enumerator)
+ idepth--;
+ interface_count = all_interfaces? eclass->interface_offsets_count: eclass->interface_count;
+ /* we add object for interfaces and the supertypes for the other
+ * types. The last of the supertypes is the element class itself which we
+ * already created the explicit interfaces for (so we include it for IEnumerator
+ * and exclude it for arrays).
+ */
+ if (MONO_CLASS_IS_INTERFACE (eclass))
+ interface_count++;
+ else
+ interface_count += idepth;
+ /* IList, ICollection, IEnumerable */
+ interface_count *= 3;
+ real_count = interface_count;
+ if (internal_enumerator)
+ real_count += idepth + eclass->interface_offsets_count;
+ interfaces = g_malloc0 (sizeof (MonoClass*) * real_count);
+ if (MONO_CLASS_IS_INTERFACE (eclass)) {
+ interfaces [0] = mono_defaults.object_class;
+ j = 3;
+ } else {
+ j = 0;
+ for (i = 0; i < idepth; i++) {
+ mono_class_init (eclass->supertypes [i]);
+ interfaces [j] = eclass->supertypes [i];
+ j += 3;
+ }
+ }
+ if (all_interfaces) {
+ for (i = 0; i < eclass->interface_offsets_count; i++) {
+ interfaces [j] = eclass->interfaces_packed [i];
+ j += 3;
+ }
+ } else {
+ for (i = 0; i < eclass->interface_count; i++) {
+ interfaces [j] = eclass->interfaces [i];
+ j += 3;
+ }
+ }
+ }
+
+ /* instantiate the generic interfaces */
+ for (i = 0; i < interface_count; i += 3) {
+ MonoType *args [1];
+ MonoClass *iface = interfaces [i];
+
+ args [0] = &iface->byval_arg;
+ interfaces [i] = mono_class_bind_generic_parameters (
+ mono_defaults.generic_ilist_class, 1, args, FALSE);
+ //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));
+ args [0] = &iface->byval_arg;
+ interfaces [i + 1] = mono_class_bind_generic_parameters (
+ generic_icollection_class, 1, args, FALSE);
+ args [0] = &iface->byval_arg;
+ interfaces [i + 2] = mono_class_bind_generic_parameters (
+ generic_ienumerable_class, 1, args, FALSE);
+ //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 1]->byval_arg, 0));
+ //g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i + 2]->byval_arg, 0));
+ }
+ if (internal_enumerator) {
+ int j;
+ /* instantiate IEnumerator<iface> */
+ for (i = 0; i < interface_count; i++) {
+ MonoType *args [1];
+ MonoClass *iface = interfaces [i];
+
+ args [0] = &iface->byval_arg;
+ interfaces [i] = mono_class_bind_generic_parameters (
+ generic_ienumerator_class, 1, args, FALSE);
+ /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+ }
+ if (!eclass_is_valuetype) {
+ j = interface_count;
+ for (i = 0; i < eclass->idepth; i++) {
+ MonoType *args [1];
+ args [0] = &eclass->supertypes [i]->byval_arg;
+ interfaces [j] = mono_class_bind_generic_parameters (
+ generic_ienumerator_class, 1, args, FALSE);
+ /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+ j ++;
+ }
+ for (i = 0; i < eclass->interface_offsets_count; i++) {
+ MonoClass *iface = eclass->interfaces_packed [i];
+ MonoType *args [1];
+ args [0] = &iface->byval_arg;
+ interfaces [j] = mono_class_bind_generic_parameters (
+ generic_ienumerator_class, 1, args, FALSE);
+ /*g_print ("%s implements %s\n", class->name, mono_type_get_name_full (&interfaces [i]->byval_arg, 0));*/
+ j ++;
+ }
+ }
+ }
+ *num = real_count;
+ return interfaces;
+}
+
/*
* LOCKING: this is supposed to be called with the loader lock held.
*/
int *interface_offsets_full;
GPtrArray *ifaces;
int interface_offsets_count;
+ MonoClass **array_interfaces;
+ int num_array_interfaces;
+ int is_enumerator = FALSE;
+
+ /*
+ * get the implicit generic interfaces for either the arrays or for System.Array/InternalEnumerator<T>
+ * implicit innterfaces 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);
/* compute maximum number of slots and maximum interface id */
max_iid = 0;
g_ptr_array_free (ifaces, TRUE);
}
}
+ for (i = 0; i < num_array_interfaces; ++i) {
+ ic = array_interfaces [i];
+ mono_class_init (ic);
+ if (max_iid < ic->interface_id)
+ max_iid = ic->interface_id;
+ }
if (MONO_CLASS_IS_INTERFACE (class)) {
if (max_iid < class->interface_id)
interface_offsets_full [class->interface_id] = cur_slot;
}
+ if (num_array_interfaces) {
+ if (is_enumerator) {
+ int ienumerator_offset;
+ g_assert (strcmp (class->interfaces [0]->name, "IEnumerator`1") == 0);
+ ienumerator_offset = interface_offsets_full [class->interfaces [0]->interface_id];
+ for (i = 0; i < num_array_interfaces; ++i) {
+ ic = array_interfaces [i];
+ interfaces_full [ic->interface_id] = ic;
+ if (strcmp (ic->name, "IEnumerator`1") == 0)
+ interface_offsets_full [ic->interface_id] = ienumerator_offset;
+ else
+ g_assert_not_reached ();
+ /*g_print ("type %s has %s offset at %d (%s)\n", class->name, ic->name, interface_offsets_full [ic->interface_id], class->interfaces [0]->name);*/
+ }
+ } else {
+ int ilist_offset, icollection_offset, ienumerable_offset;
+ g_assert (strcmp (class->interfaces [0]->name, "IList`1") == 0);
+ g_assert (strcmp (class->interfaces [0]->interfaces [0]->name, "ICollection`1") == 0);
+ g_assert (strcmp (class->interfaces [0]->interfaces [1]->name, "IEnumerable`1") == 0);
+ ilist_offset = interface_offsets_full [class->interfaces [0]->interface_id];
+ icollection_offset = interface_offsets_full [class->interfaces [0]->interfaces [0]->interface_id];
+ ienumerable_offset = interface_offsets_full [class->interfaces [0]->interfaces [1]->interface_id];
+ g_assert (ilist_offset >= 0 && icollection_offset >= 0 && ienumerable_offset >= 0);
+ for (i = 0; i < num_array_interfaces; ++i) {
+ ic = array_interfaces [i];
+ interfaces_full [ic->interface_id] = ic;
+ if (ic->generic_class->container_class == mono_defaults.generic_ilist_class)
+ interface_offsets_full [ic->interface_id] = ilist_offset;
+ else if (strcmp (ic->name, "ICollection`1") == 0)
+ interface_offsets_full [ic->interface_id] = icollection_offset;
+ else if (strcmp (ic->name, "IEnumerable`1") == 0)
+ interface_offsets_full [ic->interface_id] = ienumerable_offset;
+ else
+ g_assert_not_reached ();
+ /*g_print ("type %s has %s offset at %d (%s)\n", class->name, ic->name, interface_offsets_full [ic->interface_id], class->interfaces [0]->name);*/
+ }
+ }
+ }
+
for (interface_offsets_count = 0, i = 0; i <= max_iid; i++) {
if (interface_offsets_full [i] != -1) {
interface_offsets_count ++;
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 ++;
}
}
g_free (interfaces_full);
g_free (interface_offsets_full);
+ g_free (array_interfaces);
//printf ("JUST DONE: ");
//print_implemented_interfaces (class);
MonoGenericContext *context;
guint32 type_token;
int onum = 0;
+ int i;
gboolean ok = TRUE;
if (class->vtable)
type_token = class->type_token;
}
- if (class->image->dynamic)
- mono_reflection_get_dynamic_overrides (class, &overrides, &onum);
- else {
+ if (class->image->dynamic) {
+ if (class->generic_class) {
+ MonoClass *gklass = class->generic_class->container_class;
+
+ mono_reflection_get_dynamic_overrides (gklass, &overrides, &onum);
+ for (i = 0; i < onum; ++i) {
+ MonoMethod *override = overrides [(i * 2) + 1];
+ MonoMethod *inflated = NULL;
+ int j;
+
+ for (j = 0; j < class->method.count; ++j) {
+ if (gklass->methods [j] == override) {
+ inflated = class->methods [j];
+ break;
+ }
+ }
+ g_assert (inflated);
+
+ overrides [(i * 2) + 1] = inflated;
+ }
+ } else {
+ mono_reflection_get_dynamic_overrides (class, &overrides, &onum);
+ }
+ } else {
/* The following call fails if there are missing methods in the type */
ok = mono_class_get_overrides_full (class->image, type_token, &overrides, &onum, context);
}
}
}
+
+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 ("MONO_USE_NEW_INTERFACE_VTABLE_CODE");
+ if (env_var == NULL) {
+ __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;
+ } else {
+ __use_new_interface_vtable_code = TRUE;
+ }
+ }
+ }
+ return __use_new_interface_vtable_code;
+}
+
+
+#define DEBUG_INTERFACE_VTABLE_CODE 0
+#define TRACE_INTERFACE_VTABLE_CODE 0
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+#define DEBUG_INTERFACE_VTABLE(stmt) do {\
+ stmt;\
+} while (0)
+#else
+#define DEBUG_INTERFACE_VTABLE(stmt)
+#endif
+
+#if TRACE_INTERFACE_VTABLE_CODE
+#define TRACE_INTERFACE_VTABLE(stmt) do {\
+ stmt;\
+} while (0)
+#else
+#define TRACE_INTERFACE_VTABLE(stmt)
+#endif
+
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+static char*
+mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
+{
+ int i;
+ char *result;
+ GString *res = g_string_new ("");
+
+ g_string_append_c (res, '(');
+ for (i = 0; i < sig->param_count; ++i) {
+ if (i > 0)
+ g_string_append_c (res, ',');
+ mono_type_get_desc (res, sig->params [i], include_namespace);
+ }
+ g_string_append (res, ")=>");
+ if (sig->ret != NULL) {
+ mono_type_get_desc (res, sig->ret, include_namespace);
+ } else {
+ g_string_append (res, "NULL");
+ }
+ result = res->str;
+ g_string_free (res, FALSE);
+ return result;
+}
+static void
+print_method_signatures (MonoMethod *im, MonoMethod *cm) {
+ char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
+ char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
+ printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
+ g_free (im_sig);
+ g_free (cm_sig);
+
+}
+
+#endif
+static gboolean
+check_interface_method_override (MonoClass *class, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty, gboolean security_enabled) {
+ if (strcmp (im->name, cm->name) == 0) {
+ if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
+ TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
+ return FALSE;
+ }
+ if (! slot_is_empty) {
+ if (require_newslot) {
+ if (! interface_is_explicitly_implemented_by_class) {
+ TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
+ return FALSE;
+ }
+ if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
+ TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
+ return FALSE;
+ }
+ } else {
+ TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
+ }
+ }
+ if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+ TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("]"));
+ return FALSE;
+ }
+ TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+ TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
+ return TRUE;
+ } else {
+ MonoClass *ic = im->klass;
+ const char *ic_name_space = ic->name_space;
+ const char *ic_name = ic->name;
+ char *subname;
+
+ if (! require_newslot) {
+ TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
+ return FALSE;
+ }
+ if (cm->klass->rank == 0) {
+ TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
+ return FALSE;
+ }
+ if (! mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+ TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("]"));
+ return FALSE;
+ }
+ if (mono_class_get_image (ic) != mono_defaults.corlib) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
+ return FALSE;
+ }
+ if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
+ return FALSE;
+ }
+ if ((ic_name == NULL) || ((strcmp (ic_name, "IEnumerable`1") != 0) && (strcmp (ic_name, "ICollection`1") != 0) && (strcmp (ic_name, "IList`1") != 0))) {
+ TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
+ return FALSE;
+ }
+
+ subname = strstr (cm->name, ic_name_space);
+ if (subname != cm->name) {
+ TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
+ return FALSE;
+ }
+ subname += strlen (ic_name_space);
+ if (subname [0] != '.') {
+ TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
+ return FALSE;
+ }
+ subname ++;
+ if (strstr (subname, ic_name) != subname) {
+ TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
+ return FALSE;
+ }
+ subname += strlen (ic_name);
+ if (subname [0] != '.') {
+ TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
+ return FALSE;
+ }
+ subname ++;
+ if (strcmp (subname, im->name) != 0) {
+ TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
+ return FALSE;
+ }
+
+ TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
+ return TRUE;
+ }
+}
+
+#if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
+static void
+foreach_override (gpointer key, gpointer value, gpointer user_data) {
+ MonoMethod *method = key;
+ MonoMethod *override = value;
+ MonoClass *method_class = mono_method_get_class (method);
+ MonoClass *override_class = mono_method_get_class (override);
+
+ printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
+ mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
+ mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
+}
+static void
+print_overrides (GHashTable *override_map, const char *message) {
+ if (override_map) {
+ printf ("Override map \"%s\" START:\n", message);
+ g_hash_table_foreach (override_map, foreach_override, NULL);
+ printf ("Override map \"%s\" END.\n", message);
+ } else {
+ printf ("Override map \"%s\" EMPTY.\n", message);
+ }
+}
+static void
+print_vtable_full (MonoClass *class, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
+ char *full_name = mono_type_full_name (&class->byval_arg);
+ int i;
+ int parent_size;
+
+ printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
+
+ if (print_interfaces) {
+ print_implemented_interfaces (class);
+ printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
+ }
+
+ if (class->parent) {
+ parent_size = class->parent->vtable_size;
+ } else {
+ parent_size = 0;
+ }
+ for (i = 0; i < size; ++i) {
+ MonoMethod *cm = vtable [i];
+ if (cm) {
+ char *cm_name = mono_method_full_name (cm, TRUE);
+ char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
+ printf (" [%c][%03d][INDEX %03d] %s\n", newness, i, cm->slot, cm_name);
+ g_free (cm_name);
+ }
+ }
+
+ g_free (full_name);
+}
+#endif
+
+static void
+print_unimplemented_interface_method_info (MonoClass *class, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum) {
+ int index;
+ char *method_signature;
+
+ for (index = 0; index < onum; ++index) {
+ g_print (" at slot %d: %s (%d) overrides %s (%d)\n", im_slot, overrides [index*2+1]->name,
+ overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
+ }
+ method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
+ printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
+ mono_type_get_name (&ic->byval_arg), im->name, method_signature, class->name_space, class->name);
+ g_free (method_signature);
+ for (index = 0; index < class->method.count; ++index) {
+ MonoMethod *cm = class->methods [index];
+ method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
+
+ printf ("METHOD %s(%s)\n", cm->name, method_signature);
+ g_free (method_signature);
+ }
+}
+
/*
* LOCKING: this is supposed to be called with the loader lock held.
*/
GPtrArray *ifaces, *pifaces = NULL;
GHashTable *override_map = NULL;
gboolean security_enabled = mono_is_security_manager_active ();
+#if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
+ int first_non_interface_slot;
+#endif
if (class->vtable)
return;
max_vtsize += ic->method.count;
}
g_ptr_array_free (ifaces, TRUE);
+ ifaces = NULL;
}
if (class->parent) {
cur_slot = setup_interface_offsets (class, cur_slot);
max_iid = class->max_interface_id;
+ DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
- if (class->parent && class->parent->vtable_size)
- memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size);
+ if (use_new_interface_vtable_code ()) {
+ if (class->parent && class->parent->vtable_size) {
+ MonoClass *parent = class->parent;
+ int i;
+
+ memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
+
+ // Also inherit parent interface vtables, just as a starting point.
+ // This is needed otherwise bug-77127.exe fails when the property methods
+ // have different names in the iterface and the class, because for child
+ // classes the ".override" information is not used anymore.
+ for (i = 0; i < parent->interface_offsets_count; i++) {
+ MonoClass *parent_interface = parent->interfaces_packed [i];
+ int interface_offset = mono_class_interface_offset (class, parent_interface);
+
+ if (interface_offset >= parent->vtable_size) {
+ int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
+ int j;
+
+ mono_class_setup_methods (parent_interface);
+ TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
+ for (j = 0; j < parent_interface->method.count; j++) {
+ vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
+ TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
+ parent_interface_offset + j, parent_interface_offset, j,
+ interface_offset + j, interface_offset, j));
+ }
+ }
+
+ }
+ }
+ } else {
+ if (class->parent && class->parent->vtable_size)
+ memcpy (vtable, class->parent->vtable, sizeof (gpointer) * class->parent->vtable_size);
+ }
+ TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
/* override interface methods */
for (i = 0; i < onum; i++) {
MonoMethod *decl = overrides [i*2];
check_core_clr_override_method (class, vtable [dslot], decl);
}
}
+ TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
+ TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
- for (k = class; k ; k = k->parent) {
- int nifaces = 0;
-
- ifaces = mono_class_get_implemented_interfaces (k);
- if (ifaces) {
- nifaces = ifaces->len;
- if (k->generic_class) {
- pifaces = mono_class_get_implemented_interfaces (
- k->generic_class->container_class);
- g_assert (pifaces && (pifaces->len == nifaces));
- }
- }
- for (i = 0; i < nifaces; i++) {
- MonoClass *pic = NULL;
- int j, l, io;
-
- ic = g_ptr_array_index (ifaces, i);
- if (pifaces)
- pic = g_ptr_array_index (pifaces, i);
- g_assert (ic->interface_id <= k->max_interface_id);
- io = mono_class_interface_offset (k, ic);
-
- g_assert (io >= 0);
- g_assert (io <= max_vtsize);
-
- if (k == class) {
- mono_class_setup_methods (ic);
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
-
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- continue;
-
- for (j = 0; j < class->method.count; ++j) {
- MonoMethod *cm = class->methods [j];
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) ||
- !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
- continue;
- if (!strcmp(cm->name, im->name) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
- }
-
- if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
+ if (use_new_interface_vtable_code ()) {
+ // Loop on all implemented interfaces...
+ for (i = 0; i < class->interface_offsets_count; i++) {
+ MonoClass *parent = class->parent;
+ int ic_offset;
+ gboolean interface_is_explicitly_implemented_by_class;
+ int im_index;
+
+ ic = class->interfaces_packed [i];
+ ic_offset = mono_class_interface_offset (class, ic);
- g_assert (io + l <= max_vtsize);
- vtable [io + l] = cm;
- }
+ mono_class_setup_methods (ic);
+
+ // Check if this interface is explicitly implemented (instead of just inherited)
+ if (parent != NULL) {
+ int implemented_interfaces_index;
+ interface_is_explicitly_implemented_by_class = FALSE;
+ for (implemented_interfaces_index = 0; implemented_interfaces_index < class->interface_count; implemented_interfaces_index++) {
+ if (ic == class->interfaces [implemented_interfaces_index]) {
+ interface_is_explicitly_implemented_by_class = TRUE;
+ break;
}
}
} else {
- /* already implemented */
- if (io >= k->vtable_size)
- continue;
+ interface_is_explicitly_implemented_by_class = TRUE;
}
-
- // Override methods with the same fully qualified name
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
- char *qname, *fqname, *cname, *the_cname;
- MonoClass *k1;
+
+ // Loop on all interface methods...
+ for (im_index = 0; im_index < ic->method.count; im_index++) {
+ MonoMethod *im = ic->methods [im_index];
+ int im_slot = ic_offset + im->slot;
+ MonoMethod *override_im = (override_map != NULL) ? g_hash_table_lookup (override_map, im) : NULL;
- if (vtable [io + l])
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
continue;
- if (pic) {
- the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
- cname = the_cname;
+ // If there is an explicit implementation, just use it right away,
+ // otherwise look for a matching method
+ if (override_im == NULL) {
+ int cm_index;
+
+ // First look for a suitable method among the class methods
+ for (cm_index = 0; cm_index < class->method.count; cm_index++) {
+ MonoMethod *cm = class->methods [cm_index];
+
+ TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
+ if ((cm->flags & METHOD_ATTRIBUTE_VIRTUAL) && check_interface_method_override (class, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL), security_enabled)) {
+ TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
+ vtable [im_slot] = cm;
+ /* Why do we need this? */
+ if (cm->slot < 0) {
+ cm->slot = im_slot;
+ }
+ }
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ }
+
+ // If the slot is still empty, look in all the inherited virtual methods...
+ if ((vtable [im_slot] == NULL) && class->parent != NULL) {
+ MonoClass *parent = class->parent;
+ // Reverse order, so that last added methods are preferred
+ for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
+ MonoMethod *cm = parent->vtable [cm_index];
+
+ TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
+ if ((cm != NULL) && check_interface_method_override (class, im, cm, FALSE, FALSE, TRUE, security_enabled)) {
+ TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
+ vtable [im_slot] = cm;
+ /* Why do we need this? */
+ if (cm->slot < 0) {
+ cm->slot = im_slot;
+ }
+ break;
+ }
+ TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
+ }
+ }
} else {
- the_cname = NULL;
- cname = (char*)ic->name;
+ g_assert (vtable [im_slot] == override_im);
}
+ }
+ }
+
+ // If the class is not abstract, check that all its interface slots are full.
+ // The check is done here and not directly at the end of the loop above because
+ // it can happen (for injected generic array interfaces) that the same slot is
+ // processed multiple times (those interfaces have overlapping slots), and it
+ // will not always be the first pass the one that fills the slot.
+ if (! (class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ for (i = 0; i < class->interface_offsets_count; i++) {
+ int ic_offset;
+ int im_index;
+
+ ic = class->interfaces_packed [i];
+ ic_offset = mono_class_interface_offset (class, ic);
+
+ for (im_index = 0; im_index < ic->method.count; im_index++) {
+ MonoMethod *im = ic->methods [im_index];
+ int im_slot = ic_offset + im->slot;
- qname = g_strconcat (cname, ".", im->name, NULL);
- if (ic->name_space && ic->name_space [0])
- fqname = g_strconcat (ic->name_space, ".", cname, ".", im->name, NULL);
- else
- fqname = NULL;
+ if (im->flags & METHOD_ATTRIBUTE_STATIC)
+ continue;
- for (k1 = class; k1; k1 = k1->parent) {
- for (j = 0; j < k1->method.count; ++j) {
- MonoMethod *cm = k1->methods [j];
+ 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) {
+ print_unimplemented_interface_method_info (class, ic, im, im_slot, overrides, onum);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ if (override_map)
+ g_hash_table_destroy (override_map);
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ for (k = class; k ; k = k->parent) {
+ int nifaces = 0;
+
+ ifaces = mono_class_get_implemented_interfaces (k);
+ if (ifaces) {
+ nifaces = ifaces->len;
+ if (k->generic_class) {
+ pifaces = mono_class_get_implemented_interfaces (
+ k->generic_class->container_class);
+ g_assert (pifaces && (pifaces->len == nifaces));
+ }
+ }
+ for (i = 0; i < nifaces; i++) {
+ MonoClass *pic = NULL;
+ int j, l, io;
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
- continue;
+ ic = g_ptr_array_index (ifaces, i);
+ if (pifaces)
+ pic = g_ptr_array_index (pifaces, i);
+ g_assert (ic->interface_id <= k->max_interface_id);
+ io = mono_class_interface_offset (k, ic);
- if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) &&
- ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) {
+ g_assert (io >= 0);
+ g_assert (io <= max_vtsize);
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
- }
+ if (k == class) {
+ mono_class_setup_methods (ic);
+ for (l = 0; l < ic->method.count; l++) {
+ MonoMethod *im = ic->methods [l];
- if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
+ if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ continue;
- g_assert (io + l <= max_vtsize);
- vtable [io + l] = cm;
- break;
+ for (j = 0; j < class->method.count; ++j) {
+ MonoMethod *cm = class->methods [j];
+ if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+ !((cm->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == METHOD_ATTRIBUTE_PUBLIC) ||
+ !(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT))
+ continue;
+ if (!strcmp(cm->name, im->name) &&
+ mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ g_assert (io + l <= max_vtsize);
+ vtable [io + l] = cm;
+ TRACE_INTERFACE_VTABLE (printf (" [NOA] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ }
}
}
+ } else {
+ /* already implemented */
+ if (io >= k->vtable_size)
+ continue;
}
- g_free (the_cname);
- g_free (qname);
- g_free (fqname);
- }
- // Override methods with the same name
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = ic->methods [l];
- MonoClass *k1;
-
- g_assert (io + l <= max_vtsize);
-
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- continue;
+ // Override methods with the same fully qualified name
+ for (l = 0; l < ic->method.count; l++) {
+ MonoMethod *im = ic->methods [l];
+ char *qname, *fqname, *cname, *the_cname;
+ MonoClass *k1;
- for (k1 = class; k1; k1 = k1->parent) {
- for (j = 0; j < k1->method.count; ++j) {
- MonoMethod *cm = k1->methods [j];
+ if (vtable [io + l])
+ continue;
- if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
- !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
- continue;
+ if (pic) {
+ the_cname = mono_type_get_name_full (&pic->byval_arg, MONO_TYPE_NAME_FORMAT_IL);
+ cname = the_cname;
+ } else {
+ the_cname = NULL;
+ cname = (char*)ic->name;
+ }
- if (!strcmp(cm->name, im->name) &&
- mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
-
- /* CAS - SecurityAction.InheritanceDemand on interface */
- if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
- mono_secman_inheritancedemand_method (cm, im);
+ qname = g_strconcat (cname, ".", im->name, NULL);
+ if (ic->name_space && ic->name_space [0])
+ fqname = g_strconcat (ic->name_space, ".", cname, ".", im->name, NULL);
+ else
+ fqname = NULL;
+
+ for (k1 = class; k1; k1 = k1->parent) {
+ for (j = 0; j < k1->method.count; ++j) {
+ MonoMethod *cm = k1->methods [j];
+
+ if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
+ continue;
+
+ if (((fqname && !strcmp (cm->name, fqname)) || !strcmp (cm->name, qname)) &&
+ mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im)) &&
+ ((vtable [io + l] == NULL) || mono_class_is_subclass_of (cm->klass, vtable [io + l]->klass, FALSE))) {
+
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ g_assert (io + l <= max_vtsize);
+ vtable [io + l] = cm;
+ TRACE_INTERFACE_VTABLE (printf (" [FQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ break;
}
-
- if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
- check_core_clr_override_method (class, cm, im);
-
- g_assert (io + l <= max_vtsize);
- vtable [io + l] = cm;
- break;
}
-
}
- g_assert (io + l <= max_vtsize);
- if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
- break;
+ g_free (the_cname);
+ g_free (qname);
+ g_free (fqname);
}
- }
- if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ // Override methods with the same name
for (l = 0; l < ic->method.count; l++) {
- char *msig;
- MonoMethod *im = ic->methods [l];
- if (im->flags & METHOD_ATTRIBUTE_STATIC)
- continue;
+ MonoMethod *im = ic->methods [l];
+ MonoClass *k1;
+
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 (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ continue;
- for (; parent; parent = parent->parent) {
- if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) &&
- parent->vtable) {
- vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l];
+ for (k1 = class; k1; k1 = k1->parent) {
+ for (j = 0; j < k1->method.count; ++j) {
+ MonoMethod *cm = k1->methods [j];
+
+ if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
+ !(cm->flags & METHOD_ATTRIBUTE_PUBLIC))
+ continue;
+
+ if (!strcmp(cm->name, im->name) &&
+ mono_metadata_signature_equal (mono_method_signature (cm), mono_method_signature (im))) {
+
+ /* CAS - SecurityAction.InheritanceDemand on interface */
+ if (security_enabled && (im->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
+ mono_secman_inheritancedemand_method (cm, im);
+ }
+
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
+ check_core_clr_override_method (class, cm, im);
+
+ g_assert (io + l <= max_vtsize);
+ vtable [io + l] = cm;
+ TRACE_INTERFACE_VTABLE (printf (" [SQN] Filling slot %d (%d+%d) with method '%s'.'%s':'%s' ", io + l, io, l, cm->klass->name_space, cm->klass->name, cm->name));
+ TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
+ TRACE_INTERFACE_VTABLE (printf ("\n"));
+ break;
}
+
}
+ g_assert (io + l <= max_vtsize);
+ if (vtable [io + l] && !(vtable [io + l]->flags & METHOD_ATTRIBUTE_ABSTRACT))
+ break;
}
+ }
- 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,
- overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
- }
- msig = mono_signature_get_desc (mono_method_signature (im), FALSE);
- printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
- mono_type_get_name (&ic->byval_arg), im->name, msig, class->name_space, class->name);
- g_free (msig);
- for (j = 0; j < class->method.count; ++j) {
- MonoMethod *cm = class->methods [j];
- msig = mono_signature_get_desc (mono_method_signature (cm), TRUE);
+ if (!(class->flags & TYPE_ATTRIBUTE_ABSTRACT)) {
+ for (l = 0; l < ic->method.count; l++) {
+ char *msig;
+ MonoMethod *im = ic->methods [l];
+ 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;
- printf ("METHOD %s(%s)\n", cm->name, msig);
- g_free (msig);
+ for (; parent; parent = parent->parent) {
+ if (MONO_CLASS_IMPLEMENTS_INTERFACE (parent, ic->interface_id) &&
+ parent->vtable) {
+ vtable [io + l] = parent->vtable [mono_class_interface_offset (parent, ic) + l];
+ TRACE_INTERFACE_VTABLE (printf (" [INH] Filling slot %d (%d+%d) with method '%s'.'%s':'%s'\n", io + l, io, l, vtable [io + l]->klass->name_space, vtable [io + l]->klass->name, vtable [io + l]->name));
+ }
+ }
}
- mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ 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,
+ overrides [j*2+1]->slot, overrides [j*2]->name, overrides [j*2]->slot);
+ }
+ msig = mono_signature_get_desc (mono_method_signature (im), FALSE);
+ printf ("no implementation for interface method %s::%s(%s) in class %s.%s\n",
+ mono_type_get_name (&ic->byval_arg), im->name, msig, class->name_space, class->name);
+ g_free (msig);
+ for (j = 0; j < class->method.count; ++j) {
+ MonoMethod *cm = class->methods [j];
+ msig = mono_signature_get_desc (mono_method_signature (cm), TRUE);
+
+ printf ("METHOD %s(%s)\n", cm->name, msig);
+ g_free (msig);
+ }
+
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
- if (ifaces)
- g_ptr_array_free (ifaces, TRUE);
- if (override_map)
- g_hash_table_destroy (override_map);
+ if (ifaces)
+ g_ptr_array_free (ifaces, TRUE);
+ if (override_map)
+ g_hash_table_destroy (override_map);
- return;
+ return;
+ }
}
}
- }
-
- for (l = 0; l < ic->method.count; l++) {
- MonoMethod *im = vtable [io + l];
-
- if (im) {
- g_assert (io + l <= max_vtsize);
- if (im->slot < 0) {
- /* FIXME: why do we need this ? */
- im->slot = io + l;
- /* g_assert_not_reached (); */
+
+ for (l = 0; l < ic->method.count; l++) {
+ MonoMethod *im = vtable [io + l];
+
+ if (im) {
+ g_assert (io + l <= max_vtsize);
+ if (im->slot < 0) {
+ /* FIXME: why do we need this ? */
+ im->slot = io + l;
+ /* g_assert_not_reached (); */
+ }
}
}
}
- }
- if (ifaces)
- g_ptr_array_free (ifaces, TRUE);
- }
+ if (ifaces)
+ g_ptr_array_free (ifaces, TRUE);
+ }
+ }
+ TRACE_INTERFACE_VTABLE (print_vtable_full (class, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
for (i = 0; i < class->method.count; ++i) {
MonoMethod *cm;
memcpy (class->vtable, vtable, sizeof (gpointer) * class->vtable_size);
}
+ DEBUG_INTERFACE_VTABLE (print_vtable_full (class, class->vtable, class->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
if (mono_print_vtable) {
int icount = 0;
return n;
}
-static void
-setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
-{
- MonoGenericContext tmp_context;
- int i;
+typedef struct {
+ MonoMethod *array_method;
+ char *name;
+} GenericArrayMethodInfo;
- tmp_context.class_inst = NULL;
- tmp_context.method_inst = iface->generic_class->context.class_inst;
+static int generic_array_method_num = 0;
+static GenericArrayMethodInfo *generic_array_method_info = NULL;
+static int
+generic_array_methods (MonoClass *class)
+{
+ int i, count_generic = 0;
+ GList *list = NULL, *tmp;
+ if (generic_array_method_num)
+ return generic_array_method_num;
+ mono_class_setup_methods (class->parent);
for (i = 0; i < class->parent->method.count; i++) {
MonoMethod *m = class->parent->methods [i];
- MonoMethod *inflated;
+ if (!strncmp (m->name, "InternalArray__", 15)) {
+ count_generic++;
+ list = g_list_prepend (list, m);
+ }
+ }
+ list = g_list_reverse (list);
+ generic_array_method_info = g_malloc (sizeof (GenericArrayMethodInfo) * count_generic);
+ i = 0;
+ for (tmp = list; tmp; tmp = tmp->next) {
const char *mname, *iname;
gchar *name;
-
+ MonoMethod *m = tmp->data;
+ generic_array_method_info [i].array_method = m;
if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
iname = "System.Collections.Generic.ICollection`1.";
mname = m->name + 27;
iname = "System.Collections.Generic.IList`1.";
mname = m->name + 15;
} else {
- continue;
+ g_assert_not_reached ();
}
- name = mono_mempool_alloc (class->image->mempool, strlen (iname) + strlen (mname) + 1);
+ name = mono_mempool_alloc (mono_defaults.corlib->mempool, strlen (iname) + strlen (mname) + 1);
strcpy (name, iname);
strcpy (name + strlen (iname), mname);
+ generic_array_method_info [i].name = name;
+ i++;
+ }
+ /*g_print ("array generic methods: %d\n", count_generic);*/
+
+ generic_array_method_num = count_generic;
+ return generic_array_method_num;
+}
+
+static void
+setup_generic_array_ifaces (MonoClass *class, MonoClass *iface, int pos)
+{
+ MonoGenericContext tmp_context;
+ int i;
+
+ tmp_context.class_inst = NULL;
+ tmp_context.method_inst = iface->generic_class->context.class_inst;
+ //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
+
+ for (i = 0; i < generic_array_method_num; i++) {
+ MonoMethod *m = generic_array_method_info [i].array_method;
+ MonoMethod *inflated;
inflated = mono_class_inflate_generic_method (m, &tmp_context);
- class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, name, inflated);
+ class->methods [pos++] = mono_marshal_get_generic_array_helper (class, iface, generic_array_method_info [i].name, inflated);
}
}
break;
}
+ case MONO_EXCEPTION_BAD_IMAGE:
+ class->exception_data = error->msg;
+ break;
+
default :
g_assert_not_reached ();
}
if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
check_core_clr_inheritance (class);
- if (mono_debugger_start_class_init_func)
- mono_debugger_start_class_init_func (class);
-
mono_stats.initialized_class_count++;
if (class->generic_class && !class->generic_class->is_dynamic) {
if (MONO_CLASS_IS_INTERFACE (class))
class->interface_id = mono_get_unique_iid (class);
- g_assert (class->method.count == gklass->method.count);
- class->methods = g_new0 (MonoMethod *, class->method.count);
-
- for (i = 0; i < class->method.count; i++) {
- class->methods [i] = mono_class_inflate_generic_method_full (
- gklass->methods [i], class, mono_class_get_context (class));
- }
-
- class->property = gklass->property;
- class->properties = g_new0 (MonoProperty, class->property.count);
-
- for (i = 0; i < class->property.count; i++) {
- MonoProperty *prop = &class->properties [i];
-
- *prop = gklass->properties [i];
-
- if (prop->get)
- prop->get = mono_class_inflate_generic_method_full (
- prop->get, class, mono_class_get_context (class));
- if (prop->set)
- prop->set = mono_class_inflate_generic_method_full (
- prop->set, class, mono_class_get_context (class));
-
- prop->parent = class;
- }
-
g_assert (class->interface_count == gklass->interface_count);
}
class->method.count = 3 + (class->rank > 1? 2: 1);
if (class->interface_count) {
- for (i = 0; i < class->parent->method.count; i++) {
- MonoMethod *m = class->parent->methods [i];
- if (!strncmp (m->name, "InternalArray__", 15))
- count_generic++;
- }
+ count_generic = generic_array_methods (class);
first_generic = class->method.count;
class->method.count += class->interface_count * count_generic;
}
/*class->enumtype = class->parent->enumtype; */
mono_class_setup_supertypes (class);
} else {
+ /* initialize com types if COM interfaces are present */
+ if (MONO_CLASS_IS_IMPORT (class))
+ mono_init_com_types ();
class->parent = NULL;
}
class->name = name;
class->name_space = nspace;
+ mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
+
class->image = image;
class->type_token = type_token;
class->flags = cols [MONO_TYPEDEF_FLAGS];
if (parent == NULL){
mono_internal_hash_table_remove (&image->class_cache, GUINT_TO_POINTER (type_token));
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
return NULL;
}
}
if (!mono_metadata_interfaces_from_typedef_full (
image, type_token, &interfaces, &icount, context)){
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_FAILED);
return NULL;
}
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_OK);
+
return class;
}
mono_loader_lock ();
if (gclass->cached_class) {
mono_loader_unlock ();
- g_assert (!gclass->cached_class->generic_container);
return gclass->cached_class;
}
MonoType *inflated = mono_class_inflate_generic_type (
&gklass->nested_in->byval_arg, mono_generic_class_get_context (gclass));
klass->nested_in = mono_class_from_mono_type (inflated);
+ mono_metadata_free_type (inflated);
}
klass->name = gklass->name;
klass->name_space = gklass->name_space;
+
+ mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+
klass->image = gklass->image;
klass->flags = gklass->flags;
klass->type_token = gklass->type_token;
+ klass->field.count = gklass->field.count;
+ klass->property.count = gklass->property.count;
klass->generic_class = gclass;
klass->this_arg.type = klass->byval_arg.type = MONO_TYPE_GENERICINST;
klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
klass->this_arg.byref = TRUE;
+ klass->enumtype = gklass->enumtype;
+ klass->valuetype = gklass->valuetype;
klass->cast_class = klass->element_class = klass;
if (mono_class_is_nullable (klass))
klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
- if (gclass->is_dynamic) {
- klass->instance_size = gklass->instance_size;
- klass->sizes.class_size = gklass->sizes.class_size;
- klass->size_inited = 1;
- klass->inited = 1;
-
- klass->valuetype = gklass->valuetype;
-
- mono_class_setup_supertypes (klass);
- }
-
klass->interface_count = gklass->interface_count;
klass->interfaces = g_new0 (MonoClass *, klass->interface_count);
for (i = 0; i < klass->interface_count; i++) {
MonoType *it = &gklass->interfaces [i]->byval_arg;
MonoType *inflated = mono_class_inflate_generic_type (it, mono_generic_class_get_context (gclass));
klass->interfaces [i] = mono_class_from_mono_type (inflated);
+ mono_metadata_free_type (inflated);
}
/*
&gklass->parent->byval_arg, mono_generic_class_get_context (gclass));
klass->parent = mono_class_from_mono_type (inflated);
+ mono_metadata_free_type (inflated);
}
if (klass->parent)
klass->cast_class = gklass->cast_class;
}
+ if (gclass->is_dynamic) {
+ klass->inited = 1;
+
+ mono_class_setup_supertypes (klass);
+
+ if (klass->enumtype) {
+ /*
+ * For enums, gklass->fields might not been set, but instance_size etc. is
+ * already set in mono_reflection_create_internal_class (). For non-enums,
+ * these will be computed normally in mono_class_layout_fields ().
+ */
+ klass->instance_size = gklass->instance_size;
+ klass->sizes.class_size = gklass->sizes.class_size;
+ klass->size_inited = 1;
+ }
+ }
+
if (MONO_CLASS_IS_INTERFACE (klass))
setup_interface_offsets (klass, 0);
+ mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+
mono_loader_unlock ();
return klass;
MonoClass *klass, **ptr;
int count, pos, i;
- if (param->pklass)
+ mono_loader_lock ();
+
+ if (param->pklass) {
+ mono_loader_unlock ();
return param->pklass;
+ }
+
+ if (!image && param->owner) {
+ if (is_mvar) {
+ MonoMethod *method = param->owner->owner.method;
+ image = (method && method->klass) ? method->klass->image : NULL;
+ } else {
+ MonoClass *klass = param->owner->owner.klass;
+ // FIXME: 'klass' should not be null
+ // But, monodis creates GenericContainers without associating a owner to it
+ image = klass ? klass->image : NULL;
+ }
+ }
+ if (!image)
+ /* FIXME: */
+ image = mono_defaults.corlib;
- klass = param->pklass = g_new0 (MonoClass, 1);
+ klass = param->pklass = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass));
+ if (param->name)
+ klass->name = param->name;
+ else {
+ klass->name = mono_mempool_alloc0 (image->mempool, 16);
+ sprintf ((char*)klass->name, is_mvar ? "!!%d" : "!%d", param->num);
+ }
+ klass->name_space = "";
+ mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+
for (count = 0, ptr = param->constraints; ptr && *ptr; ptr++, count++)
;
if (count - pos > 0) {
klass->interface_count = count - pos;
- klass->interfaces = g_new0 (MonoClass *, count - pos);
+ klass->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass *) * (count - pos));
for (i = pos; i < count; i++)
klass->interfaces [i - pos] = param->constraints [i];
}
- if (param->name)
- klass->name = param->name;
- else
- klass->name = g_strdup_printf (is_mvar ? "!!%d" : "!%d", param->num);
-
- klass->name_space = "";
-
- if (!image && param->owner) {
- if (is_mvar) {
- MonoMethod *method = param->owner->owner.method;
- image = (method && method->klass) ? method->klass->image : NULL;
- } else {
- MonoClass *klass = param->owner->owner.klass;
- // FIXME: 'klass' should not be null
- // But, monodis creates GenericContainers without associating a owner to it
- image = klass ? klass->image : NULL;
- }
- }
-
if (!image)
image = mono_defaults.corlib;
mono_class_setup_supertypes (klass);
+ mono_loader_unlock ();
+
+ mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+
return klass;
}
name = g_strdup_printf ("%s*", el_class->name);
result->name = mono_mempool_strdup (image->mempool, name);
g_free (name);
+
+ mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+
result->image = el_class->image;
result->inited = TRUE;
result->flags = TYPE_ATTRIBUTE_CLASS | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK);
mono_loader_unlock ();
+ mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+
return result;
}
result->parent = NULL; /* no parent for PTR types */
result->name_space = "System";
result->name = "MonoFNPtrFakeClass";
+
+ mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+
result->image = mono_defaults.corlib; /* need to fix... */
result->inited = TRUE;
result->flags = TYPE_ATTRIBUTE_CLASS; /* | (el_class->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK); */
mono_loader_unlock ();
+ mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+
return result;
}
name [nsize + rank + 1] = 0;
class->name = mono_mempool_strdup (image->mempool, name);
g_free (name);
+
+ mono_profiler_class_event (class, MONO_PROFILE_START_LOAD);
+
class->type_token = 0;
/* all arrays are marked serializable and sealed, bug #42779 */
class->flags = TYPE_ATTRIBUTE_CLASS | TYPE_ATTRIBUTE_SERIALIZABLE | TYPE_ATTRIBUTE_SEALED |
mono_class_setup_supertypes (class);
- if (mono_defaults.generic_ilist_class) {
- MonoClass *fclass = NULL;
- int i;
-
- if (eclass->valuetype) {
- if (eclass == mono_defaults.int16_class)
- fclass = mono_defaults.uint16_class;
- if (eclass == mono_defaults.uint16_class)
- fclass = mono_defaults.int16_class;
- if (eclass == mono_defaults.int32_class)
- fclass = mono_defaults.uint32_class;
- if (eclass == mono_defaults.uint32_class)
- fclass = mono_defaults.int32_class;
- if (eclass == mono_defaults.int64_class)
- fclass = mono_defaults.uint64_class;
- if (eclass == mono_defaults.uint64_class)
- fclass = mono_defaults.int64_class;
- if (eclass == mono_defaults.byte_class)
- fclass = mono_defaults.sbyte_class;
- if (eclass == mono_defaults.sbyte_class)
- fclass = mono_defaults.byte_class;
-
- class->interface_count = fclass ? 2 : 1;
- } else if (MONO_CLASS_IS_INTERFACE (eclass)) {
- class->interface_count = 2 + eclass->interface_count;
- } else {
- class->interface_count = eclass->idepth + eclass->interface_count;
- }
+ if (mono_defaults.generic_ilist_class && !bounded && rank == 1) {
+ MonoType *args [1];
+ /* generic IList, ICollection, IEnumerable */
+ class->interface_count = 1;
class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
- for (i = 0; i < class->interface_count; i++) {
- MonoType *args [1];
- MonoClass *iface;
-
- if (eclass->valuetype)
- iface = (i == 0) ? eclass : fclass;
- else if (MONO_CLASS_IS_INTERFACE (eclass)) {
- if (i == 0)
- iface = mono_defaults.object_class;
- else if (i == 1)
- iface = eclass;
- else
- iface = eclass->interfaces [i - 2];
- } else {
- if (i < eclass->idepth)
- iface = eclass->supertypes [i];
- else
- iface = eclass->interfaces [i - eclass->idepth];
- }
-
- args [0] = &iface->byval_arg;
-
- class->interfaces [i] = mono_class_bind_generic_parameters (
- mono_defaults.generic_ilist_class, 1, args, FALSE);
- }
+ args [0] = &eclass->byval_arg;
+ class->interfaces [0] = mono_class_bind_generic_parameters (
+ mono_defaults.generic_ilist_class, 1, args, FALSE);
}
if (eclass->generic_class)
mono_loader_unlock ();
+ mono_profiler_class_loaded (class, MONO_PROFILE_OK);
+
return class;
}
return 0;
}
+/*
+ * mono_class_get_field_default_value:
+ *
+ * Return the default value of the field as a pointer into the metadata blob.
+ */
+const char*
+mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
+{
+ guint32 cindex;
+ guint32 constant_cols [MONO_CONSTANT_SIZE];
+
+ 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);
+ g_assert (cindex);
+ g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
+
+ mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
+ field->def_type = constant_cols [MONO_CONSTANT_TYPE];
+ field->data = (gpointer)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
+ }
+
+ *def_type = field->def_type;
+ return field->data;
+}
+
guint32
mono_class_get_event_token (MonoEvent *event)
{
{
MonoClass *class = NULL;
- if (image->dynamic)
- return mono_lookup_dynamic_token (image, type_token);
+ if (image->dynamic) {
+ int table = mono_metadata_token_table (type_token);
+
+ if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
+ mono_loader_set_error_bad_image (g_strdup ("Bad type token."));
+ return NULL;
+ }
+ return mono_lookup_dynamic_token (image, type_token, context);
+ }
switch (type_token & 0xff000000){
case MONO_TOKEN_TYPE_DEF:
//FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
if (image->dynamic)
- return mono_class_get_type (mono_lookup_dynamic_token (image, type_token));
+ return mono_class_get_type (mono_lookup_dynamic_token (image, type_token, context));
if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
MonoClass *class = mono_class_get_full (image, type_token, context);
for (i = 1; i <= t->rows; ++i) {
mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
- /* nested types are accessed from the nesting name */
visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
- if (visib > TYPE_ATTRIBUTE_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_ASSEMBLY)
+ /*
+ * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
+ * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
+ */
+ if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
continue;
name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
/**
* mono_class_from_name_case:
- * @image: The MonoImage where the type is looked up in, or NULL for looking up in all loaded assemblies
+ * @image: The MonoImage where the type is looked up in
* @name_space: the type namespace
* @name: the type short name.
*
/* add a cache if needed */
for (i = 1; i <= t->rows; ++i) {
mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
- /* nested types are accessed from the nesting name */
visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
- if (visib > TYPE_ATTRIBUTE_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_ASSEMBLY)
+ /*
+ * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
+ * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
+ */
+ if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
continue;
n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
/**
* mono_class_from_name:
- * @image: The MonoImage where the type is looked up in, or NULL for looking up in all loaded assemblies
+ * @image: The MonoImage where the type is looked up in
* @name_space: the type namespace
* @name: the type short name.
*
GHashTable *nspace_table;
MonoImage *loaded_image;
guint32 token = 0;
+ int i;
MonoClass *class;
char *nested;
char buf [1024];
mono_loader_unlock ();
+ if (!token && image->dynamic && image->modules) {
+ /* Search modules as well */
+ for (i = 0; i < image->module_count; ++i) {
+ MonoImage *module = image->modules [i];
+
+ class = mono_class_from_name (module, name_space, name);
+ if (class)
+ return class;
+ }
+ }
+
if (!token)
return NULL;
return FALSE;
}
+static gboolean
+mono_class_has_variant_generic_params (MonoClass *klass)
+{
+ int i;
+ MonoGenericContainer *container;
+
+ if (!klass->generic_class)
+ return FALSE;
+
+ container = klass->generic_class->container_class->generic_container;
+
+ for (i = 0; i < container->type_argc; ++i)
+ if (container->type_params [i].flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * mono_class_is_assignable_from:
+ * @klass: the class to be assigned to
+ * @oklass: the source class
+ *
+ * Return: true if an instance of object oklass can be assigned to an
+ * instance of object @klass
+ */
gboolean
mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
{
if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
return TRUE;
+
+ if (mono_class_has_variant_generic_params (klass)) {
+ if (oklass->generic_class) {
+ int i;
+ gboolean match = FALSE;
+ MonoClass *container_class1 = klass->generic_class->container_class;
+ MonoClass *container_class2 = oklass->generic_class->container_class;
+
+ /*
+ * Check whenever the generic definition of oklass implements the
+ * generic definition of klass. The IMPLEMENTS_INTERFACE stuff is not usable
+ * here since the relevant tables are not set up.
+ */
+ for (i = 0; i < container_class2->interface_offsets_count; ++i)
+ if ((container_class2->interfaces_packed [i] == container_class1) || (container_class2->interfaces_packed [i]->generic_class && (container_class2->interfaces_packed [i]->generic_class->container_class == container_class1)))
+ match = TRUE;
+
+ if (match) {
+ MonoGenericContainer *container;
+
+ container = klass->generic_class->container_class->generic_container;
+
+ match = TRUE;
+ for (i = 0; i < container->type_argc; ++i) {
+ 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]);
+
+ /*
+ * The _VARIANT and _COVARIANT constants should read _COVARIANT and
+ * _CONTRAVARIANT, but they are in a public header so we can't fix it.
+ */
+ if (param1_class != param2_class) {
+ if ((container->type_params [i].flags & MONO_GEN_PARAM_VARIANT) && mono_class_is_assignable_from (param1_class, param2_class))
+ ;
+ else if (((container->type_params [i].flags & MONO_GEN_PARAM_COVARIANT) && mono_class_is_assignable_from (param2_class, param1_class)))
+ ;
+ else
+ match = FALSE;
+ }
+ }
+
+ if (match)
+ return TRUE;
+ }
+ }
+ }
} else if (klass->rank) {
MonoClass *eclass, *eoclass;
return mono_class_has_parent (oklass, klass);
}
-/*
+/**
* mono_class_get_cctor:
+ * @klass: A MonoClass pointer
*
- * Returns the static constructor of @klass if it exists, NULL otherwise.
+ * Returns: the static constructor of @klass if it exists, NULL otherwise.
*/
MonoMethod*
mono_class_get_cctor (MonoClass *klass)
return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
}
-/*
+/**
* mono_class_get_finalizer:
+ * @klass: The MonoClass pointer
*
- * Returns the finalizer method of @klass if it exists, NULL otherwise.
+ * Returns: the finalizer method of @klass if it exists, NULL otherwise.
*/
MonoMethod*
mono_class_get_finalizer (MonoClass *klass)
}
}
-/*
+/**
* mono_class_needs_cctor_run:
+ * @klass: the MonoClass pointer
+ * @caller: a MonoMethod describing the caller
*
- * Determines whenever the class has a static constructor and whenever it
+ * Determines whenever the class has a static constructor and whenever it
* needs to be called when executing CALLER.
*/
gboolean
{
if (image->dynamic) {
MonoClass *tmp_handle_class;
- gpointer obj = mono_lookup_dynamic_token_class (image, token, &tmp_handle_class);
+ gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context);
g_assert (tmp_handle_class);
if (handle_class)
mono_class_init (class);
return mono_class_get_field (class, token);
}
- case MONO_TOKEN_METHOD_DEF: {
+ case MONO_TOKEN_METHOD_DEF:
+ case MONO_TOKEN_METHOD_SPEC: {
MonoMethod *meth;
meth = mono_get_method_full (image, token, NULL, context);
if (handle_class)
}
gpointer
-mono_lookup_dynamic_token (MonoImage *image, guint32 token)
+mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context)
{
MonoClass *handle_class;
- return lookup_dynamic (image, token, &handle_class);
+ return lookup_dynamic (image, token, TRUE, &handle_class, context);
}
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
{
- return lookup_dynamic (image, token, handle_class);
+ return lookup_dynamic (image, token, valid_token, handle_class, context);
}
static MonoGetCachedClassInfo get_cached_class_info = NULL;
return field->type->attrs;
}
+/**
+ * mono_field_get_offset;
+ * @field: the MonoClassField to act on
+ *
+ * Returns: the field offset.
+ */
+guint32
+mono_field_get_offset (MonoClassField *field)
+{
+ return field->offset;
+}
+
/**
* mono_field_get_data;
* @field: the MonoClassField to act on
return ex;
}
+ case MONO_EXCEPTION_BAD_IMAGE: {
+ return mono_get_exception_bad_image_format (klass->exception_data);
+ }
default: {
MonoLoaderError *error;
MonoException *ex;
can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
{
MonoClass *member_generic_def;
- if (access_klass->generic_class && access_klass->generic_class->container_class &&
+ if (((access_klass->generic_class && access_klass->generic_class->container_class) ||
+ access_klass->generic_container) &&
(member_generic_def = get_generic_definition_class (member_klass))) {
- if (can_access_member (access_klass->generic_class->container_class,
- member_generic_def, access_level))
+ MonoClass *access_container;
+
+ if (access_klass->generic_container)
+ access_container = access_klass;
+ else
+ access_container = access_klass->generic_class->container_class;
+
+ if (can_access_member (access_container, member_generic_def, access_level))
return TRUE;
}
return TRUE;
}
+
+gboolean
+mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
+{
+ return gklass->context.class_inst == gklass->container_class->generic_container->context.class_inst;
+}
+
+/*
+ * mono_class_generic_sharing_enabled:
+ * @class: a class
+ *
+ * Returns whether generic sharing is enabled for class.
+ *
+ * This is a stop-gap measure to slowly introduce generic sharing
+ * until we have all the issues sorted out, at which time this
+ * function will disappear and generic sharing will always be enabled.
+ */
+gboolean
+mono_class_generic_sharing_enabled (MonoClass *class)
+{
+ static int generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+ static gboolean inited = FALSE;
+
+ if (!inited) {
+ const char *option;
+
+ if ((option = g_getenv ("MONO_GENERIC_SHARING"))) {
+ if (strcmp (option, "corlib") == 0)
+ generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+ else if (strcmp (option, "all") == 0)
+ generic_sharing = MONO_GENERIC_SHARING_ALL;
+ else if (strcmp (option, "none") == 0)
+ generic_sharing = MONO_GENERIC_SHARING_NONE;
+ else
+ g_warning ("Unknown generic sharing option `%s'.", option);
+ }
+
+ inited = TRUE;
+ }
+
+ switch (generic_sharing) {
+ case MONO_GENERIC_SHARING_NONE:
+ return FALSE;
+ case MONO_GENERIC_SHARING_ALL:
+ return TRUE;
+ case MONO_GENERIC_SHARING_CORLIB :
+ return class->image == mono_defaults.corlib;
+ default:
+ g_assert_not_reached ();
+ }
+}