@@ -2498,7 +2498,8 @@ mono_class_need_stelemref_method (MonoClass *klass)
24982498}
24992499
25002500static int
2501- apply_override (MonoClass * klass , MonoMethod * * vtable , MonoMethod * decl , MonoMethod * override )
2501+ apply_override (MonoClass * klass , MonoClass * override_class , MonoMethod * * vtable , MonoMethod * decl , MonoMethod * override ,
2502+ GHashTable * * override_map , GHashTable * * override_class_map , GHashTable * * conflict_map )
25022503{
25032504 int dslot ;
25042505 dslot = mono_method_get_vtable_slot (decl );
@@ -2517,12 +2518,138 @@ apply_override (MonoClass *klass, MonoMethod **vtable, MonoMethod *decl, MonoMet
25172518 vtable [dslot ]-> slot = dslot ;
25182519 }
25192520
2520- if (mono_security_core_clr_enabled ())
2521- mono_security_core_clr_check_override (klass , vtable [dslot ], decl );
2521+ if (!* override_map ) {
2522+ * override_map = g_hash_table_new (mono_aligned_addr_hash , NULL );
2523+ * override_class_map = g_hash_table_new (mono_aligned_addr_hash , NULL );
2524+ }
2525+ GHashTable * map = * override_map ;
2526+ GHashTable * class_map = * override_class_map ;
2527+
2528+ MonoMethod * prev_override = g_hash_table_lookup (map , decl );
2529+ MonoClass * prev_override_class = g_hash_table_lookup (class_map , decl );
2530+
2531+ g_hash_table_insert (map , decl , override );
2532+ g_hash_table_insert (class_map , decl , override_class );
2533+
2534+ /* Collect potentially conflicting overrides which are introduced by default interface methods */
2535+ if (prev_override ) {
2536+ ERROR_DECL (error );
2537+
2538+ /*
2539+ * The override methods are part of the generic definition, need to inflate them so their
2540+ * parent class becomes the actual interface/class containing the override, i.e.
2541+ * IFace<T> in:
2542+ * class Foo<T> : IFace<T>
2543+ * This is needed so the mono_class_is_assignable_from () calls in the
2544+ * conflict resolution work.
2545+ */
2546+ if (mono_class_is_ginst (override_class )) {
2547+ override = mono_class_inflate_generic_method_checked (override , & mono_class_get_generic_class (override_class )-> context , error );
2548+ mono_error_assert_ok (error );
2549+ }
2550+
2551+ if (mono_class_is_ginst (prev_override_class )) {
2552+ prev_override = mono_class_inflate_generic_method_checked (prev_override , & mono_class_get_generic_class (prev_override_class )-> context , error );
2553+ mono_error_assert_ok (error );
2554+ }
2555+
2556+ if (!* conflict_map )
2557+ * conflict_map = g_hash_table_new (mono_aligned_addr_hash , NULL );
2558+ GHashTable * cmap = * conflict_map ;
2559+ GSList * entries = g_hash_table_lookup (cmap , decl );
2560+ if (!(decl -> flags & METHOD_ATTRIBUTE_ABSTRACT ))
2561+ entries = g_slist_prepend (entries , decl );
2562+ entries = g_slist_prepend (entries , prev_override );
2563+ entries = g_slist_prepend (entries , override );
2564+
2565+ g_hash_table_insert (cmap , decl , entries );
2566+ }
25222567
25232568 return TRUE;
25242569}
25252570
2571+ static void
2572+ handle_dim_conflicts (MonoMethod * * vtable , MonoClass * klass , GHashTable * conflict_map )
2573+ {
2574+ GHashTableIter iter ;
2575+ MonoMethod * decl ;
2576+ GSList * entries , * l , * l2 ;
2577+ GSList * dim_conflicts = NULL ;
2578+
2579+ g_hash_table_iter_init (& iter , conflict_map );
2580+ while (g_hash_table_iter_next (& iter , (gpointer * )& decl , (gpointer * )& entries )) {
2581+ /*
2582+ * Iterate over the candidate methods, remove ones whose class is less concrete than the
2583+ * class of another one.
2584+ */
2585+ /* This is O(n^2), but that shouldn't be a problem in practice */
2586+ for (l = entries ; l ; l = l -> next ) {
2587+ for (l2 = entries ; l2 ; l2 = l2 -> next ) {
2588+ MonoMethod * m1 = l -> data ;
2589+ MonoMethod * m2 = l2 -> data ;
2590+ if (!m1 || !m2 || m1 == m2 )
2591+ continue ;
2592+ if (mono_class_is_assignable_from (m1 -> klass , m2 -> klass ))
2593+ l -> data = NULL ;
2594+ else if (mono_class_is_assignable_from (m2 -> klass , m1 -> klass ))
2595+ l2 -> data = NULL ;
2596+ }
2597+ }
2598+ int nentries = 0 ;
2599+ MonoMethod * impl = NULL ;
2600+ for (l = entries ; l ; l = l -> next ) {
2601+ if (l -> data ) {
2602+ nentries ++ ;
2603+ impl = l -> data ;
2604+ }
2605+ }
2606+ if (nentries > 1 ) {
2607+ /* If more than one method is left, we have a conflict */
2608+ if (decl -> is_inflated )
2609+ decl = ((MonoMethodInflated * )decl )-> declaring ;
2610+ dim_conflicts = g_slist_prepend (dim_conflicts , decl );
2611+ /*
2612+ for (l = entries; l; l = l->next) {
2613+ if (l->data)
2614+ printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2615+ }
2616+ */
2617+ } else {
2618+ /*
2619+ * Use the implementing method computed above instead of the already
2620+ * computed one, which depends on interface ordering.
2621+ */
2622+ int ic_offset = mono_class_interface_offset (klass , decl -> klass );
2623+ int im_slot = ic_offset + decl -> slot ;
2624+ vtable [im_slot ] = impl ;
2625+ }
2626+ g_slist_free (entries );
2627+ }
2628+ if (dim_conflicts ) {
2629+ mono_loader_lock ();
2630+ klass -> has_dim_conflicts = 1 ;
2631+ mono_loader_unlock ();
2632+
2633+ /*
2634+ * Exceptions are thrown at method call time and only for the methods which have
2635+ * conflicts, so just save them in the class.
2636+ */
2637+
2638+ /* Make a copy of the list from the class mempool */
2639+ GSList * conflicts = mono_class_alloc0 (klass , g_slist_length (dim_conflicts ) * sizeof (GSList ));
2640+ int i = 0 ;
2641+ for (l = dim_conflicts ; l ; l = l -> next ) {
2642+ conflicts [i ].data = l -> data ;
2643+ conflicts [i ].next = & conflicts [i + 1 ];
2644+ i ++ ;
2645+ }
2646+ conflicts [i - 1 ].next = NULL ;
2647+
2648+ mono_class_set_dim_conflicts (klass , conflicts );
2649+ g_slist_free (dim_conflicts );
2650+ }
2651+ }
2652+
25262653static void
25272654print_unimplemented_interface_method_info (MonoClass * klass , MonoClass * ic , MonoMethod * im , int im_slot , MonoMethod * * overrides , int onum )
25282655{
@@ -2664,6 +2791,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
26642791 guint32 max_iid ;
26652792 GPtrArray * ifaces = NULL ;
26662793 GHashTable * override_map = NULL ;
2794+ GHashTable * override_class_map = NULL ;
2795+ GHashTable * conflict_map = NULL ;
26672796 MonoMethod * cm ;
26682797#if (DEBUG_INTERFACE_VTABLE_CODE |TRACE_INTERFACE_VTABLE_CODE )
26692798 int first_non_interface_slot ;
@@ -2746,6 +2875,10 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
27462875 mono_memory_barrier ();
27472876 klass -> vtable = tmp ;
27482877
2878+ mono_loader_lock ();
2879+ klass -> has_dim_conflicts = gklass -> has_dim_conflicts ;
2880+ mono_loader_unlock ();
2881+
27492882 /* Have to set method->slot for abstract virtual methods */
27502883 if (klass -> methods && gklass -> methods ) {
27512884 int mcount = mono_class_get_method_count (klass );
@@ -2823,12 +2956,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
28232956 for (int i = 0 ; i < iface_onum ; i ++ ) {
28242957 MonoMethod * decl = iface_overrides [i * 2 ];
28252958 MonoMethod * override = iface_overrides [i * 2 + 1 ];
2826- if (!apply_override (klass , vtable , decl , override ))
2959+ if (!apply_override (klass , ic , vtable , decl , override , & override_map , & override_class_map , & conflict_map ))
28272960 goto fail ;
2828-
2829- if (!override_map )
2830- override_map = g_hash_table_new (mono_aligned_addr_hash , NULL );
2831- g_hash_table_insert (override_map , decl , override );
28322961 }
28332962 g_free (iface_overrides );
28342963 }
@@ -2838,12 +2967,8 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
28382967 MonoMethod * decl = overrides [i * 2 ];
28392968 MonoMethod * override = overrides [i * 2 + 1 ];
28402969 if (MONO_CLASS_IS_INTERFACE (decl -> klass )) {
2841- if (!apply_override (klass , vtable , decl , override ))
2970+ if (!apply_override (klass , klass , vtable , decl , override , & override_map , & override_class_map , & conflict_map ))
28422971 goto fail ;
2843-
2844- if (!override_map )
2845- override_map = g_hash_table_new (mono_aligned_addr_hash , NULL );
2846- g_hash_table_insert (override_map , decl , override );
28472972 }
28482973 }
28492974
@@ -3108,6 +3233,14 @@ mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int o
31083233 override_map = NULL ;
31093234 }
31103235
3236+ if (override_class_map )
3237+ g_hash_table_destroy (override_class_map );
3238+
3239+ if (conflict_map ) {
3240+ handle_dim_conflicts (vtable , klass , conflict_map );
3241+ g_hash_table_destroy (conflict_map );
3242+ }
3243+
31113244 g_slist_free (virt_methods );
31123245 virt_methods = NULL ;
31133246
0 commit comments