Skip to content

Commit e7e00d0

Browse files
committed
When searching for a variant interface, use a special 'variant search table' that contains only variant interfaces in the correct search order
1 parent 7d04e76 commit e7e00d0

File tree

2 files changed

+70
-17
lines changed

2 files changed

+70
-17
lines changed

src/mono/mono/metadata/class-private-definition.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct _MonoClass {
8080
guint has_deferred_failure : 1;
8181
/* next byte*/
8282
guint is_exception_class : 1; /* is System.Exception or derived from it */
83+
guint variant_search_table_inited : 1;
8384

8485
MonoClass *parent;
8586
MonoClass *nested_in;
@@ -127,6 +128,9 @@ struct _MonoClass {
127128

128129
/* Infrequently used items. See class-accessors.c: InfrequentDataKind for what goes into here. */
129130
MonoPropertyBag infrequent_data;
131+
132+
void *variant_search_table;
133+
guint variant_search_table_length;
130134
};
131135

132136
struct _MonoClassDef {

src/mono/mono/metadata/class.c

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,60 @@ mono_class_interface_offset (MonoClass *klass, MonoClass *itf)
19331933
return -1;
19341934
}
19351935

1936+
typedef struct VarianceSearchEntry {
1937+
MonoClass *klass;
1938+
int interface_offset;
1939+
} VarianceSearchEntry;
1940+
1941+
static void
1942+
build_variance_search_table (MonoClass *klass) {
1943+
guint buf_size = m_class_get_interface_offsets_count (klass), buf_count = 0;
1944+
VarianceSearchEntry *buf = g_alloca (buf_size * sizeof(VarianceSearchEntry));
1945+
memset (buf, 0, buf_size * sizeof(VarianceSearchEntry));
1946+
1947+
MonoClass *current = klass;
1948+
while (current) {
1949+
// g_print ("%s.%s:\n", m_class_get_name_space (current), m_class_get_name (current));
1950+
MonoClass **ifaces = m_class_get_interfaces (current);
1951+
for (guint i = 0, c = m_class_get_interface_count (current); i < c; i++) {
1952+
MonoClass *iface = ifaces [i];
1953+
if (!mono_class_has_variant_generic_params (iface))
1954+
continue;
1955+
1956+
// FIXME: Avoid adding duplicates.
1957+
// g_print ("-> %s.%s\n", m_class_get_name_space (iface), m_class_get_name (iface));
1958+
g_assert (buf_count < buf_size);
1959+
buf[buf_count].klass = iface;
1960+
buf[buf_count].interface_offset = mono_class_interface_offset (klass, iface);
1961+
buf_count++;
1962+
}
1963+
1964+
current = current->parent;
1965+
}
1966+
1967+
if (buf_count) {
1968+
guint bytes = buf_count * sizeof(VarianceSearchEntry);
1969+
klass->variant_search_table = g_malloc (bytes);
1970+
memcpy (klass->variant_search_table, buf, bytes);
1971+
} else
1972+
klass->variant_search_table = NULL;
1973+
klass->variant_search_table_length = buf_count;
1974+
klass->variant_search_table_inited = TRUE;
1975+
}
1976+
1977+
static void
1978+
get_variance_search_table (MonoClass *klass, VarianceSearchEntry **table, guint *table_size) {
1979+
g_assert (klass);
1980+
g_assert (table);
1981+
g_assert (table_size);
1982+
1983+
if (!klass->variant_search_table_inited)
1984+
build_variance_search_table (klass);
1985+
1986+
*table = (VarianceSearchEntry *)klass->variant_search_table;
1987+
*table_size = klass->variant_search_table_length;
1988+
}
1989+
19361990
/**
19371991
* mono_class_interface_offset_with_variance:
19381992
*
@@ -1959,11 +2013,11 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo
19592013

19602014
int klass_interface_offsets_count = m_class_get_interface_offsets_count (klass);
19612015

1962-
if (m_class_is_array_special_interface (itf) && m_class_get_rank (klass) < 2) {
2016+
if (m_class_is_array_special_interface (itf) && m_class_get_rank (klass) < 2) {
19632017
MonoClass *gtd = mono_class_get_generic_type_definition (itf);
19642018
int found = -1;
19652019

1966-
for (i = klass_interface_offsets_count - 1; i >= 0; i--) {
2020+
for (i = 0; i < klass_interface_offsets_count; i++) {
19672021
if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
19682022
/*
19692023
g_print (
@@ -1981,7 +2035,7 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo
19812035
if (found != -1)
19822036
return m_class_get_interface_offsets_packed (klass) [found];
19832037

1984-
for (i = klass_interface_offsets_count - 1; i >= 0; i--) {
2038+
for (i = 0; i < klass_interface_offsets_count; i++) {
19852039
if (mono_class_get_generic_type_definition (m_class_get_interfaces_packed (klass) [i]) == gtd) {
19862040
/*
19872041
g_print (
@@ -2000,22 +2054,17 @@ mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gbo
20002054
return -1;
20012055

20022056
return m_class_get_interface_offsets_packed (klass) [found];
2003-
}
2057+
} else if (has_variance) {
2058+
VarianceSearchEntry *vst;
2059+
guint vst_count;
2060+
get_variance_search_table (klass, &vst, &vst_count);
20042061

2005-
if (!has_variance)
2006-
return -1;
2062+
for (guint i = 0; i < vst_count; i++) {
2063+
if (!mono_class_is_variant_compatible (itf, vst [i].klass, FALSE))
2064+
continue;
20072065

2008-
for (i = klass_interface_offsets_count - 1; i >= 0; i--) {
2009-
if (mono_class_is_variant_compatible (itf, m_class_get_interfaces_packed (klass) [i], FALSE)) {
2010-
/*
2011-
g_print (
2012-
"is_variant_compatible (%s, %s, FALSE) == true\n",
2013-
iname,
2014-
mono_type_get_name_full (m_class_get_byval_arg (m_class_get_interfaces_packed (klass) [i]), MONO_TYPE_NAME_FORMAT_FULL_NAME)
2015-
);
2016-
*/
2017-
*non_exact_match = (i != exact_match);
2018-
return m_class_get_interface_offsets_packed (klass) [i];
2066+
*non_exact_match = (vst [i].interface_offset != exact_match);
2067+
return vst [i].interface_offset;
20192068
}
20202069
}
20212070

0 commit comments

Comments
 (0)