@@ -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