2 * \file MonoClass vtable setup
4 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
5 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
6 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
7 * Copyright 2018 Microsoft
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11 #include <mono/metadata/class-init.h>
12 #include <mono/metadata/class-init-internals.h>
13 #include <mono/metadata/class-internals.h>
14 #include <mono/metadata/debug-helpers.h>
15 #include <mono/metadata/security-core-clr.h>
16 #include <mono/metadata/security-manager.h>
17 #include <mono/utils/mono-logger-internals.h>
18 #include <mono/utils/unlocked.h>
19 #ifdef MONO_CLASS_DEF_PRIVATE
20 /* Class initialization gets to see the fields of MonoClass */
21 #define REALLY_INCLUDE_CLASS_DEF 1
22 #include <mono/metadata/class-private-definition.h>
23 #undef REALLY_INCLUDE_CLASS_DEF
27 #define FEATURE_COVARIANT_RETURNS
30 static void mono_class_setup_vtable_full (MonoClass
*klass
, GList
*in_setup
);
33 print_implemented_interfaces (MonoClass
*klass
)
37 GPtrArray
*ifaces
= NULL
;
39 int ancestor_level
= 0;
41 name
= mono_type_get_full_name (klass
);
42 printf ("Packed interface table for class %s has size %d\n", name
, klass
->interface_offsets_count
);
45 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
46 char *ic_name
= mono_type_get_full_name (klass
->interfaces_packed
[i
]);
47 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i
,
48 klass
->interfaces_packed
[i
]->interface_id
,
49 klass
->interface_offsets_packed
[i
],
50 mono_class_get_method_count (klass
->interfaces_packed
[i
]),
54 printf ("Interface flags: ");
55 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
56 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
61 printf ("Dump interface flags:");
62 #ifdef COMPRESSED_INTERFACE_BITMAP
64 const uint8_t* p
= klass
->interface_bitmap
;
65 i
= klass
->max_interface_id
;
67 printf (" %d x 00 %02X", p
[0], p
[1]);
73 for (i
= 0; i
< ((((klass
->max_interface_id
+ 1) >> 3)) + (((klass
->max_interface_id
+ 1) & 7)? 1 :0)); i
++)
74 printf (" %02X", klass
->interface_bitmap
[i
]);
77 while (klass
!= NULL
) {
78 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level
, klass
->name
);
79 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
81 printf (" Type failed due to %s\n", mono_error_get_message (error
));
82 mono_error_cleanup (error
);
84 for (i
= 0; i
< ifaces
->len
; i
++) {
85 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
86 printf (" [UIID %d] interface %s\n", ic
->interface_id
, ic
->name
);
87 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i
,
89 mono_class_interface_offset (klass
, ic
),
90 mono_class_get_method_count (ic
),
94 g_ptr_array_free (ifaces
, TRUE
);
97 klass
= klass
->parent
;
102 set_interface_and_offset (int num_ifaces
, MonoClass
**interfaces_full
, int *interface_offsets_full
, MonoClass
*ic
, int offset
, mono_bool force_set
)
105 for (i
= 0; i
< num_ifaces
; ++i
) {
106 if (interfaces_full
[i
] && interfaces_full
[i
]->interface_id
== ic
->interface_id
) {
109 interface_offsets_full
[i
] = offset
;
112 if (interfaces_full
[i
])
114 interfaces_full
[i
] = ic
;
115 interface_offsets_full
[i
] = offset
;
122 * mono_class_setup_interface_offsets_internal:
124 * Do not call this function outside of class creation.
126 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
127 * LOCKING: Acquires the loader lock.
130 mono_class_setup_interface_offsets_internal (MonoClass
*klass
, int cur_slot
, gboolean overwrite
)
134 int i
, j
, num_ifaces
;
136 MonoClass
**interfaces_full
= NULL
;
137 int *interface_offsets_full
= NULL
;
139 GPtrArray
**ifaces_array
= NULL
;
140 int interface_offsets_count
;
142 num_ifaces
= interface_offsets_count
= 0;
146 mono_class_setup_supertypes (klass
);
148 if (mono_class_is_ginst (klass
)) {
149 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
151 interface_offsets_count
= num_ifaces
= gklass
->interface_offsets_count
;
152 interfaces_full
= (MonoClass
**)g_malloc (sizeof (MonoClass
*) * num_ifaces
);
153 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
156 for (int i
= 0; i
< num_ifaces
; ++i
) {
157 MonoClass
*gklass_ic
= gklass
->interfaces_packed
[i
];
158 MonoClass
*inflated
= mono_class_inflate_generic_class_checked (gklass_ic
, mono_class_get_context(klass
), error
);
159 if (!is_ok (error
)) {
160 char *name
= mono_type_get_full_name (gklass_ic
);
161 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
167 mono_class_setup_interface_id_nolock (inflated
);
169 interfaces_full
[i
] = inflated
;
170 interface_offsets_full
[i
] = gklass
->interface_offsets_packed
[i
];
172 int count
= mono_class_setup_count_virtual_methods (inflated
);
174 char *name
= mono_type_get_full_name (inflated
);
175 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
181 cur_slot
= MAX (cur_slot
, interface_offsets_full
[i
] + count
);
182 max_iid
= MAX (max_iid
, inflated
->interface_id
);
187 /* compute maximum number of slots and maximum interface id */
189 num_ifaces
= 0; /* this can include duplicated ones */
190 ifaces_array
= g_new0 (GPtrArray
*, klass
->idepth
);
191 for (j
= 0; j
< klass
->idepth
; j
++) {
192 k
= klass
->supertypes
[j
];
194 num_ifaces
+= k
->interface_count
;
195 for (i
= 0; i
< k
->interface_count
; i
++) {
196 ic
= k
->interfaces
[i
];
198 /* A gparam does not have any interface_id set. */
199 if (! mono_class_is_gparam (ic
))
200 mono_class_setup_interface_id_nolock (ic
);
202 if (max_iid
< ic
->interface_id
)
203 max_iid
= ic
->interface_id
;
205 ifaces
= mono_class_get_implemented_interfaces (k
, error
);
206 if (!is_ok (error
)) {
207 char *name
= mono_type_get_full_name (k
);
208 mono_class_set_type_load_failure (klass
, "Error getting the interfaces of %s due to %s", name
, mono_error_get_message (error
));
210 mono_error_cleanup (error
);
215 num_ifaces
+= ifaces
->len
;
216 for (i
= 0; i
< ifaces
->len
; ++i
) {
217 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
218 if (max_iid
< ic
->interface_id
)
219 max_iid
= ic
->interface_id
;
221 ifaces_array
[j
] = ifaces
;
225 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
227 if (max_iid
< klass
->interface_id
)
228 max_iid
= klass
->interface_id
;
231 /* compute vtable offset for interfaces */
232 interfaces_full
= (MonoClass
**)g_malloc0 (sizeof (MonoClass
*) * num_ifaces
);
233 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
235 for (i
= 0; i
< num_ifaces
; i
++)
236 interface_offsets_full
[i
] = -1;
238 /* skip the current class */
239 for (j
= 0; j
< klass
->idepth
- 1; j
++) {
240 k
= klass
->supertypes
[j
];
241 ifaces
= ifaces_array
[j
];
244 for (i
= 0; i
< ifaces
->len
; ++i
) {
246 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
248 /*Force the sharing of interface offsets between parent and subtypes.*/
249 io
= mono_class_interface_offset (k
, ic
);
250 g_assertf (io
>= 0, "class %s parent %s has no offset for iface %s",
251 mono_type_get_full_name (klass
),
252 mono_type_get_full_name (k
),
253 mono_type_get_full_name (ic
));
255 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, io
, TRUE
);
260 g_assert (klass
== klass
->supertypes
[klass
->idepth
- 1]);
261 ifaces
= ifaces_array
[klass
->idepth
- 1];
263 for (i
= 0; i
< ifaces
->len
; ++i
) {
265 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
266 if (set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, cur_slot
, FALSE
))
268 count
= mono_class_setup_count_virtual_methods (ic
);
270 char *name
= mono_type_get_full_name (ic
);
271 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
280 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
))
281 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, klass
, cur_slot
, TRUE
);
283 for (interface_offsets_count
= 0, i
= 0; i
< num_ifaces
; i
++) {
284 if (interface_offsets_full
[i
] != -1)
285 interface_offsets_count
++;
289 /* Publish the data */
290 klass
->max_interface_id
= max_iid
;
292 * We might get called multiple times:
293 * - mono_class_init_internal ()
294 * - mono_class_setup_vtable ().
295 * - mono_class_setup_interface_offsets ().
296 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
297 * means we have to overwrite those when called from other places (#4440).
299 if (klass
->interfaces_packed
) {
301 g_assert (klass
->interface_offsets_count
== interface_offsets_count
);
305 klass
->interface_offsets_count
= interface_offsets_count
;
306 klass
->interfaces_packed
= (MonoClass
**)mono_class_alloc (klass
, sizeof (MonoClass
*) * interface_offsets_count
);
307 klass
->interface_offsets_packed
= (guint16
*)mono_class_alloc (klass
, sizeof (guint16
) * interface_offsets_count
);
308 bsize
= (sizeof (guint8
) * ((max_iid
+ 1) >> 3)) + (((max_iid
+ 1) & 7)? 1 :0);
309 #ifdef COMPRESSED_INTERFACE_BITMAP
310 bitmap
= g_malloc0 (bsize
);
312 bitmap
= (uint8_t *)mono_class_alloc0 (klass
, bsize
);
314 for (i
= 0; i
< interface_offsets_count
; i
++) {
315 guint32 id
= interfaces_full
[i
]->interface_id
;
316 bitmap
[id
>> 3] |= (1 << (id
& 7));
317 klass
->interfaces_packed
[i
] = interfaces_full
[i
];
318 klass
->interface_offsets_packed
[i
] = interface_offsets_full
[i
];
320 #ifdef COMPRESSED_INTERFACE_BITMAP
321 i
= mono_compress_bitmap (NULL
, bitmap
, bsize
);
322 klass
->interface_bitmap
= mono_class_alloc0 (klass
, i
);
323 mono_compress_bitmap (klass
->interface_bitmap
, bitmap
, bsize
);
326 klass
->interface_bitmap
= bitmap
;
330 mono_loader_unlock ();
332 g_free (interfaces_full
);
333 g_free (interface_offsets_full
);
335 for (i
= 0; i
< klass
->idepth
; i
++) {
336 ifaces
= ifaces_array
[i
];
338 g_ptr_array_free (ifaces
, TRUE
);
340 g_free (ifaces_array
);
343 //printf ("JUST DONE: ");
344 //print_implemented_interfaces (klass);
350 * Setup interface offsets for interfaces.
352 * - klass->max_interface_id
353 * - klass->interface_offsets_count
354 * - klass->interfaces_packed
355 * - klass->interface_offsets_packed
356 * - klass->interface_bitmap
358 * This function can fail @class.
362 mono_class_setup_interface_offsets (MonoClass
*klass
)
364 /* NOTE: This function is only correct for interfaces.
366 * It assumes that klass's interfaces can be assigned offsets starting
367 * from 0. That assumption is incorrect for classes and valuetypes.
369 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) && !mono_class_is_ginst (klass
));
370 mono_class_setup_interface_offsets_internal (klass
, 0, FALSE
);
374 #define DEBUG_INTERFACE_VTABLE_CODE 0
375 #define TRACE_INTERFACE_VTABLE_CODE 0
376 #define VERIFY_INTERFACE_VTABLE_CODE 0
377 #define VTABLE_SELECTOR (1)
379 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
380 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
381 if (!(VTABLE_SELECTOR)) break; \
385 #define DEBUG_INTERFACE_VTABLE(stmt)
388 #if TRACE_INTERFACE_VTABLE_CODE
389 #define TRACE_INTERFACE_VTABLE(stmt) do {\
390 if (!(VTABLE_SELECTOR)) break; \
394 #define TRACE_INTERFACE_VTABLE(stmt)
397 #if VERIFY_INTERFACE_VTABLE_CODE
398 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
399 if (!(VTABLE_SELECTOR)) break; \
403 #define VERIFY_INTERFACE_VTABLE(stmt)
407 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
409 mono_signature_get_full_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
413 GString
*res
= g_string_new ("");
415 g_string_append_c (res
, '(');
416 for (i
= 0; i
< sig
->param_count
; ++i
) {
418 g_string_append_c (res
, ',');
419 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
421 g_string_append (res
, ")=>");
422 if (sig
->ret
!= NULL
) {
423 mono_type_get_desc (res
, sig
->ret
, include_namespace
);
425 g_string_append (res
, "NULL");
428 g_string_free (res
, FALSE
);
432 print_method_signatures (MonoMethod
*im
, MonoMethod
*cm
) {
433 char *im_sig
= mono_signature_get_full_desc (mono_method_signature_internal (im
), TRUE
);
434 char *cm_sig
= mono_signature_get_full_desc (mono_method_signature_internal (cm
), TRUE
);
435 printf ("(IM \"%s\", CM \"%s\")", im_sig
, cm_sig
);
444 is_wcf_hack_disabled (void)
446 static char disabled
;
448 disabled
= g_hasenv ("MONO_DISABLE_WCF_HACK") ? 1 : 2;
449 return disabled
== 1;
453 check_interface_method_override (MonoClass
*klass
, MonoMethod
*im
, MonoMethod
*cm
, gboolean require_newslot
, gboolean interface_is_explicitly_implemented_by_class
, gboolean slot_is_empty
)
455 MonoMethodSignature
*cmsig
, *imsig
;
456 if (strcmp (im
->name
, cm
->name
) == 0) {
457 if (! (cm
->flags
& METHOD_ATTRIBUTE_PUBLIC
)) {
458 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
461 if (! slot_is_empty
) {
462 if (require_newslot
) {
463 if (! interface_is_explicitly_implemented_by_class
) {
464 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
467 if (! (cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
468 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
472 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
475 cmsig
= mono_method_signature_internal (cm
);
476 imsig
= mono_method_signature_internal (im
);
477 if (!cmsig
|| !imsig
) {
478 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
482 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
483 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
484 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
485 TRACE_INTERFACE_VTABLE (printf ("]"));
488 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
489 if (mono_security_core_clr_enabled ())
490 mono_security_core_clr_check_override (klass
, cm
, im
);
492 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
493 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
494 char *body_name
= mono_method_full_name (cm
, TRUE
);
495 char *decl_name
= mono_method_full_name (im
, TRUE
);
496 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
504 MonoClass
*ic
= im
->klass
;
505 const char *ic_name_space
= ic
->name_space
;
506 const char *ic_name
= ic
->name
;
509 if (! require_newslot
) {
510 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
513 if (cm
->klass
->rank
== 0) {
514 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
517 cmsig
= mono_method_signature_internal (cm
);
518 imsig
= mono_method_signature_internal (im
);
519 if (!cmsig
|| !imsig
) {
520 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
524 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
525 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
526 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
527 TRACE_INTERFACE_VTABLE (printf ("]"));
530 if (mono_class_get_image (ic
) != mono_defaults
.corlib
) {
531 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
534 if ((ic_name_space
== NULL
) || (strcmp (ic_name_space
, "System.Collections.Generic") != 0)) {
535 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
538 if ((ic_name
== NULL
) || ((strcmp (ic_name
, "IEnumerable`1") != 0) && (strcmp (ic_name
, "ICollection`1") != 0) && (strcmp (ic_name
, "IList`1") != 0) && (strcmp (ic_name
, "IReadOnlyList`1") != 0) && (strcmp (ic_name
, "IReadOnlyCollection`1") != 0))) {
539 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
543 subname
= (char*)strstr (cm
->name
, ic_name_space
);
544 if (subname
!= cm
->name
) {
545 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
548 subname
+= strlen (ic_name_space
);
549 if (subname
[0] != '.') {
550 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
554 if (strstr (subname
, ic_name
) != subname
) {
555 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
558 subname
+= strlen (ic_name
);
559 if (subname
[0] != '.') {
560 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
564 if (strcmp (subname
, im
->name
) != 0) {
565 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
569 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
570 if (mono_security_core_clr_enabled ())
571 mono_security_core_clr_check_override (klass
, cm
, im
);
573 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
574 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
575 char *body_name
= mono_method_full_name (cm
, TRUE
);
576 char *decl_name
= mono_method_full_name (im
, TRUE
);
577 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
587 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
589 foreach_override (gpointer key
, gpointer value
, gpointer user_data
)
591 MonoMethod
*method
= key
;
592 MonoMethod
*override
= value
;
594 char *method_name
= mono_method_get_full_name (method
);
595 char *override_name
= mono_method_get_full_name (override
);
596 printf (" Method '%s' has override '%s'\n", method_name
, override_name
);
597 g_free (method_name
);
598 g_free (override_name
);
602 print_overrides (GHashTable
*override_map
, const char *message
)
605 printf ("Override map \"%s\" START:\n", message
);
606 g_hash_table_foreach (override_map
, foreach_override
, NULL
);
607 printf ("Override map \"%s\" END.\n", message
);
609 printf ("Override map \"%s\" EMPTY.\n", message
);
614 print_vtable_full (MonoClass
*klass
, MonoMethod
** vtable
, int size
, int first_non_interface_slot
, const char *message
, gboolean print_interfaces
)
616 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
620 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name
, message
, size
);
622 if (print_interfaces
) {
623 print_implemented_interfaces (klass
);
624 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name
, size
);
628 parent_size
= klass
->parent
->vtable_size
;
632 for (i
= 0; i
< size
; ++i
) {
633 MonoMethod
*cm
= vtable
[i
];
634 char *cm_name
= cm
? mono_method_full_name (cm
, TRUE
) : g_strdup ("nil");
635 char newness
= (i
< parent_size
) ? 'O' : ((i
< first_non_interface_slot
) ? 'I' : 'N');
637 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness
, i
, cm
? cm
->slot
: - 1, cm_name
, cm
);
645 #if VERIFY_INTERFACE_VTABLE_CODE
647 mono_method_try_get_vtable_index (MonoMethod
*method
)
649 if (method
->is_inflated
&& (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
650 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
651 if (imethod
->declaring
->is_generic
)
652 return imethod
->declaring
->slot
;
658 mono_class_verify_vtable (MonoClass
*klass
)
661 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
663 printf ("*** Verifying VTable of class '%s' \n", full_name
);
670 count
= mono_class_get_method_count (klass
);
671 for (i
= 0; i
< count
; ++i
) {
672 MonoMethod
*cm
= klass
->methods
[i
];
675 if (!(cm
->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
679 full_name
= mono_method_full_name (cm
, TRUE
);
681 slot
= mono_method_try_get_vtable_index (cm
);
683 if (slot
>= klass
->vtable_size
) {
684 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name
, slot
, klass
->vtable_size
);
688 if (slot
>= 0 && klass
->vtable
[slot
] != cm
&& (klass
->vtable
[slot
])) {
689 char *other_name
= klass
->vtable
[slot
] ? mono_method_full_name (klass
->vtable
[slot
], TRUE
) : g_strdup ("[null value]");
690 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name
, slot
, other_name
);
694 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name
);
701 mono_method_get_method_definition (MonoMethod
*method
)
703 while (method
->is_inflated
)
704 method
= ((MonoMethodInflated
*)method
)->declaring
;
709 verify_class_overrides (MonoClass
*klass
, MonoMethod
**overrides
, int onum
)
713 for (i
= 0; i
< onum
; ++i
) {
714 MonoMethod
*decl
= overrides
[i
* 2];
715 MonoMethod
*body
= overrides
[i
* 2 + 1];
717 if (mono_class_get_generic_type_definition (body
->klass
) != mono_class_get_generic_type_definition (klass
)) {
718 mono_class_set_type_load_failure (klass
, "Method belongs to a different class than the declared one");
722 if (!(body
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (body
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
723 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
724 mono_class_set_type_load_failure (klass
, "Method must not be static to override a base type");
726 mono_class_set_type_load_failure (klass
, "Method must be virtual to override a base type");
730 if (!(decl
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (decl
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
731 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
732 mono_class_set_type_load_failure (klass
, "Cannot override a static method in a base type");
734 mono_class_set_type_load_failure (klass
, "Cannot override a non virtual method in a base type");
738 if (!mono_class_is_assignable_from_slow (decl
->klass
, klass
)) {
739 mono_class_set_type_load_failure (klass
, "Method overrides a class or interface that is not extended or implemented by this type");
743 body
= mono_method_get_method_definition (body
);
744 decl
= mono_method_get_method_definition (decl
);
746 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body
, decl
, NULL
)) {
747 char *body_name
= mono_method_full_name (body
, TRUE
);
748 char *decl_name
= mono_method_full_name (decl
, TRUE
);
749 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
758 /*Checks if @klass has @parent as one of it's parents type gtd
762 * Bar<T> : Foo<Bar<Bar<T>>>
766 mono_class_has_gtd_parent (MonoClass
*klass
, MonoClass
*parent
)
768 klass
= mono_class_get_generic_type_definition (klass
);
769 parent
= mono_class_get_generic_type_definition (parent
);
770 mono_class_setup_supertypes (klass
);
771 mono_class_setup_supertypes (parent
);
773 return klass
->idepth
>= parent
->idepth
&&
774 mono_class_get_generic_type_definition (klass
->supertypes
[parent
->idepth
- 1]) == parent
;
778 mono_class_check_vtable_constraints (MonoClass
*klass
, GList
*in_setup
)
780 MonoGenericInst
*ginst
;
783 if (!mono_class_is_ginst (klass
)) {
784 mono_class_setup_vtable_full (klass
, in_setup
);
785 return !mono_class_has_failure (klass
);
788 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass
), in_setup
);
789 if (mono_class_set_type_load_failure_causedby_class (klass
, mono_class_get_generic_class (klass
)->container_class
, "Failed to load generic definition vtable"))
792 ginst
= mono_class_get_generic_class (klass
)->context
.class_inst
;
793 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
795 if (ginst
->type_argv
[i
]->type
!= MONO_TYPE_GENERICINST
)
797 arg
= mono_class_from_mono_type_internal (ginst
->type_argv
[i
]);
798 /*Those 2 will be checked by mono_class_setup_vtable itself*/
799 if (mono_class_has_gtd_parent (klass
, arg
) || mono_class_has_gtd_parent (arg
, klass
))
801 if (!mono_class_check_vtable_constraints (arg
, in_setup
)) {
802 mono_class_set_type_load_failure (klass
, "Failed to load generic parameter %d", i
);
810 * mono_class_setup_vtable:
812 * Creates the generic vtable of CLASS.
813 * Initializes the following fields in MonoClass:
816 * Plus all the fields initialized by setup_interface_offsets ().
817 * If there is an error during vtable construction, klass->has_failure
818 * is set and details are stored in a MonoErrorBoxed.
820 * LOCKING: Acquires the loader lock.
823 mono_class_setup_vtable (MonoClass
*klass
)
825 mono_class_setup_vtable_full (klass
, NULL
);
829 mono_class_setup_vtable_full (MonoClass
*klass
, GList
*in_setup
)
832 MonoMethod
**overrides
= NULL
;
833 MonoGenericContext
*context
;
840 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
841 /* This sets method->slot for all methods if this is an interface */
842 mono_class_setup_methods (klass
);
846 if (mono_class_has_failure (klass
))
849 if (g_list_find (in_setup
, klass
))
855 mono_loader_unlock ();
859 UnlockedIncrement (&mono_stats
.generic_vtable_count
);
860 in_setup
= g_list_prepend (in_setup
, klass
);
862 if (mono_class_is_ginst (klass
)) {
863 if (!mono_class_check_vtable_constraints (klass
, in_setup
)) {
864 mono_loader_unlock ();
865 g_list_remove (in_setup
, klass
);
869 context
= mono_class_get_context (klass
);
870 type_token
= mono_class_get_generic_class (klass
)->container_class
->type_token
;
872 context
= (MonoGenericContext
*) mono_class_try_get_generic_container (klass
); //FIXME is this a case of a try?
873 type_token
= klass
->type_token
;
876 if (image_is_dynamic (klass
->image
)) {
877 /* Generic instances can have zero method overrides without causing any harm.
878 * This is true since we don't do layout all over again for them, we simply inflate
879 * the layout of the parent.
881 mono_reflection_get_dynamic_overrides (klass
, &overrides
, &onum
, error
);
882 if (!is_ok (error
)) {
883 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
887 /* The following call fails if there are missing methods in the type */
888 /* FIXME it's probably a good idea to avoid this for generic instances. */
889 mono_class_get_overrides_full (klass
->image
, type_token
, &overrides
, &onum
, context
, error
);
890 if (!is_ok (error
)) {
891 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
896 mono_class_setup_vtable_general (klass
, overrides
, onum
, in_setup
);
900 mono_error_cleanup (error
);
902 mono_loader_unlock ();
903 g_list_remove (in_setup
, klass
);
909 mono_class_setup_need_stelemref_method (MonoClass
*klass
)
911 return klass
->rank
== 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass
)));
915 apply_override (MonoClass
*klass
, MonoClass
*override_class
, MonoMethod
**vtable
, MonoMethod
*decl
, MonoMethod
*override
,
916 GHashTable
**override_map
, GHashTable
**override_class_map
, GHashTable
**conflict_map
)
919 dslot
= mono_method_get_vtable_slot (decl
);
921 mono_class_set_type_load_failure (klass
, "");
925 dslot
+= mono_class_interface_offset (klass
, decl
->klass
);
927 //check if the override comes from an interface and the overrided method is from a class, if this is the case it shouldn't be changed
928 if (vtable
[dslot
] && vtable
[dslot
]->klass
&& MONO_CLASS_IS_INTERFACE_INTERNAL (override
->klass
) && !MONO_CLASS_IS_INTERFACE_INTERNAL (vtable
[dslot
]->klass
))
931 vtable
[dslot
] = override
;
932 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override
->klass
)) {
934 * If override from an interface, then it is an override of a default interface method,
935 * don't override its slot.
937 vtable
[dslot
]->slot
= dslot
;
940 if (!*override_map
) {
941 *override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
942 *override_class_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
944 GHashTable
*map
= *override_map
;
945 GHashTable
*class_map
= *override_class_map
;
947 MonoMethod
*prev_override
= (MonoMethod
*)g_hash_table_lookup (map
, decl
);
948 MonoClass
*prev_override_class
= (MonoClass
*)g_hash_table_lookup (class_map
, decl
);
950 g_hash_table_insert (map
, decl
, override
);
951 g_hash_table_insert (class_map
, decl
, override_class
);
953 /* Collect potentially conflicting overrides which are introduced by default interface methods */
958 * The override methods are part of the generic definition, need to inflate them so their
959 * parent class becomes the actual interface/class containing the override, i.e.
961 * class Foo<T> : IFace<T>
962 * This is needed so the mono_class_is_assignable_from_internal () calls in the
963 * conflict resolution work.
965 if (mono_class_is_ginst (override_class
)) {
966 override
= mono_class_inflate_generic_method_checked (override
, &mono_class_get_generic_class (override_class
)->context
, error
);
967 mono_error_assert_ok (error
);
970 if (mono_class_is_ginst (prev_override_class
)) {
971 prev_override
= mono_class_inflate_generic_method_checked (prev_override
, &mono_class_get_generic_class (prev_override_class
)->context
, error
);
972 mono_error_assert_ok (error
);
976 *conflict_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
977 GHashTable
*cmap
= *conflict_map
;
978 GSList
*entries
= (GSList
*)g_hash_table_lookup (cmap
, decl
);
979 if (!(decl
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
980 entries
= g_slist_prepend (entries
, decl
);
981 entries
= g_slist_prepend (entries
, prev_override
);
982 entries
= g_slist_prepend (entries
, override
);
984 g_hash_table_insert (cmap
, decl
, entries
);
991 handle_dim_conflicts (MonoMethod
**vtable
, MonoClass
*klass
, GHashTable
*conflict_map
)
995 GSList
*entries
, *l
, *l2
;
996 GSList
*dim_conflicts
= NULL
;
998 g_hash_table_iter_init (&iter
, conflict_map
);
999 while (g_hash_table_iter_next (&iter
, (gpointer
*)&decl
, (gpointer
*)&entries
)) {
1001 * Iterate over the candidate methods, remove ones whose class is less concrete than the
1002 * class of another one.
1004 /* This is O(n^2), but that shouldn't be a problem in practice */
1005 for (l
= entries
; l
; l
= l
->next
) {
1006 for (l2
= entries
; l2
; l2
= l2
->next
) {
1007 MonoMethod
*m1
= (MonoMethod
*)l
->data
;
1008 MonoMethod
*m2
= (MonoMethod
*)l2
->data
;
1009 if (!m1
|| !m2
|| m1
== m2
)
1011 if (mono_class_is_assignable_from_internal (m1
->klass
, m2
->klass
))
1013 else if (mono_class_is_assignable_from_internal (m2
->klass
, m1
->klass
))
1018 MonoMethod
*impl
= NULL
;
1019 for (l
= entries
; l
; l
= l
->next
) {
1022 impl
= (MonoMethod
*)l
->data
;
1026 /* If more than one method is left, we have a conflict */
1027 if (decl
->is_inflated
)
1028 decl
= ((MonoMethodInflated
*)decl
)->declaring
;
1029 dim_conflicts
= g_slist_prepend (dim_conflicts
, decl
);
1031 for (l = entries; l; l = l->next) {
1033 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
1038 * Use the implementing method computed above instead of the already
1039 * computed one, which depends on interface ordering.
1041 int ic_offset
= mono_class_interface_offset (klass
, decl
->klass
);
1042 int im_slot
= ic_offset
+ decl
->slot
;
1043 vtable
[im_slot
] = impl
;
1045 g_slist_free (entries
);
1047 if (dim_conflicts
) {
1048 mono_loader_lock ();
1049 klass
->has_dim_conflicts
= 1;
1050 mono_loader_unlock ();
1053 * Exceptions are thrown at method call time and only for the methods which have
1054 * conflicts, so just save them in the class.
1057 /* Make a copy of the list from the class mempool */
1058 GSList
*conflicts
= (GSList
*)mono_class_alloc0 (klass
, g_slist_length (dim_conflicts
) * sizeof (GSList
));
1060 for (l
= dim_conflicts
; l
; l
= l
->next
) {
1061 conflicts
[i
].data
= l
->data
;
1062 conflicts
[i
].next
= &conflicts
[i
+ 1];
1065 conflicts
[i
- 1].next
= NULL
;
1067 mono_class_set_dim_conflicts (klass
, conflicts
);
1068 g_slist_free (dim_conflicts
);
1073 print_unimplemented_interface_method_info (MonoClass
*klass
, MonoClass
*ic
, MonoMethod
*im
, int im_slot
, MonoMethod
**overrides
, int onum
)
1076 char *method_signature
;
1079 for (index
= 0; index
< onum
; ++index
) {
1080 mono_trace_warning (MONO_TRACE_TYPE
, " at slot %d: %s (%d) overrides %s (%d)", im_slot
, overrides
[index
*2+1]->name
,
1081 overrides
[index
*2+1]->slot
, overrides
[index
*2]->name
, overrides
[index
*2]->slot
);
1083 method_signature
= mono_signature_get_desc (mono_method_signature_internal (im
), FALSE
);
1084 type_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
1085 mono_trace_warning (MONO_TRACE_TYPE
, "no implementation for interface method %s::%s(%s) in class %s",
1086 mono_type_get_name (m_class_get_byval_arg (ic
)), im
->name
, method_signature
, type_name
);
1087 g_free (method_signature
);
1089 mono_class_setup_methods (klass
);
1090 if (mono_class_has_failure (klass
)) {
1091 char *name
= mono_type_get_full_name (klass
);
1092 mono_trace_warning (MONO_TRACE_TYPE
, "CLASS %s failed to resolve methods", name
);
1096 mcount
= mono_class_get_method_count (klass
);
1097 for (index
= 0; index
< mcount
; ++index
) {
1098 MonoMethod
*cm
= klass
->methods
[index
];
1099 method_signature
= mono_signature_get_desc (mono_method_signature_internal (cm
), TRUE
);
1101 mono_trace_warning (MONO_TRACE_TYPE
, "METHOD %s(%s)", cm
->name
, method_signature
);
1102 g_free (method_signature
);
1107 * mono_class_get_virtual_methods:
1109 * Iterate over the virtual methods of KLASS.
1111 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
1114 mono_class_get_virtual_methods (MonoClass
* klass
, gpointer
*iter
)
1116 // FIXME move state to caller
1117 gboolean static_iter
= FALSE
;
1123 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
1124 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
1127 if ((gsize
)(*iter
) & 1)
1129 /* Use the static metadata only if klass->methods is not yet initialized */
1130 if (!static_iter
&& !(klass
->methods
|| !MONO_CLASS_HAS_STATIC_METADATA (klass
)))
1134 MonoMethod
** methodptr
;
1137 mono_class_setup_methods (klass
);
1139 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
1140 * FIXME we should better report this error to the caller
1142 if (!klass
->methods
)
1144 /* start from the first */
1145 methodptr
= &klass
->methods
[0];
1147 methodptr
= (MonoMethod
**)*iter
;
1151 g_assert ((guint64
)(*iter
) > 0x100);
1152 int mcount
= mono_class_get_method_count (klass
);
1153 while (methodptr
< &klass
->methods
[mcount
]) {
1154 if (*methodptr
&& ((*methodptr
)->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
1158 if (methodptr
< &klass
->methods
[mcount
]) {
1165 /* Search directly in metadata to avoid calling setup_methods () */
1166 MonoMethod
*res
= NULL
;
1172 start_index
= GPOINTER_TO_UINT (*iter
) >> 1;
1175 int first_idx
= mono_class_get_first_method_idx (klass
);
1176 int mcount
= mono_class_get_method_count (klass
);
1177 for (i
= start_index
; i
< mcount
; ++i
) {
1180 /* first_idx points into the methodptr table */
1181 flags
= mono_metadata_decode_table_row_col (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
, MONO_METHOD_FLAGS
);
1183 if (flags
& METHOD_ATTRIBUTE_VIRTUAL
)
1189 res
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| (first_idx
+ i
+ 1), klass
, NULL
, error
);
1190 mono_error_cleanup (error
); /* FIXME don't swallow the error */
1192 /* Add 1 here so the if (*iter) check fails */
1193 *iter
= GUINT_TO_POINTER (((i
+ 1) << 1) | 1);
1202 print_vtable_layout_result (MonoClass
*klass
, MonoMethod
**vtable
, int cur_slot
)
1206 print_implemented_interfaces (klass
);
1208 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
1209 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
1212 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass
)),
1213 klass
->vtable_size
, icount
);
1215 for (i
= 0; i
< cur_slot
; ++i
) {
1220 printf (" slot assigned: %03d, slot index: %03d %s\n", i
, cm
->slot
,
1221 mono_method_get_full_name (cm
));
1223 printf (" slot assigned: %03d, <null>\n", i
);
1229 printf ("Interfaces %s.%s (max_iid = %d)\n", klass
->name_space
,
1230 klass
->name
, klass
->max_interface_id
);
1232 for (i
= 0; i
< klass
->interface_count
; i
++) {
1233 MonoClass
*ic
= klass
->interfaces
[i
];
1234 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
1235 mono_class_interface_offset (klass
, ic
),
1236 mono_class_setup_count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
1239 for (MonoClass
*k
= klass
->parent
; k
; k
= k
->parent
) {
1240 for (i
= 0; i
< k
->interface_count
; i
++) {
1241 MonoClass
*ic
= k
->interfaces
[i
];
1242 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
1243 mono_class_interface_offset (klass
, ic
),
1244 mono_class_setup_count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
1251 * LOCKING: this is supposed to be called with the loader lock held.
1254 setup_class_vtsize (MonoClass
*klass
, GList
*in_setup
, int *cur_slot
, int *stelemref_slot
, MonoError
*error
)
1256 GPtrArray
*ifaces
= NULL
;
1257 int i
, max_vtsize
= 0;
1258 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
1259 if (!is_ok (error
)) {
1260 char *name
= mono_type_get_full_name (klass
);
1261 mono_class_set_type_load_failure (klass
, "Could not resolve %s interfaces due to %s", name
, mono_error_get_message (error
));
1263 mono_error_cleanup (error
);
1265 } else if (ifaces
) {
1266 for (i
= 0; i
< ifaces
->len
; i
++) {
1267 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1268 max_vtsize
+= mono_class_get_method_count (ic
);
1270 g_ptr_array_free (ifaces
, TRUE
);
1274 if (klass
->parent
) {
1275 mono_class_init_internal (klass
->parent
);
1276 mono_class_setup_vtable_full (klass
->parent
, in_setup
);
1278 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Parent class failed to load"))
1281 max_vtsize
+= klass
->parent
->vtable_size
;
1282 *cur_slot
= klass
->parent
->vtable_size
;
1285 max_vtsize
+= mono_class_get_method_count (klass
);
1287 /*Array have a slot for stelemref*/
1288 if (mono_class_setup_need_stelemref_method (klass
)) {
1289 *stelemref_slot
= *cur_slot
;
1297 * LOCKING: this is supposed to be called with the loader lock held.
1300 mono_class_setup_vtable_ginst (MonoClass
*klass
, GList
*in_setup
)
1304 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
1307 mono_class_setup_vtable_full (gklass
, in_setup
);
1308 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Could not load generic definition"))
1311 tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * gklass
->vtable_size
);
1312 klass
->vtable_size
= gklass
->vtable_size
;
1313 for (i
= 0; i
< gklass
->vtable_size
; ++i
)
1314 if (gklass
->vtable
[i
]) {
1315 MonoMethod
*inflated
= mono_class_inflate_generic_method_full_checked (gklass
->vtable
[i
], klass
, mono_class_get_context (klass
), error
);
1316 if (!is_ok (error
)) {
1317 char *name
= mono_type_get_full_name (klass
);
1318 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed due to: %s", name
, mono_error_get_message (error
));
1319 mono_error_cleanup (error
);
1324 tmp
[i
]->slot
= gklass
->vtable
[i
]->slot
;
1326 mono_memory_barrier ();
1327 klass
->vtable
= tmp
;
1329 mono_loader_lock ();
1330 klass
->has_dim_conflicts
= gklass
->has_dim_conflicts
;
1331 mono_loader_unlock ();
1333 /* Have to set method->slot for abstract virtual methods */
1334 if (klass
->methods
&& gklass
->methods
) {
1335 int mcount
= mono_class_get_method_count (klass
);
1336 for (i
= 0; i
< mcount
; ++i
)
1337 if (klass
->methods
[i
]->slot
== -1)
1338 klass
->methods
[i
]->slot
= gklass
->methods
[i
]->slot
;
1341 if (mono_print_vtable
)
1342 print_vtable_layout_result (klass
, klass
->vtable
, gklass
->vtable_size
);
1346 #ifdef FEATURE_COVARIANT_RETURNS
1348 * vtable_slot_has_preserve_base_overrides_attribute:
1350 * Needs to walk up the class hierarchy looking for the methods in this slot to
1351 * see if any are tagged with PreserveBaseOverrideAtrribute.
1354 vtable_slot_has_preserve_base_overrides_attribute (MonoClass
*klass
, int slot
, MonoClass
**out_klass
)
1357 * FIXME: it's slow to do this loop every time. A faster way would be
1358 * to hang a boolean in the image of the parent class if it or any of
1359 * its ancestors have the attribute.
1362 for (; klass
; klass
= klass
->parent
) {
1363 if (slot
>= klass
->vtable_size
)
1365 MonoMethod
*method
= klass
->vtable
[slot
];
1367 /* FIXME: for abstract classes, do we put abstract methods here? */
1368 if (method
&& mono_class_setup_method_has_preserve_base_overrides_attribute (method
)) {
1378 * is_ok_for_covariant_ret:
1380 * Returns TRUE if the given pair of types are a valid return type for the covariant returns feature.
1382 * This is the CanCastTo relation from ECMA (impl type can be cast to the decl
1383 * type), except that we don't allow a valuetype to be cast to one of its
1384 * implemented interfaces, and we don't allow T to Nullable<T>.
1387 is_ok_for_covariant_ret (MonoType
*type_impl
, MonoType
*type_decl
)
1389 if (type_impl
->byref
^ type_decl
->byref
)
1392 if (type_impl
->byref
) {
1393 return mono_byref_type_is_assignable_from (type_decl
, type_impl
, TRUE
);
1395 /* method declared to return an interface, impl returns a value type that implements the interface */
1396 if (!mono_type_is_reference (type_impl
) && mono_type_is_reference (type_decl
))
1400 TRACE_INTERFACE_VTABLE (do {
1401 char *decl_str
= mono_type_full_name (type_decl
);
1402 char *impl_str
= mono_type_full_name (type_impl
);
1403 printf ("Checking if %s is assignable from %s", decl_str
, impl_str
);
1408 MonoClass
*class_impl
= mono_class_from_mono_type_internal (type_impl
);
1409 MonoClass
*class_decl
= mono_class_from_mono_type_internal (type_decl
);
1411 /* Also disallow overriding a Nullable<T> return with an impl that
1413 if (mono_class_is_nullable (class_decl
) &&
1414 mono_class_get_nullable_param_internal (class_decl
) == class_impl
)
1418 ERROR_DECL (local_error
);
1419 gboolean result
= FALSE
;
1420 mono_class_signature_is_assignable_from (class_decl
, class_impl
, &result
, local_error
);
1421 mono_error_cleanup (local_error
);
1426 * signature_is_subsumed:
1427 * \param impl_method method that implements the override. defined in \p klass
1428 * \param decl_method method that is being overridden.
1430 * Check that \p impl_method has a signature that is subsumed by the signature of \p decl_method. That is,
1431 * that the argument types all match and that the return type of \p impl_method is castable to the return type of \p decl_method, except that
1432 * both must not be valuetypes or interfaces.
1434 * Returns \c TRUE if \p impl_method is subsumed by \p decl_method, or FALSE otherwise. On error sets \p error and returns \c FALSE
1436 * Note that \p decl_method may not be the explicitly overridden method as specified by an .override in the class where \p impl_method is defined,
1437 * but rather some method on an ancestor class that is itself a previous override.
1440 * public virtual C Foo ();
1443 * public virtual newslot B Foo () {
1444 * .PreserveBaseOverrideAttribute;
1445 * .override C C::Foo ();
1449 * public virtual newslot C Foo () {
1450 * .override C C::Foo (); // type load error - it should be a a subclass of B because of B's override of C::Foo
1455 signature_is_subsumed (MonoMethod
*impl_method
, MonoMethod
*decl_method
, MonoError
*error
)
1457 MonoMethodSignature
*impl_sig
= mono_method_signature_internal (impl_method
);
1458 MonoMethodSignature
*decl_sig
= mono_method_signature_internal (decl_method
);
1460 if (mono_metadata_signature_equal (impl_sig
, decl_sig
))
1463 if (!mono_metadata_signature_equal_no_ret (impl_sig
, decl_sig
))
1466 MonoType
*impl_ret
= impl_sig
->ret
;
1467 MonoType
*decl_ret_0
= decl_sig
->ret
;
1470 * Comparing return types of generic methods:
1472 * Suppose decl is a generic method RetTy0`2[!!0,!!1] Method<T1,T2> (DeclArgTys...)
1473 * we need to check that:
1475 * 1. impl is a generic method with the same number of type arguments
1476 * ImplRetTy Method<S1,S2> (ImplArgTys...)
1477 * (because the number of generic arguments isn't allowed to change)
1478 * 2. Inflate RetTy0`2[T1,T2] with S1,S2 for T1,T2 to get RetTy0`2[S1,S2]
1479 * 3. Compare if ImplRetTy is assignable to RetTy0`2[S1,S2]
1481 * (For example the decl method might return IReadOnlyDictionary<K,V>
1482 * Foo<K,V>() and the impl method might be SortedList<A,B> Foo<A,B>(),
1483 * so we want to check that SortedList<A,B> is assignable to
1484 * IReadOnlyDictionary<A,B>. If we naively check SortedList<A,B>
1485 * against IReadOnlyDictionary<K,V> it will fail because the
1486 * implementation of the assignable relation won't consider K and A
1489 * It's possible that actually mono_metadata_signature_equal will work
1490 * (because it does a signature check which considers !!0 equal to !!0
1491 * even if they come from different generic containers), so if the
1492 * return types are identical, we won't even get here, but for the
1493 * return type assignable checking, we need to inflate RetTy0 properly.
1496 /* We only inflate the return type, not the entire method signature,
1497 * because the signature_equal_no_ret check above can compare
1498 * corresponding positional type parameters even if they come from
1499 * different generic methods. So since the arguments aren't allowed to
1500 * vary at all, we know they were already identical and we only need to
1501 * compare return types.
1504 /* both have to be non-generic, or both generic */
1505 if ((impl_method
->is_generic
|| decl_method
->is_generic
) &&
1506 !!impl_method
->is_generic
!= !!decl_method
->is_generic
)
1510 MonoType
*alloc_decl_ret
= NULL
;
1511 if (!impl_method
->is_generic
) {
1512 decl_ret
= decl_ret_0
;
1514 g_assert (decl_method
->is_generic
);
1516 MonoGenericContainer
*impl_container
= mono_method_get_generic_container (impl_method
);
1517 MonoGenericContainer
*decl_container
= mono_method_get_generic_container (decl_method
);
1519 g_assert (decl_container
!= NULL
);
1520 g_assert (impl_container
!= NULL
);
1522 if (impl_container
->type_argc
!= decl_container
->type_argc
)
1525 /* inflate decl's return type with the type parameters of impl */
1526 alloc_decl_ret
= mono_class_inflate_generic_type_checked (decl_ret_0
, &impl_container
->context
, error
);
1527 return_val_if_nok (error
, FALSE
);
1528 decl_ret
= alloc_decl_ret
;
1531 gboolean result
= is_ok_for_covariant_ret (impl_ret
, decl_ret
);
1533 mono_metadata_free_type (alloc_decl_ret
);
1538 check_signature_covariant (MonoClass
*klass
, MonoMethod
*impl
, MonoMethod
*decl
)
1540 TRACE_INTERFACE_VTABLE (printf (" checking covariant signature compatability on behalf of %s: '%s' overriding '%s'\n", mono_type_full_name (m_class_get_byval_arg (klass
)), mono_method_full_name (impl
, 1), mono_method_full_name (decl
, 1)));
1541 ERROR_DECL (local_error
);
1542 gboolean subsumed
= signature_is_subsumed (impl
, decl
, local_error
);
1543 if (!is_ok (local_error
) || !subsumed
) {
1544 const gboolean print_sig
= TRUE
;
1545 const gboolean print_ret_type
= TRUE
;
1546 char *decl_method_name
= mono_method_get_name_full (decl
, print_sig
, print_ret_type
, MONO_TYPE_NAME_FORMAT_IL
);
1547 char *impl_method_name
= mono_method_get_name_full (impl
, print_sig
, print_ret_type
, MONO_TYPE_NAME_FORMAT_IL
);
1549 if (!is_ok (local_error
)) {
1550 msg
= mono_error_get_message (local_error
);
1552 msg
= "but with an incompatible signature";
1554 mono_class_set_type_load_failure (klass
, "Method '%s' overrides method '%s', %s",
1555 impl_method_name
, decl_method_name
, msg
);
1556 mono_error_cleanup (local_error
);
1557 g_free (decl_method_name
);
1558 g_free (impl_method_name
);
1565 * check_vtable_covariant_override_impls:
1566 * \param klass the class
1567 * \param vtable the provisional vtable
1568 * \param vtable_size the number of slots in the vtable
1570 * Given a provisional vtable for a class, check that any methods that come from \p klass that have the \c
1571 * MonoMethodDefInfrequentBits:is_covariant_override_impl bit have the most specific signature of any method in that
1572 * slot in the ancestor classes. This checks that if the current class is overriding a method, it is doing so with the
1573 * most specific signature.
1575 * Because classes can override methods either explicitly using an .override directive or implicitly by matching the
1576 * signature of some virtual method of some ancestor class, you could get into a situation where a class incorrectly
1577 * overrides a method with a less specific signature.
1582 * public virtual A Foo ();
1585 * public override B Foo (); // covariant return override
1588 * public override A Foo (); // incorrect
1592 check_vtable_covariant_override_impls (MonoClass
*klass
, MonoMethod
**vtable
, int vtable_size
)
1594 MonoClass
*parent_class
= klass
->parent
;
1598 /* we only need to check the slots that the parent class has, too. Everything else is new. */
1599 for (int slot
= 0; slot
< parent_class
->vtable_size
; ++slot
) {
1600 MonoMethod
*impl
= vtable
[slot
];
1601 if (!impl
|| !mono_method_get_is_covariant_override_impl (impl
) || impl
->klass
!= klass
)
1603 MonoMethod
*last_checked_prev_override
= NULL
;
1604 for (MonoClass
*cur_class
= parent_class
; cur_class
; cur_class
= cur_class
->parent
) {
1605 if (slot
>= cur_class
->vtable_size
)
1607 MonoMethod
*prev_impl
= cur_class
->vtable
[slot
];
1609 if (prev_impl
!= last_checked_prev_override
) {
1611 * the new impl should be subsumed by the prior one, ie this
1612 * newest leaf class provides the most specific implementation
1613 * of the method of any of its ancestor classes.
1616 * but as we go up the inheritance hierarchy only check if the
1617 * prev_impl method is changing. If it's the same one in the
1618 * slot the whole time, don't bother checking it over and
1621 /* FIXME: do we need to check all the way up? can we just check the most derived one? */
1622 if (!check_signature_covariant (klass
, impl
, prev_impl
))
1624 last_checked_prev_override
= prev_impl
;
1630 #endif /* FEATURE_COVARIANT_RETURNS */
1633 * LOCKING: this is supposed to be called with the loader lock held.
1636 mono_class_setup_vtable_general (MonoClass
*klass
, MonoMethod
**overrides
, int onum
, GList
*in_setup
)
1640 MonoMethod
**vtable
= NULL
;
1641 int i
, max_vtsize
= 0, cur_slot
= 0;
1642 GHashTable
*override_map
= NULL
;
1643 GHashTable
*override_class_map
= NULL
;
1644 GHashTable
*conflict_map
= NULL
;
1646 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
1647 int first_non_interface_slot
;
1649 GSList
*virt_methods
= NULL
, *l
;
1650 int stelemref_slot
= 0;
1655 if (overrides
&& !verify_class_overrides (klass
, overrides
, onum
))
1658 max_vtsize
= setup_class_vtsize (klass
, in_setup
, &cur_slot
, &stelemref_slot
, error
);
1659 if (max_vtsize
== -1)
1662 cur_slot
= mono_class_setup_interface_offsets_internal (klass
, cur_slot
, TRUE
);
1663 if (cur_slot
== -1) /*setup_interface_offsets fails the type.*/
1666 DEBUG_INTERFACE_VTABLE (first_non_interface_slot
= cur_slot
);
1668 /* Optimized version for generic instances */
1669 if (mono_class_is_ginst (klass
)) {
1670 mono_class_setup_vtable_ginst (klass
, in_setup
);
1674 vtable
= (MonoMethod
**)g_malloc0 (sizeof (gpointer
) * max_vtsize
);
1676 if (klass
->parent
&& klass
->parent
->vtable_size
)
1677 memcpy (vtable
, klass
->parent
->vtable
, sizeof (gpointer
) * klass
->parent
->vtable_size
);
1679 /*Array have a slot for stelemref*/
1680 if (mono_class_setup_need_stelemref_method (klass
)) {
1681 MonoMethod
*method
= mono_marshal_get_virtual_stelemref (klass
);
1683 method
->slot
= stelemref_slot
;
1685 g_assert (method
->slot
== stelemref_slot
);
1687 vtable
[stelemref_slot
] = method
;
1690 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER INHERITING PARENT VTABLE", TRUE
));
1692 /* Process overrides from interface default methods */
1693 // FIXME: Ordering between interfaces
1694 for (int ifindex
= 0; ifindex
< klass
->interface_offsets_count
; ifindex
++) {
1695 ic
= klass
->interfaces_packed
[ifindex
];
1697 mono_class_setup_methods (ic
);
1698 if (mono_class_has_failure (ic
))
1701 MonoMethod
**iface_overrides
;
1703 mono_class_get_overrides_full (ic
->image
, ic
->type_token
, &iface_overrides
, &iface_onum
, mono_class_get_context (ic
), error
);
1704 goto_if_nok (error
, fail
);
1705 for (int i
= 0; i
< iface_onum
; i
++) {
1706 MonoMethod
*decl
= iface_overrides
[i
*2];
1707 MonoMethod
*override
= iface_overrides
[i
*2 + 1];
1708 if (decl
->is_inflated
) {
1709 override
= mono_class_inflate_generic_method_checked (override
, mono_method_get_context (decl
), error
);
1710 mono_error_assert_ok (error
);
1711 } else if (mono_class_is_gtd (override
->klass
)) {
1712 override
= mono_class_inflate_generic_method_full_checked (override
, ic
, mono_class_get_context (ic
), error
);
1714 if (!apply_override (klass
, ic
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
1717 g_free (iface_overrides
);
1720 /* override interface methods */
1721 for (i
= 0; i
< onum
; i
++) {
1722 MonoMethod
*decl
= overrides
[i
*2];
1723 MonoMethod
*override
= overrides
[i
*2 + 1];
1724 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
1725 if (!apply_override (klass
, klass
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
1730 TRACE_INTERFACE_VTABLE (print_overrides (override_map
, "AFTER OVERRIDING INTERFACE METHODS"));
1731 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER OVERRIDING INTERFACE METHODS", FALSE
));
1734 * Create a list of virtual methods to avoid calling
1735 * mono_class_get_virtual_methods () which is slow because of the metadata
1739 gpointer iter
= NULL
;
1742 virt_methods
= NULL
;
1743 while ((cm
= mono_class_get_virtual_methods (klass
, &iter
))) {
1744 virt_methods
= g_slist_prepend (virt_methods
, cm
);
1746 if (mono_class_has_failure (klass
))
1750 // Loop on all implemented interfaces...
1751 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
1752 MonoClass
*parent
= klass
->parent
;
1754 gboolean interface_is_explicitly_implemented_by_class
;
1757 ic
= klass
->interfaces_packed
[i
];
1758 ic_offset
= mono_class_interface_offset (klass
, ic
);
1760 mono_class_setup_methods (ic
);
1761 if (mono_class_has_failure (ic
))
1764 // Check if this interface is explicitly implemented (instead of just inherited)
1765 if (parent
!= NULL
) {
1766 int implemented_interfaces_index
;
1767 interface_is_explicitly_implemented_by_class
= FALSE
;
1768 for (implemented_interfaces_index
= 0; implemented_interfaces_index
< klass
->interface_count
; implemented_interfaces_index
++) {
1769 if (ic
== klass
->interfaces
[implemented_interfaces_index
]) {
1770 interface_is_explicitly_implemented_by_class
= TRUE
;
1775 interface_is_explicitly_implemented_by_class
= TRUE
;
1778 // Loop on all interface methods...
1779 int mcount
= mono_class_get_method_count (ic
);
1780 for (im_index
= 0; im_index
< mcount
; im_index
++) {
1781 MonoMethod
*im
= ic
->methods
[im_index
];
1782 int im_slot
= ic_offset
+ im
->slot
;
1783 MonoMethod
*override_im
= (override_map
!= NULL
) ? (MonoMethod
*)g_hash_table_lookup (override_map
, im
) : NULL
;
1785 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
1788 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im
,1)));
1790 if (override_im
== NULL
|| (override_im
&& MONO_CLASS_IS_INTERFACE_INTERNAL(override_im
->klass
))) {
1794 // First look for a suitable method among the class methods
1795 for (l
= virt_methods
; l
; l
= l
->next
) {
1796 cm
= (MonoMethod
*)l
->data
;
1797 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
)));
1798 if (check_interface_method_override (klass
, im
, cm
, TRUE
, interface_is_explicitly_implemented_by_class
, (vtable
[im_slot
] == NULL
))) {
1799 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
1800 vtable
[im_slot
] = cm
;
1801 /* Why do we need this? */
1806 g_hash_table_remove(conflict_map
, im
);
1809 TRACE_INTERFACE_VTABLE (printf ("\n"));
1810 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
1814 // If the slot is still empty, look in all the inherited virtual methods...
1815 if ((vtable
[im_slot
] == NULL
) && klass
->parent
!= NULL
) {
1816 MonoClass
*parent
= klass
->parent
;
1817 // Reverse order, so that last added methods are preferred
1818 for (cm_index
= parent
->vtable_size
- 1; cm_index
>= 0; cm_index
--) {
1819 MonoMethod
*cm
= parent
->vtable
[cm_index
];
1821 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
));
1822 if ((cm
!= NULL
) && check_interface_method_override (klass
, im
, cm
, FALSE
, FALSE
, TRUE
)) {
1823 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
1824 vtable
[im_slot
] = cm
;
1825 /* Why do we need this? */
1831 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
1833 TRACE_INTERFACE_VTABLE ((cm
!= NULL
) && printf ("\n"));
1837 if (vtable
[im_slot
] == NULL
) {
1838 if (!(im
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)) {
1839 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im
, 1)));
1840 vtable
[im_slot
] = im
;
1844 g_assert (vtable
[im_slot
] == override_im
);
1849 // If the class is not abstract, check that all its interface slots are full.
1850 // The check is done here and not directly at the end of the loop above because
1851 // it can happen (for injected generic array interfaces) that the same slot is
1852 // processed multiple times (those interfaces have overlapping slots), and it
1853 // will not always be the first pass the one that fills the slot.
1854 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
1855 if (!mono_class_is_abstract (klass
)) {
1856 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
1860 ic
= klass
->interfaces_packed
[i
];
1861 ic_offset
= mono_class_interface_offset (klass
, ic
);
1863 int mcount
= mono_class_get_method_count (ic
);
1864 for (im_index
= 0; im_index
< mcount
; im_index
++) {
1865 MonoMethod
*im
= ic
->methods
[im_index
];
1866 int im_slot
= ic_offset
+ im
->slot
;
1868 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
1870 if (mono_method_get_is_reabstracted (im
))
1873 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
1874 im_slot
, ic
->name_space
, ic
->name
, im
->name
, (vtable
[im_slot
] == NULL
)));
1875 if (vtable
[im_slot
] == NULL
) {
1876 print_unimplemented_interface_method_info (klass
, ic
, im
, im_slot
, overrides
, onum
);
1883 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER SETTING UP INTERFACE METHODS", FALSE
));
1884 for (l
= virt_methods
; l
; l
= l
->next
) {
1885 cm
= (MonoMethod
*)l
->data
;
1887 * If the method is REUSE_SLOT, we must check in the
1888 * base class for a method to override.
1890 if (!(cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
1892 for (k
= klass
->parent
; k
; k
= k
->parent
) {
1897 while ((m1
= mono_class_get_virtual_methods (k
, &k_iter
))) {
1898 MonoMethodSignature
*cmsig
, *m1sig
;
1900 cmsig
= mono_method_signature_internal (cm
);
1901 m1sig
= mono_method_signature_internal (m1
);
1903 if (!cmsig
|| !m1sig
) /* FIXME proper error message, use signature_checked? */
1906 if (!strcmp(cm
->name
, m1
->name
) &&
1907 mono_metadata_signature_equal (cmsig
, m1sig
)) {
1909 if (mono_security_core_clr_enabled ())
1910 mono_security_core_clr_check_override (klass
, cm
, m1
);
1912 slot
= mono_method_get_vtable_slot (m1
);
1916 #ifdef FEATURE_COVARIANT_RETURNS
1917 if (vtable
[slot
] && mono_method_get_is_covariant_override_impl (vtable
[slot
])) {
1918 TRACE_INTERFACE_VTABLE (printf (" in class %s, implicit override %s overrides %s in slot %d, which contained %s which had the covariant return bit\n", mono_type_full_name (m_class_get_byval_arg (klass
)), mono_method_full_name (cm
, 1), mono_method_full_name (m1
, 1), slot
, mono_method_full_name (vtable
[slot
], 1)));
1919 /* Mark the current method as overriding a covariant return method; after the explicit overloads are applied, if this method is still in its slot in the vtable, we will check that it's the most specific implementation */
1920 mono_method_set_is_covariant_override_impl (cm
);
1922 #endif /* FEATURE_COVARIANT_RETURNS */
1924 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, m1
, NULL
)) {
1925 char *body_name
= mono_method_full_name (cm
, TRUE
);
1926 char *decl_name
= mono_method_full_name (m1
, TRUE
);
1927 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
1933 g_assert (cm
->slot
< max_vtsize
);
1935 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1936 TRACE_INTERFACE_VTABLE (printf ("adding base class override from %s [%p] to %s [%p]\n",
1937 mono_method_full_name (m1
, 1), m1
,
1938 mono_method_full_name (cm
, 1), cm
));
1939 g_hash_table_insert (override_map
, m1
, cm
);
1943 if (mono_class_has_failure (k
))
1953 /*Non final newslot methods must be given a non-interface vtable slot*/
1954 if ((cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
) && !(cm
->flags
& METHOD_ATTRIBUTE_FINAL
) && cm
->slot
>= 0)
1958 cm
->slot
= cur_slot
++;
1960 if (!(cm
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
1961 vtable
[cm
->slot
] = cm
;
1964 /* override non interface methods */
1965 for (i
= 0; i
< onum
; i
++) {
1966 MonoMethod
*decl
= overrides
[i
*2];
1967 MonoMethod
*impl
= overrides
[i
*2 + 1];
1968 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
1969 g_assert (decl
->slot
!= -1);
1970 #ifdef FEATURE_COVARIANT_RETURNS
1971 MonoMethod
*prev_impl
= vtable
[decl
->slot
];
1973 vtable
[decl
->slot
] = impl
;
1974 #ifdef FEATURE_COVARIANT_RETURNS
1975 gboolean impl_newslot
= (impl
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
) != 0;
1976 /* covariant returns generate an explicit override impl with a newslot flag. respect it. */
1978 impl
->slot
= decl
->slot
;
1981 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1982 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
1983 mono_method_full_name (decl
, 1), decl
,
1984 mono_method_full_name (impl
, 1), impl
));
1985 g_hash_table_insert (override_map
, decl
, impl
);
1987 #ifdef FEATURE_COVARIANT_RETURNS
1988 MonoClass
*impl_class
= impl
->klass
;
1989 gboolean has_preserve_base_overrides
=
1990 mono_class_setup_method_has_preserve_base_overrides_attribute (impl
) ||
1992 vtable_slot_has_preserve_base_overrides_attribute (klass
->parent
, decl
->slot
, &impl_class
) &&
1993 impl_class
!= decl
->klass
);
1995 if (impl_class
== decl
->klass
) {
1996 TRACE_INTERFACE_VTABLE (printf ("preserve base overrides attribute is on slot %d is on the decl method %s; not adding any more overrides\n", decl
->slot
, mono_method_full_name (decl
, 1)));
1999 if (has_preserve_base_overrides
) {
2000 g_assert (impl_class
!= NULL
);
2001 g_assert (impl_class
== klass
|| decl
->slot
< impl_class
->vtable_size
);
2002 TRACE_INTERFACE_VTABLE (do {
2003 MonoMethod
*impl_with_attr
= impl_class
== klass
? impl
: impl_class
->vtable
[decl
->slot
];
2004 printf ("override decl [slot %d] %s in class %s has method %s in this slot and it has the preserve base overrides attribute. overridden by %s\n", decl
->slot
, mono_method_full_name (decl
, 1), mono_type_full_name (m_class_get_byval_arg (impl_class
)), mono_method_full_name (impl_with_attr
, 1), mono_method_full_name (impl
, 1));
2008 /* Historically, mono didn't do a signature equivalence check for explicit overrides, but we need one for covariant returns */
2009 /* If the previous impl in the slot had the covariant signature bit set, or if the signature of the proposed impl doesn't match the signature of the previous impl, check for covariance */
2010 if (prev_impl
!= NULL
&&
2011 (mono_method_get_is_covariant_override_impl (prev_impl
) ||
2012 !mono_metadata_signature_equal (mono_method_signature_internal (impl
), mono_method_signature_internal (prev_impl
)))) {
2013 mono_method_set_is_covariant_override_impl (impl
);
2016 /* if we saw the attribute or if we think we need to check impl sigs, we will need to traverse the class hierarchy. */
2017 if (has_preserve_base_overrides
) {
2018 for (MonoClass
*cur_class
= klass
->parent
; cur_class
; cur_class
= cur_class
->parent
) {
2019 if (decl
->slot
>= cur_class
->vtable_size
)
2021 prev_impl
= cur_class
->vtable
[decl
->slot
];
2022 g_hash_table_insert (override_map
, prev_impl
, impl
);
2023 TRACE_INTERFACE_VTABLE (do {
2024 char *full_name
= mono_type_full_name (m_class_get_byval_arg (cur_class
));
2025 printf (" slot %d of %s was %s adding override to %s\n", decl
->slot
, full_name
, mono_method_full_name (prev_impl
, 1), mono_method_full_name (impl
, 1));
2030 #endif /* FEATURE_COVARIANT_RETURNS */
2032 if (mono_security_core_clr_enabled ())
2033 mono_security_core_clr_check_override (klass
, impl
, decl
);
2037 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER OVERRIDING NON-INTERFACE METHODS", FALSE
));
2039 #ifdef FEATURE_COVARIANT_RETURNS
2041 * for each vtable slot that has one of the methods from klass that has the is_covariant_override_impl bit set,
2042 * check that it is subsumed by the methods in each ancestor class.
2044 * This check has to be done after both implicit and explicit non-interface method overrides are applied to the
2045 * vtable. If it's done inline earlier, we could erroneously check an implicit override that should actually be
2046 * ignored (because a more specific explicit override is applied).
2048 if (!check_vtable_covariant_override_impls (klass
, vtable
, cur_slot
))
2053 * If a method occupies more than one place in the vtable, and it is
2054 * overriden, then change the other occurrences too.
2059 for (i
= 0; i
< max_vtsize
; ++i
)
2061 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i
, mono_method_full_name (vtable
[i
], 1), vtable
[i
]));
2063 cm
= (MonoMethod
*)g_hash_table_lookup (override_map
, vtable
[i
]);
2068 g_hash_table_destroy (override_map
);
2069 override_map
= NULL
;
2072 if (override_class_map
)
2073 g_hash_table_destroy (override_class_map
);
2076 handle_dim_conflicts (vtable
, klass
, conflict_map
);
2077 g_hash_table_destroy (conflict_map
);
2080 g_slist_free (virt_methods
);
2081 virt_methods
= NULL
;
2083 g_assert (cur_slot
<= max_vtsize
);
2085 /* Ensure that all vtable slots are filled with concrete instance methods */
2086 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
2087 if (!mono_class_is_abstract (klass
)) {
2088 for (i
= 0; i
< cur_slot
; ++i
) {
2089 if (vtable
[i
] == NULL
|| (vtable
[i
]->flags
& (METHOD_ATTRIBUTE_ABSTRACT
| METHOD_ATTRIBUTE_STATIC
))) {
2090 if (vtable
[i
] != NULL
&& mono_method_get_is_reabstracted (vtable
[i
]))
2092 char *type_name
= mono_type_get_full_name (klass
);
2093 char *method_name
= vtable
[i
] ? mono_method_full_name (vtable
[i
], TRUE
) : g_strdup ("none");
2094 mono_class_set_type_load_failure (klass
, "Type %s has invalid vtable method slot %d with method %s", type_name
, i
, method_name
);
2096 g_free (method_name
);
2098 if (mono_print_vtable
)
2099 print_vtable_layout_result (klass
, vtable
, cur_slot
);
2107 if (mono_class_is_ginst (klass
)) {
2108 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
2110 mono_class_init_internal (gklass
);
2112 klass
->vtable_size
= MAX (gklass
->vtable_size
, cur_slot
);
2114 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
2115 if (klass
->vtable_size
)
2116 g_assert (cur_slot
== klass
->vtable_size
);
2117 klass
->vtable_size
= cur_slot
;
2120 /* Try to share the vtable with our parent. */
2121 if (klass
->parent
&& (klass
->parent
->vtable_size
== klass
->vtable_size
) && (memcmp (klass
->parent
->vtable
, vtable
, sizeof (gpointer
) * klass
->vtable_size
) == 0)) {
2122 mono_memory_barrier ();
2123 klass
->vtable
= klass
->parent
->vtable
;
2125 MonoMethod
**tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * klass
->vtable_size
);
2126 memcpy (tmp
, vtable
, sizeof (gpointer
) * klass
->vtable_size
);
2127 mono_memory_barrier ();
2128 klass
->vtable
= tmp
;
2131 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass
, klass
->vtable
, klass
->vtable_size
, first_non_interface_slot
, "FINALLY", FALSE
));
2132 if (mono_print_vtable
)
2133 print_vtable_layout_result (klass
, vtable
, cur_slot
);
2137 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass
));
2142 char *name
= mono_type_get_full_name (klass
);
2144 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed due to: %s", name
, mono_error_get_message (error
));
2146 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed", name
);
2147 mono_error_cleanup (error
);
2149 if (mono_print_vtable
)
2150 print_vtable_layout_result (klass
, vtable
, cur_slot
);
2155 g_hash_table_destroy (override_map
);
2157 g_slist_free (virt_methods
);