#include <mono/metadata/assembly.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/security-manager.h>
#include <mono/metadata/security-core-clr.h>
#include <mono/metadata/attrdefs.h>
-#include <mono/os/gc_wrapper.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:
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:
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
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)
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;
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);
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.
+ * 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;
return;
}
- if (class->generic_class && !class->generic_class->is_dynamic) {
+ 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);
for (i = 0; i < class->method.count; i++) {
/* 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;
}
- if (class->generic_class && !class->generic_class->is_dynamic) {
+ if (class->generic_class) {
MonoClass *gklass = class->generic_class->container_class;
class->property = gklass->property;
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;
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);
+ }
- if (ifaces)
- g_ptr_array_free (ifaces, TRUE);
- if (override_map)
- g_hash_table_destroy (override_map);
+ mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
- return;
+ if (ifaces)
+ g_ptr_array_free (ifaces, TRUE);
+ if (override_map)
+ g_hash_table_destroy (override_map);
+
+ 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;
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];
if (!strncmp (m->name, "InternalArray__", 15)) {
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) {
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
*/
{
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;
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.
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")) {
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")) {
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) {
/*
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; */
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;
}
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++) {
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;
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++)
;
klass->interfaces [i - pos] = param->constraints [i];
}
- 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 = "";
-
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) {
- static MonoClass* generic_icollection_class = NULL;
- static MonoClass* generic_ienumerable_class = NULL;
- MonoClass *fclass = NULL;
- int i;
-
- 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");
- }
-
- /*
- * 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 class->interfaces at intervals of 3, because 3 are
- * the generic interfaces needed to implement. We then walk class->interfaces
- * in a single loop to build the proper interface classes.
- */
- 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;
-
-/* set to 3 to enable the additional interfaces */
-#define ARRAY_IFACES_NUM 1
- /* IList, ICollection, IEnumerable */
- class->interface_count = fclass ? 2 : 1;
- class->interface_count *= ARRAY_IFACES_NUM;
- class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
- class->interfaces [0] = eclass;
- if (fclass)
- class->interfaces [ARRAY_IFACES_NUM] = fclass;
- } else if (MONO_CLASS_IS_INTERFACE (eclass)) {
- int j;
- class->interface_count = 2 + eclass->interface_count;
- /* IList, ICollection, IEnumerable */
- class->interface_count *= ARRAY_IFACES_NUM;
- class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
- class->interfaces [0] = mono_defaults.object_class;
- class->interfaces [ARRAY_IFACES_NUM] = eclass;
- j = ARRAY_IFACES_NUM * 2;
- for (i = 0; i < eclass->interface_count; i++) {
- class->interfaces [j] = eclass->interfaces [i];
- j += ARRAY_IFACES_NUM;
- }
- } else {
- int j;
- class->interface_count = eclass->idepth + eclass->interface_count;
- /* IList, ICollection, IEnumerable */
- class->interface_count *= ARRAY_IFACES_NUM;
- class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
- j = 0;
- for (i = 0; i < eclass->idepth; i++) {
- class->interfaces [j] = eclass->supertypes [i];
- j += ARRAY_IFACES_NUM;
- }
- for (i = 0; i < eclass->interface_count; i++) {
- class->interfaces [j] = eclass->interfaces [i];
- j += ARRAY_IFACES_NUM;
- }
- }
+ if (mono_defaults.generic_ilist_class && !bounded && rank == 1) {
+ MonoType *args [1];
- for (i = 0; i < class->interface_count; i += ARRAY_IFACES_NUM) {
- MonoType *args [1];
- MonoClass *iface = class->interfaces [i];
+ /* generic IList, ICollection, IEnumerable */
+ class->interface_count = 1;
+ class->interfaces = mono_mempool_alloc0 (image->mempool, sizeof (MonoClass*) * class->interface_count);
- args [0] = &iface->byval_arg;
- class->interfaces [i] = mono_class_bind_generic_parameters (
- mono_defaults.generic_ilist_class, 1, args, FALSE);
-#if ARRAY_IFACES_NUM == 3
- args [0] = &iface->byval_arg;
- class->interfaces [i + 1] = mono_class_bind_generic_parameters (
- generic_icollection_class, 1, args, FALSE);
- args [0] = &iface->byval_arg;
- class->interfaces [i + 2] = mono_class_bind_generic_parameters (
- generic_ienumerable_class, 1, args, FALSE);
-#endif
- }
+ 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)
+ 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:
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;
}
+/**
+ * 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)
{
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, context);
+ 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)
{
MonoClass *handle_class;
- return lookup_dynamic (image, token, &handle_class, context);
+ return lookup_dynamic (image, token, TRUE, &handle_class, context);
}
gpointer
-mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, MonoClass **handle_class, MonoGenericContext *context)
+mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
{
- return lookup_dynamic (image, token, handle_class, context);
+ 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
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;
- }
}
/**
return ex;
}
+ case MONO_EXCEPTION_BAD_IMAGE: {
+ return mono_get_exception_bad_image_format (klass->exception_data);
+ }
default: {
MonoLoaderError *error;
MonoException *ex;
}
}
+static gboolean
+is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
+ {
+ do {
+ if (outer_klass == inner_klass)
+ return TRUE;
+ inner_klass = inner_klass->nested_in;
+ } while (inner_klass);
+ 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 (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 (context_klass, access_klass))
+ return FALSE;
+ return TRUE;
+}
+
static gboolean
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;
return NULL;
}
+static gboolean
+can_access_type (MonoClass *access_klass, MonoClass *member_klass)
+{
+ int access_level = member_klass->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
+
+ 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 (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 (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 (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 &&
+ 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, context_klass, access_level))
return TRUE;
}
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:
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;
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;
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)
+ return TRUE;
+ 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_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)
+ return TRUE;
+ 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
{
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)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ static int generic_sharing = MONO_GENERIC_SHARING_CORLIB;
+#else
+ static int generic_sharing = MONO_GENERIC_SHARING_NONE;
+#endif
+ 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 ();
+ }
+}