Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / metadata / class-setup-vtable.c
blob486fed9f60c28362b89520658b5e33bda700eb51
1 /**
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.
9 */
10 #include <config.h>
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
24 #endif
26 #ifdef ENABLE_NETCORE
27 #define FEATURE_COVARIANT_RETURNS
28 #endif
30 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
32 static void
33 print_implemented_interfaces (MonoClass *klass)
35 char *name;
36 ERROR_DECL (error);
37 GPtrArray *ifaces = NULL;
38 int i;
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);
43 g_free (name);
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]),
51 ic_name);
52 g_free (ic_name);
54 printf ("Interface flags: ");
55 for (i = 0; i <= klass->max_interface_id; i++)
56 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
57 printf ("(%d,T)", i);
58 else
59 printf ("(%d,F)", i);
60 printf ("\n");
61 printf ("Dump interface flags:");
62 #ifdef COMPRESSED_INTERFACE_BITMAP
64 const uint8_t* p = klass->interface_bitmap;
65 i = klass->max_interface_id;
66 while (i > 0) {
67 printf (" %d x 00 %02X", p [0], p [1]);
68 i -= p [0] * 8;
69 i -= 8;
72 #else
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]);
75 #endif
76 printf ("\n");
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);
80 if (!is_ok (error)) {
81 printf (" Type failed due to %s\n", mono_error_get_message (error));
82 mono_error_cleanup (error);
83 } else if (ifaces) {
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,
88 ic->interface_id,
89 mono_class_interface_offset (klass, ic),
90 mono_class_get_method_count (ic),
91 ic->name_space,
92 ic->name );
94 g_ptr_array_free (ifaces, TRUE);
96 ancestor_level ++;
97 klass = klass->parent;
101 static mono_bool
102 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
104 int i;
105 for (i = 0; i < num_ifaces; ++i) {
106 if (interfaces_full [i] && interfaces_full [i]->interface_id == ic->interface_id) {
107 if (!force_set)
108 return TRUE;
109 interface_offsets_full [i] = offset;
110 return FALSE;
112 if (interfaces_full [i])
113 continue;
114 interfaces_full [i] = ic;
115 interface_offsets_full [i] = offset;
116 break;
118 return FALSE;
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)
132 ERROR_DECL (error);
133 MonoClass *k, *ic;
134 int i, j, num_ifaces;
135 guint32 max_iid;
136 MonoClass **interfaces_full = NULL;
137 int *interface_offsets_full = NULL;
138 GPtrArray *ifaces;
139 GPtrArray **ifaces_array = NULL;
140 int interface_offsets_count;
141 max_iid = 0;
142 num_ifaces = interface_offsets_count = 0;
144 mono_loader_lock ();
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);
155 cur_slot = 0;
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);
162 g_free (name);
163 cur_slot = -1;
164 goto end;
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);
173 if (count == -1) {
174 char *name = mono_type_get_full_name (inflated);
175 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
176 g_free (name);
177 cur_slot = -1;
178 goto end;
181 cur_slot = MAX (cur_slot, interface_offsets_full [i] + count);
182 max_iid = MAX (max_iid, inflated->interface_id);
185 goto publish;
187 /* compute maximum number of slots and maximum interface id */
188 max_iid = 0;
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];
193 g_assert (k);
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));
209 g_free (name);
210 mono_error_cleanup (error);
211 cur_slot = -1;
212 goto end;
214 if (ifaces) {
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)) {
226 num_ifaces++;
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];
243 if (ifaces) {
244 for (i = 0; i < ifaces->len; ++i) {
245 int io;
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];
262 if (ifaces) {
263 for (i = 0; i < ifaces->len; ++i) {
264 int count;
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))
267 continue;
268 count = mono_class_setup_count_virtual_methods (ic);
269 if (count == -1) {
270 char *name = mono_type_get_full_name (ic);
271 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
272 g_free (name);
273 cur_slot = -1;
274 goto end;
276 cur_slot += count;
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 ++;
288 publish:
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) {
300 if (!overwrite)
301 g_assert (klass->interface_offsets_count == interface_offsets_count);
302 } else {
303 uint8_t *bitmap;
304 int bsize;
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);
311 #else
312 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
313 #endif
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);
324 g_free (bitmap);
325 #else
326 klass->interface_bitmap = bitmap;
327 #endif
329 end:
330 mono_loader_unlock ();
332 g_free (interfaces_full);
333 g_free (interface_offsets_full);
334 if (ifaces_array) {
335 for (i = 0; i < klass->idepth; i++) {
336 ifaces = ifaces_array [i];
337 if (ifaces)
338 g_ptr_array_free (ifaces, TRUE);
340 g_free (ifaces_array);
343 //printf ("JUST DONE: ");
344 //print_implemented_interfaces (klass);
346 return cur_slot;
350 * Setup interface offsets for interfaces.
351 * Initializes:
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.
361 void
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; \
382 stmt;\
383 } while (0)
384 #else
385 #define DEBUG_INTERFACE_VTABLE(stmt)
386 #endif
388 #if TRACE_INTERFACE_VTABLE_CODE
389 #define TRACE_INTERFACE_VTABLE(stmt) do {\
390 if (!(VTABLE_SELECTOR)) break; \
391 stmt;\
392 } while (0)
393 #else
394 #define TRACE_INTERFACE_VTABLE(stmt)
395 #endif
397 #if VERIFY_INTERFACE_VTABLE_CODE
398 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
399 if (!(VTABLE_SELECTOR)) break; \
400 stmt;\
401 } while (0)
402 #else
403 #define VERIFY_INTERFACE_VTABLE(stmt)
404 #endif
407 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
408 static char*
409 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
411 int i;
412 char *result;
413 GString *res = g_string_new ("");
415 g_string_append_c (res, '(');
416 for (i = 0; i < sig->param_count; ++i) {
417 if (i > 0)
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);
424 } else {
425 g_string_append (res, "NULL");
427 result = res->str;
428 g_string_free (res, FALSE);
429 return result;
431 static void
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);
436 g_free (im_sig);
437 g_free (cm_sig);
441 #endif
443 static gboolean
444 is_wcf_hack_disabled (void)
446 static char disabled;
447 if (!disabled)
448 disabled = g_hasenv ("MONO_DISABLE_WCF_HACK") ? 1 : 2;
449 return disabled == 1;
452 static gboolean
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]"));
459 return FALSE;
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]"));
465 return FALSE;
467 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
468 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
469 return FALSE;
471 } else {
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");
479 return FALSE;
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 ("]"));
486 return FALSE;
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);
497 g_free (body_name);
498 g_free (decl_name);
499 return FALSE;
502 return TRUE;
503 } else {
504 MonoClass *ic = im->klass;
505 const char *ic_name_space = ic->name_space;
506 const char *ic_name = ic->name;
507 char *subname;
509 if (! require_newslot) {
510 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
511 return FALSE;
513 if (cm->klass->rank == 0) {
514 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
515 return FALSE;
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");
521 return FALSE;
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 ("]"));
528 return FALSE;
530 if (mono_class_get_image (ic) != mono_defaults.corlib) {
531 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
532 return FALSE;
534 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
535 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
536 return FALSE;
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]"));
540 return FALSE;
543 subname = (char*)strstr (cm->name, ic_name_space);
544 if (subname != cm->name) {
545 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
546 return FALSE;
548 subname += strlen (ic_name_space);
549 if (subname [0] != '.') {
550 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
551 return FALSE;
553 subname ++;
554 if (strstr (subname, ic_name) != subname) {
555 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
556 return FALSE;
558 subname += strlen (ic_name);
559 if (subname [0] != '.') {
560 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
561 return FALSE;
563 subname ++;
564 if (strcmp (subname, im->name) != 0) {
565 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
566 return FALSE;
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);
578 g_free (body_name);
579 g_free (decl_name);
580 return FALSE;
583 return TRUE;
587 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
588 static void
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);
601 static void
602 print_overrides (GHashTable *override_map, const char *message)
604 if (override_map) {
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);
608 } else {
609 printf ("Override map \"%s\" EMPTY.\n", message);
613 static void
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));
617 int i;
618 int parent_size;
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);
627 if (klass->parent) {
628 parent_size = klass->parent->vtable_size;
629 } else {
630 parent_size = 0;
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);
638 g_free (cm_name);
641 g_free (full_name);
643 #endif
645 #if VERIFY_INTERFACE_VTABLE_CODE
646 static int
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;
654 return method->slot;
657 static void
658 mono_class_verify_vtable (MonoClass *klass)
660 int i, count;
661 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
663 printf ("*** Verifying VTable of class '%s' \n", full_name);
664 g_free (full_name);
665 full_name = NULL;
667 if (!klass->methods)
668 return;
670 count = mono_class_get_method_count (klass);
671 for (i = 0; i < count; ++i) {
672 MonoMethod *cm = klass->methods [i];
673 int slot;
675 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
676 continue;
678 g_free (full_name);
679 full_name = mono_method_full_name (cm, TRUE);
681 slot = mono_method_try_get_vtable_index (cm);
682 if (slot >= 0) {
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);
685 continue;
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);
691 g_free (other_name);
693 } else
694 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
696 g_free (full_name);
698 #endif
700 static MonoMethod*
701 mono_method_get_method_definition (MonoMethod *method)
703 while (method->is_inflated)
704 method = ((MonoMethodInflated*)method)->declaring;
705 return method;
708 static gboolean
709 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
711 int i;
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");
719 return FALSE;
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");
725 else
726 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
727 return FALSE;
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");
733 else
734 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
735 return FALSE;
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");
740 return FALSE;
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);
750 g_free (body_name);
751 g_free (decl_name);
752 return FALSE;
755 return TRUE;
758 /*Checks if @klass has @parent as one of it's parents type gtd
760 * For example:
761 * Foo<T>
762 * Bar<T> : Foo<Bar<Bar<T>>>
765 static gboolean
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;
777 gboolean
778 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
780 MonoGenericInst *ginst;
781 int i;
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"))
790 return FALSE;
792 ginst = mono_class_get_generic_class (klass)->context.class_inst;
793 for (i = 0; i < ginst->type_argc; ++i) {
794 MonoClass *arg;
795 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
796 continue;
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))
800 continue;
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);
803 return FALSE;
806 return TRUE;
810 * mono_class_setup_vtable:
812 * Creates the generic vtable of CLASS.
813 * Initializes the following fields in MonoClass:
814 * - vtable
815 * - vtable_size
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.
822 void
823 mono_class_setup_vtable (MonoClass *klass)
825 mono_class_setup_vtable_full (klass, NULL);
828 static void
829 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
831 ERROR_DECL (error);
832 MonoMethod **overrides = NULL;
833 MonoGenericContext *context;
834 guint32 type_token;
835 int onum = 0;
837 if (klass->vtable)
838 return;
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);
843 return;
846 if (mono_class_has_failure (klass))
847 return;
849 if (g_list_find (in_setup, klass))
850 return;
852 mono_loader_lock ();
854 if (klass->vtable) {
855 mono_loader_unlock ();
856 return;
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);
866 return;
869 context = mono_class_get_context (klass);
870 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
871 } else {
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));
884 goto done;
886 } else {
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));
892 goto done;
896 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
898 done:
899 g_free (overrides);
900 mono_error_cleanup (error);
902 mono_loader_unlock ();
903 g_list_remove (in_setup, klass);
905 return;
908 gboolean
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)));
914 static int
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)
918 int dslot;
919 dslot = mono_method_get_vtable_slot (decl);
920 if (dslot == -1) {
921 mono_class_set_type_load_failure (klass, "");
922 return FALSE;
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))
929 return TRUE;
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 */
954 if (prev_override) {
955 ERROR_DECL (error);
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.
960 * IFace<T> in:
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);
975 if (!*conflict_map)
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);
987 return TRUE;
990 static void
991 handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflict_map)
993 GHashTableIter iter;
994 MonoMethod *decl;
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)
1010 continue;
1011 if (mono_class_is_assignable_from_internal (m1->klass, m2->klass))
1012 l->data = NULL;
1013 else if (mono_class_is_assignable_from_internal (m2->klass, m1->klass))
1014 l2->data = NULL;
1017 int nentries = 0;
1018 MonoMethod *impl = NULL;
1019 for (l = entries; l; l = l->next) {
1020 if (l->data) {
1021 nentries ++;
1022 impl = (MonoMethod*)l->data;
1025 if (nentries > 1) {
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) {
1032 if (l->data)
1033 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
1036 } else {
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));
1059 int i = 0;
1060 for (l = dim_conflicts; l; l = l->next) {
1061 conflicts [i].data = l->data;
1062 conflicts [i].next = &conflicts [i + 1];
1063 i ++;
1065 conflicts [i - 1].next = NULL;
1067 mono_class_set_dim_conflicts (klass, conflicts);
1068 g_slist_free (dim_conflicts);
1072 static void
1073 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
1075 int index, mcount;
1076 char *method_signature;
1077 char *type_name;
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);
1088 g_free (type_name);
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);
1093 g_free (name);
1094 return;
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).
1113 static MonoMethod*
1114 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
1116 // FIXME move state to caller
1117 gboolean static_iter = FALSE;
1119 if (!iter)
1120 return NULL;
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
1125 * klass->methods.
1127 if ((gsize)(*iter) & 1)
1128 static_iter = TRUE;
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)))
1131 static_iter = TRUE;
1133 if (!static_iter) {
1134 MonoMethod** methodptr;
1136 if (!*iter) {
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)
1143 return NULL;
1144 /* start from the first */
1145 methodptr = &klass->methods [0];
1146 } else {
1147 methodptr = (MonoMethod **)*iter;
1148 methodptr++;
1150 if (*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))
1155 break;
1156 methodptr ++;
1158 if (methodptr < &klass->methods [mcount]) {
1159 *iter = methodptr;
1160 return *methodptr;
1161 } else {
1162 return NULL;
1164 } else {
1165 /* Search directly in metadata to avoid calling setup_methods () */
1166 MonoMethod *res = NULL;
1167 int i, start_index;
1169 if (!*iter) {
1170 start_index = 0;
1171 } else {
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) {
1178 guint32 flags;
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)
1184 break;
1187 if (i < mcount) {
1188 ERROR_DECL (error);
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);
1194 return res;
1195 } else {
1196 return NULL;
1201 static void
1202 print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot)
1204 int i, icount = 0;
1206 print_implemented_interfaces (klass);
1208 for (i = 0; i <= klass->max_interface_id; i++)
1209 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
1210 icount++;
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) {
1216 MonoMethod *cm;
1218 cm = vtable [i];
1219 if (cm) {
1220 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
1221 mono_method_get_full_name (cm));
1222 } else {
1223 printf (" slot assigned: %03d, <null>\n", i);
1228 if (icount) {
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.
1253 static int
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));
1262 g_free (name);
1263 mono_error_cleanup (error);
1264 return -1;
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);
1271 ifaces = NULL;
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"))
1279 return -1;
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;
1290 ++max_vtsize;
1291 ++*cur_slot;
1293 return max_vtsize;
1297 * LOCKING: this is supposed to be called with the loader lock held.
1299 static void
1300 mono_class_setup_vtable_ginst (MonoClass *klass, GList *in_setup)
1302 ERROR_DECL (error);
1303 int i;
1304 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1305 MonoMethod **tmp;
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"))
1309 return;
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);
1320 g_free (name);
1321 return;
1323 tmp [i] = inflated;
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.
1353 static gboolean
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)
1364 break;
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)) {
1369 if (out_klass)
1370 *out_klass = klass;
1371 return TRUE;
1374 return FALSE;
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>.
1386 static gboolean
1387 is_ok_for_covariant_ret (MonoType *type_impl, MonoType *type_decl)
1389 if (type_impl->byref ^ type_decl->byref)
1390 return FALSE;
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))
1397 return FALSE;
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);
1404 g_free (decl_str);
1405 g_free (impl_str);
1406 } while (0));
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
1412 * returns T */
1413 if (mono_class_is_nullable (class_decl) &&
1414 mono_class_get_nullable_param_internal (class_decl) == class_impl)
1415 return FALSE;
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);
1422 return result;
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.
1439 * class C {
1440 * public virtual C Foo ();
1442 * class B : C {
1443 * public virtual newslot B Foo () {
1444 * .PreserveBaseOverrideAttribute;
1445 * .override C C::Foo ();
1448 * class A : B {
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
1454 static gboolean
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))
1461 return TRUE;
1463 if (!mono_metadata_signature_equal_no_ret (impl_sig, decl_sig))
1464 return FALSE;
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
1487 * equal)
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)
1507 return FALSE;
1509 MonoType *decl_ret;
1510 MonoType *alloc_decl_ret = NULL;
1511 if (!impl_method->is_generic) {
1512 decl_ret = decl_ret_0;
1513 } else {
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)
1523 return FALSE;
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);
1532 if (alloc_decl_ret)
1533 mono_metadata_free_type (alloc_decl_ret);
1534 return result;
1537 static gboolean
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);
1548 const char *msg;
1549 if (!is_ok (local_error)) {
1550 msg = mono_error_get_message (local_error);
1551 } else {
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);
1559 return FALSE;
1561 return TRUE;
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.
1579 * For example:
1581 * class A {
1582 * public virtual A Foo ();
1584 * class B : A {
1585 * public override B Foo (); // covariant return override
1587 * class C : B {
1588 * public override A Foo (); // incorrect
1591 static gboolean
1592 check_vtable_covariant_override_impls (MonoClass *klass, MonoMethod **vtable, int vtable_size)
1594 MonoClass *parent_class = klass->parent;
1595 if (!parent_class)
1596 return TRUE;
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)
1602 continue;
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)
1606 break;
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
1619 * over.
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))
1623 return FALSE;
1624 last_checked_prev_override = prev_impl;
1628 return TRUE;
1630 #endif /* FEATURE_COVARIANT_RETURNS */
1633 * LOCKING: this is supposed to be called with the loader lock held.
1635 void
1636 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
1638 ERROR_DECL (error);
1639 MonoClass *k, *ic;
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;
1645 MonoMethod *cm;
1646 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
1647 int first_non_interface_slot;
1648 #endif
1649 GSList *virt_methods = NULL, *l;
1650 int stelemref_slot = 0;
1652 if (klass->vtable)
1653 return;
1655 if (overrides && !verify_class_overrides (klass, overrides, onum))
1656 return;
1658 max_vtsize = setup_class_vtsize (klass, in_setup, &cur_slot, &stelemref_slot, error);
1659 if (max_vtsize == -1)
1660 return;
1662 cur_slot = mono_class_setup_interface_offsets_internal (klass, cur_slot, TRUE);
1663 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
1664 return;
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);
1671 return;
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);
1682 if (!method->slot)
1683 method->slot = stelemref_slot;
1684 else
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))
1699 goto fail;
1701 MonoMethod **iface_overrides;
1702 int iface_onum;
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))
1715 goto fail;
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))
1726 goto fail;
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
1736 * optimization.
1739 gpointer iter = NULL;
1740 MonoMethod *cm;
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))
1747 goto fail;
1750 // Loop on all implemented interfaces...
1751 for (i = 0; i < klass->interface_offsets_count; i++) {
1752 MonoClass *parent = klass->parent;
1753 int ic_offset;
1754 gboolean interface_is_explicitly_implemented_by_class;
1755 int im_index;
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))
1762 goto fail;
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;
1771 break;
1774 } else {
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)
1786 continue;
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))) {
1791 int cm_index;
1792 MonoMethod *cm;
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? */
1802 if (cm->slot < 0) {
1803 cm->slot = im_slot;
1805 if (conflict_map)
1806 g_hash_table_remove(conflict_map, im);
1807 break;
1809 TRACE_INTERFACE_VTABLE (printf ("\n"));
1810 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
1811 goto fail;
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? */
1826 if (cm->slot < 0) {
1827 cm->slot = im_slot;
1829 break;
1831 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
1832 goto fail;
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;
1843 } else {
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++) {
1857 int ic_offset;
1858 int im_index;
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)
1869 continue;
1870 if (mono_method_get_is_reabstracted (im))
1871 continue;
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);
1877 goto fail;
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)) {
1891 int slot = -1;
1892 for (k = klass->parent; k ; k = k->parent) {
1893 gpointer k_iter;
1894 MonoMethod *m1;
1896 k_iter = NULL;
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? */
1904 goto fail;
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);
1913 if (slot == -1)
1914 goto fail;
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);
1928 g_free (body_name);
1929 g_free (decl_name);
1930 goto fail;
1933 g_assert (cm->slot < max_vtsize);
1934 if (!override_map)
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);
1940 break;
1943 if (mono_class_has_failure (k))
1944 goto fail;
1946 if (slot >= 0)
1947 break;
1949 if (slot >= 0)
1950 cm->slot = slot;
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)
1955 cm->slot = -1;
1957 if (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];
1972 #endif
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. */
1977 if (!impl_newslot)
1978 impl->slot = decl->slot;
1979 #endif
1980 if (!override_map)
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) ||
1991 (klass->parent &&
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));
2005 } while (0));
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)
2020 break;
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));
2026 g_free (full_name);
2027 } while (0));
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))
2049 goto fail;
2050 #endif
2053 * If a method occupies more than one place in the vtable, and it is
2054 * overriden, then change the other occurrences too.
2056 if (override_map) {
2057 MonoMethod *cm;
2059 for (i = 0; i < max_vtsize; ++i)
2060 if (vtable [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]);
2064 if (cm)
2065 vtable [i] = cm;
2068 g_hash_table_destroy (override_map);
2069 override_map = NULL;
2072 if (override_class_map)
2073 g_hash_table_destroy (override_class_map);
2075 if (conflict_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]))
2091 continue;
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);
2095 g_free (type_name);
2096 g_free (method_name);
2098 if (mono_print_vtable)
2099 print_vtable_layout_result (klass, vtable, cur_slot);
2101 g_free (vtable);
2102 return;
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);
2113 } else {
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;
2124 } else {
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);
2135 g_free (vtable);
2137 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
2138 return;
2140 fail:
2142 char *name = mono_type_get_full_name (klass);
2143 if (!is_ok (error))
2144 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (error));
2145 else
2146 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
2147 mono_error_cleanup (error);
2148 g_free (name);
2149 if (mono_print_vtable)
2150 print_vtable_layout_result (klass, vtable, cur_slot);
2153 g_free (vtable);
2154 if (override_map)
2155 g_hash_table_destroy (override_map);
2156 if (virt_methods)
2157 g_slist_free (virt_methods);