guint has_finalize_inited : 1; /* has_finalize is initialized */
guint fields_inited : 1; /* setup_fields () has finished */
guint has_failure : 1; /* See mono_class_get_exception_data () for a MonoErrorBoxed with the details */
+ guint is_array_special_interface : 1;
MonoClass *parent;
MonoClass *nested_in;
MonoClass *argumenthandle_class;
MonoClass *monitor_class;
MonoClass *generic_ilist_class;
+ MonoClass *generic_icollection_class;
+ MonoClass *generic_ienumerable_class;
MonoClass *generic_nullable_class;
MonoClass *handleref_class;
MonoClass *attribute_class;
#include <mono/utils/bsearch.h>
#include <mono/utils/checked-build.h>
+#define ENABLE_LAZY_ARRAY_IFACES TRUE
+
MonoStats mono_stats;
gboolean mono_print_vtable = FALSE;
if (i >= 0)
return i;
+ if (itf->is_array_special_interface && klass->rank < 2) {
+ MonoClass *gtd = mono_class_get_generic_type_definition (itf);
+
+ for (i = 0; i < klass->interface_offsets_count; i++) {
+ // printf ("\t%s\n", mono_type_get_full_name (klass->interfaces_packed [i]));
+ if (mono_class_get_generic_type_definition (klass->interfaces_packed [i]) == gtd) {
+ *non_exact_match = TRUE;
+ return klass->interface_offsets_packed [i];
+ }
+ }
+ }
+
if (!mono_class_has_variant_generic_params (itf))
return -1;
gboolean internal_enumerator;
gboolean eclass_is_valuetype;
- if (!mono_defaults.generic_ilist_class) {
+ if (!mono_defaults.generic_ilist_class || ENABLE_LAZY_ARRAY_IFACES) {
*num = 0;
return NULL;
}
klass->enumtype = gklass->enumtype;
klass->valuetype = gklass->valuetype;
+
if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
g_assert (gclass->context.class_inst);
g_assert (gclass->context.class_inst->type_argc > 0);
if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
klass->simd_type = 1;
}
+ klass->is_array_special_interface = gklass->is_array_special_interface;
klass->cast_class = klass->element_class = klass;
if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
return TRUE;
+ if (klass->is_array_special_interface && oklass->rank == 1) {
+ //XXX we could offset this by having the cast target computed at JIT time
+ //XXX we could go even further and emit a wrapper that would do the extra type check
+ MonoClass *iface_klass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
+ MonoClass *obj_klass = oklass->cast_class; //This gets us the cast class of element type of the array
+
+ // If the target we're trying to cast to is a valuetype, we must account of weird valuetype equivalences such as IntEnum <> int or uint <> int
+ // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
+ if (iface_klass->valuetype)
+ iface_klass = iface_klass->cast_class;
+
+ //array covariant casts only operates on scalar to scalar
+ //This is so int[] can't be casted to IComparable<int>[]
+ if (!(obj_klass->valuetype && !iface_klass->valuetype) && mono_class_is_assignable_from (iface_klass, obj_klass))
+ return TRUE;
+ }
+
if (mono_class_has_variant_generic_params (klass)) {
int i;
mono_class_setup_interfaces (oklass, &error);
mono_defaults.uint64_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "UInt64");
+ //XXX find a better place, which kinda doesn't exists as those types depend on each other.
+ mono_defaults.uint32_class->cast_class = mono_defaults.int32_class;
+ mono_defaults.uint16_class->cast_class = mono_defaults.int16_class;
+ mono_defaults.sbyte_class->cast_class = mono_defaults.byte_class;
+ mono_defaults.uint64_class->cast_class = mono_defaults.int64_class;
+
+
mono_defaults.single_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Single");
mono_class_init (mono_defaults.array_class);
mono_defaults.generic_nullable_class = mono_class_load_from_name (
mono_defaults.corlib, "System", "Nullable`1");
- mono_defaults.generic_ilist_class = mono_class_load_from_name (
- mono_defaults.corlib, "System.Collections.Generic", "IList`1");
mono_defaults.generic_ireadonlylist_class = mono_class_load_from_name (
mono_defaults.corlib, "System.Collections.Generic", "IReadOnlyList`1");
+ //IList, ICollection, IEnumerable
+ mono_defaults.generic_ilist_class = mono_class_load_from_name (
+ mono_defaults.corlib, "System.Collections.Generic", "IList`1");
+ mono_defaults.generic_icollection_class = mono_class_load_from_name (
+ mono_defaults.corlib, "System.Collections.Generic", "ICollection`1");
+ mono_defaults.generic_ienumerable_class = mono_class_load_from_name (
+ mono_defaults.corlib, "System.Collections.Generic", "IEnumerable`1");
+
+ //XXX This is a hack, there's probably a better place to do this. Probably in mono_class_create_from_typedef
+ mono_defaults.generic_ilist_class->is_array_special_interface = 1;
+ mono_defaults.generic_icollection_class->is_array_special_interface = 1;
+ mono_defaults.generic_ienumerable_class->is_array_special_interface = 1;
+
+ //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
+ MonoClass *tmp = mono_class_load_from_name (
+ mono_defaults.corlib, "System.Collections.Generic", "IEnumerator`1");
+ tmp->is_array_special_interface = 1;
+
+
mono_defaults.threadpool_wait_callback_class = mono_class_load_from_name (
mono_defaults.corlib, "System.Threading", "_ThreadPoolWaitCallback");
#define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
static mono_mutex_t ldstr_section;
+
/**
* mono_runtime_object_init:
* @this_obj: the object to initialize
MONO_REQ_GC_UNSAFE_MODE;
MonoVTable *vt;
+ static gboolean inited = FALSE;
+ static int special_array_iface_tests, special_array_iface_tests_fails;
+ if (!inited) {
+ inited = TRUE;
+ mono_counters_register ("Special array interfaces type tests",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &special_array_iface_tests);
+ mono_counters_register ("Special array interface type tests fails",
+ MONO_COUNTER_METADATA | MONO_COUNTER_INT, &special_array_iface_tests_fails);
+ }
mono_error_init (error);
return obj;
}
+ /* casting an array one of the invariant interfaces that must act as such */
+ if (klass->is_array_special_interface) {
+ ++special_array_iface_tests;
+ if (mono_class_is_assignable_from (klass, vt->klass))
+ return obj;
+ else
+ ++special_array_iface_tests_fails;
+ }
+
/*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
- if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
+ else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
return obj;
} else {
MonoClass *oklass = vt->klass;
NEW_BBLOCK (cfg, first_bb);
cfg->cbb = first_bb;
- if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
+ if (!context_used && (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface)) {
if (is_isinst)
ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
else