[merp] Remove dead code (#20043)
[mono-project.git] / mono / metadata / class-init.c
blob6c3664f2c8cb26e6eaab936687e1c10afddf5b09
1 /**
2 * \file MonoClass construction and initialization
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-internals.h>
13 #include <mono/metadata/custom-attrs-internals.h>
14 #include <mono/metadata/debug-helpers.h>
15 #include <mono/metadata/exception-internals.h>
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/metadata/object-internals.h>
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/metadata/security-core-clr.h>
20 #include <mono/metadata/security-manager.h>
21 #include <mono/metadata/verify-internals.h>
22 #include <mono/metadata/abi-details.h>
23 #include <mono/utils/checked-build.h>
24 #include <mono/utils/mono-counters.h>
25 #include <mono/utils/mono-error-internals.h>
26 #include <mono/utils/mono-logger-internals.h>
27 #include <mono/utils/mono-memory-model.h>
28 #include <mono/utils/unlocked.h>
29 #ifdef MONO_CLASS_DEF_PRIVATE
30 /* Class initialization gets to see the fields of MonoClass */
31 #define REALLY_INCLUDE_CLASS_DEF 1
32 #include <mono/metadata/class-private-definition.h>
33 #undef REALLY_INCLUDE_CLASS_DEF
34 #endif
37 gboolean mono_print_vtable = FALSE;
38 gboolean mono_align_small_structs = FALSE;
39 #ifdef ENABLE_NETCORE
40 /* Set by the EE */
41 gint32 mono_simd_register_size;
42 #endif
44 /* Statistics */
45 static gint32 classes_size;
46 static gint32 inflated_classes_size;
47 gint32 mono_inflated_methods_size;
48 static gint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
50 /* Low level lock which protects data structures in this module */
51 static mono_mutex_t classes_mutex;
53 static gboolean class_kind_may_contain_generic_instances (MonoTypeKind kind);
54 static int setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite);
55 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
56 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd);
57 static int generic_array_methods (MonoClass *klass);
58 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
59 static gboolean class_has_isbyreflike_attribute (MonoClass *klass);
60 static void mono_class_setup_interface_id_internal (MonoClass *klass);
62 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
63 static MonoNativeTlsKey setup_fields_tls_id;
65 static MonoNativeTlsKey init_pending_tls_id;
67 static void
68 classes_lock (void)
70 mono_locks_os_acquire (&classes_mutex, ClassesLock);
73 static void
74 classes_unlock (void)
76 mono_locks_os_release (&classes_mutex, ClassesLock);
80 We use gclass recording to allow recursive system f types to be referenced by a parent.
82 Given the following type hierarchy:
84 class TextBox : TextBoxBase<TextBox> {}
85 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
86 class TextInput<T> : Input<T> where T: TextInput<T> {}
87 class Input<T> {}
89 The runtime tries to load TextBoxBase<>.
90 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
91 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
92 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
94 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
95 at this point, iow, both are registered in the type map and both and a NULL parent. This means
96 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
98 To fix that what we do is to record all generic instantes created while resolving the parent of
99 any generic type definition and, after resolved, correct the parent field if needed.
102 static int record_gclass_instantiation;
103 static GSList *gclass_recorded_list;
104 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
107 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
109 static void
110 enable_gclass_recording (void)
112 ++record_gclass_instantiation;
116 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
118 static void
119 disable_gclass_recording (gclass_record_func func, void *user_data)
121 GSList **head = &gclass_recorded_list;
123 g_assert (record_gclass_instantiation > 0);
124 --record_gclass_instantiation;
126 while (*head) {
127 GSList *node = *head;
128 if (func ((MonoClass*)node->data, user_data)) {
129 *head = node->next;
130 g_slist_free_1 (node);
131 } else {
132 head = &node->next;
136 /* We automatically discard all recorded gclasses when disabled. */
137 if (!record_gclass_instantiation && gclass_recorded_list) {
138 g_slist_free (gclass_recorded_list);
139 gclass_recorded_list = NULL;
143 #define mono_class_new0(klass,struct_type, n_structs) \
144 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
147 * mono_class_setup_basic_field_info:
148 * \param class The class to initialize
150 * Initializes the following fields in MonoClass:
151 * * klass->fields (only field->parent and field->name)
152 * * klass->field.count
153 * * klass->first_field_idx
154 * LOCKING: Acquires the loader lock
156 void
157 mono_class_setup_basic_field_info (MonoClass *klass)
159 MonoGenericClass *gklass;
160 MonoClassField *field;
161 MonoClassField *fields;
162 MonoClass *gtd;
163 MonoImage *image;
164 int i, top;
166 if (klass->fields)
167 return;
169 gklass = mono_class_try_get_generic_class (klass);
170 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
171 image = klass->image;
174 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
176 * This happens when a generic instance of an unfinished generic typebuilder
177 * is used as an element type for creating an array type. We can't initialize
178 * the fields of this class using the fields of gklass, since gklass is not
179 * finished yet, fields could be added to it later.
181 return;
184 if (gtd) {
185 mono_class_setup_basic_field_info (gtd);
187 mono_loader_lock ();
188 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
189 mono_loader_unlock ();
192 top = mono_class_get_field_count (klass);
194 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
197 * Fetch all the field information.
199 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
200 for (i = 0; i < top; i++) {
201 field = &fields [i];
202 field->parent = klass;
204 if (gtd) {
205 field->name = mono_field_get_name (&gtd->fields [i]);
206 } else {
207 int idx = first_field_idx + i;
208 /* first_field_idx and idx points into the fieldptr table */
209 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
210 /* The name is needed for fieldrefs */
211 field->name = mono_metadata_string_heap (image, name_idx);
215 mono_memory_barrier ();
217 mono_loader_lock ();
218 if (!klass->fields)
219 klass->fields = fields;
220 mono_loader_unlock ();
224 * mono_class_setup_fields:
225 * \p klass The class to initialize
227 * Initializes klass->fields, computes class layout and sizes.
228 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
229 * Sets the following fields in \p klass:
230 * - all the fields initialized by mono_class_init_sizes ()
231 * - element_class/cast_class (for enums)
232 * - sizes:element_size (for arrays)
233 * - field->type/offset for all fields
234 * - fields_inited
236 * LOCKING: Acquires the loader lock.
238 void
239 mono_class_setup_fields (MonoClass *klass)
241 ERROR_DECL (error);
242 MonoImage *m = klass->image;
243 int top;
244 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
245 int i;
246 guint32 real_size = 0;
247 guint32 packing_size = 0;
248 int instance_size;
249 gboolean explicit_size;
250 MonoClassField *field;
251 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
252 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
254 if (klass->fields_inited)
255 return;
257 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
259 * This happens when a generic instance of an unfinished generic typebuilder
260 * is used as an element type for creating an array type. We can't initialize
261 * the fields of this class using the fields of gklass, since gklass is not
262 * finished yet, fields could be added to it later.
264 return;
267 mono_class_setup_basic_field_info (klass);
268 top = mono_class_get_field_count (klass);
270 if (gtd) {
271 mono_class_setup_fields (gtd);
272 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
273 return;
276 instance_size = 0;
277 if (klass->parent) {
278 /* For generic instances, klass->parent might not have been initialized */
279 mono_class_init_internal (klass->parent);
280 mono_class_setup_fields (klass->parent);
281 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
282 return;
283 instance_size = klass->parent->instance_size;
284 } else {
285 instance_size = MONO_ABI_SIZEOF (MonoObject);
288 /* Get the real size */
289 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
290 if (explicit_size)
291 instance_size += real_size;
293 #ifdef ENABLE_NETCORE
294 if (mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System.Numerics") && !strcmp (klass->name, "Register")) {
295 if (mono_simd_register_size)
296 instance_size += mono_simd_register_size;
298 #endif
301 * This function can recursively call itself.
302 * Prevent infinite recursion by using a list in TLS.
304 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
305 if (g_slist_find (init_list, klass))
306 return;
307 init_list = g_slist_prepend (init_list, klass);
308 mono_native_tls_set_value (setup_fields_tls_id, init_list);
311 * Fetch all the field information.
313 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
314 for (i = 0; i < top; i++) {
315 int idx = first_field_idx + i;
316 field = &klass->fields [i];
318 if (!field->type) {
319 mono_field_resolve_type (field, error);
320 if (!is_ok (error)) {
321 /*mono_field_resolve_type already failed class*/
322 mono_error_cleanup (error);
323 break;
325 if (!field->type)
326 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
327 g_assert (field->type);
330 if (!mono_type_get_underlying_type (field->type)) {
331 mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
332 break;
335 if (mono_field_is_deleted (field))
336 continue;
337 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
338 guint32 uoffset;
339 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
340 int offset = uoffset;
342 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
343 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
344 break;
346 if (offset < -1) { /*-1 is used to encode special static fields */
347 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
348 break;
350 if (mono_class_is_gtd (klass)) {
351 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
352 break;
355 if (mono_type_has_exceptions (field->type)) {
356 char *class_name = mono_type_get_full_name (klass);
357 char *type_name = mono_type_full_name (field->type);
359 mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
360 g_free (class_name);
361 g_free (type_name);
362 break;
364 /* The def_value of fields is compute lazily during vtable creation */
367 if (!mono_class_has_failure (klass)) {
368 mono_loader_lock ();
369 mono_class_layout_fields (klass, instance_size, packing_size, real_size, FALSE);
370 mono_loader_unlock ();
373 init_list = g_slist_remove (init_list, klass);
374 mono_native_tls_set_value (setup_fields_tls_id, init_list);
377 static gboolean
378 discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
380 return mono_class_get_generic_class (gclass)->container_class == user_data;
383 static gboolean
384 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
386 MonoClass *gtd = (MonoClass*)user_data;
387 /* Only try to fix generic instances of @gtd */
388 if (mono_class_get_generic_class (gclass)->container_class != gtd)
389 return FALSE;
391 /* Check if the generic instance has no parent. */
392 if (gtd->parent && !gclass->parent)
393 mono_generic_class_setup_parent (gclass, gtd);
395 return TRUE;
398 static void
399 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
401 mono_class_set_type_load_failure (klass, "%s", msg);
402 mono_error_set_type_load_class (error, klass, "%s", msg);
406 * mono_class_create_from_typedef:
407 * \param image: image where the token is valid
408 * \param type_token: typedef token
409 * \param error: used to return any error found while creating the type
411 * Create the MonoClass* representing the specified type token.
412 * \p type_token must be a TypeDef token.
414 * FIXME: don't return NULL on failure, just let the caller figure it out.
416 MonoClass *
417 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
419 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
420 MonoClass *klass, *parent = NULL;
421 guint32 cols [MONO_TYPEDEF_SIZE];
422 guint32 cols_next [MONO_TYPEDEF_SIZE];
423 guint tidx = mono_metadata_token_index (type_token);
424 MonoGenericContext *context = NULL;
425 const char *name, *nspace;
426 guint icount = 0;
427 MonoClass **interfaces;
428 guint32 field_last, method_last;
429 guint32 nesting_tokeen;
431 error_init (error);
433 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
434 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
435 return NULL;
438 mono_loader_lock ();
440 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
441 mono_loader_unlock ();
442 return klass;
445 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
447 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
448 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
450 if (mono_metadata_has_generic_params (image, type_token)) {
451 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassGtd));
452 klass->class_kind = MONO_CLASS_GTD;
453 UnlockedAdd (&classes_size, sizeof (MonoClassGtd));
454 ++class_gtd_count;
455 } else {
456 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassDef));
457 klass->class_kind = MONO_CLASS_DEF;
458 UnlockedAdd (&classes_size, sizeof (MonoClassDef));
459 ++class_def_count;
462 klass->name = name;
463 klass->name_space = nspace;
465 MONO_PROFILER_RAISE (class_loading, (klass));
467 klass->image = image;
468 klass->type_token = type_token;
469 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
471 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
474 * Check whether we're a generic type definition.
476 if (mono_class_is_gtd (klass)) {
477 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL, klass);
478 context = &generic_container->context;
479 mono_class_set_generic_container (klass, generic_container);
480 MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
481 canonical_inst->type = MONO_TYPE_GENERICINST;
482 canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
483 enable_gclass_recording ();
486 if (cols [MONO_TYPEDEF_EXTENDS]) {
487 MonoClass *tmp;
488 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
490 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
491 /*WARNING: this must satisfy mono_metadata_type_hash*/
492 klass->this_arg.byref = 1;
493 klass->this_arg.data.klass = klass;
494 klass->this_arg.type = MONO_TYPE_CLASS;
495 klass->_byval_arg.data.klass = klass;
496 klass->_byval_arg.type = MONO_TYPE_CLASS;
498 parent = mono_class_get_checked (image, parent_token, error);
499 if (parent && context) /* Always inflate */
500 parent = mono_class_inflate_generic_class_checked (parent, context, error);
502 if (parent == NULL) {
503 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
504 goto parent_failure;
507 for (tmp = parent; tmp; tmp = tmp->parent) {
508 if (tmp == klass) {
509 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
510 goto parent_failure;
512 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
513 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
514 goto parent_failure;
519 mono_class_setup_parent (klass, parent);
521 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
522 mono_class_setup_mono_type (klass);
524 if (mono_class_is_gtd (klass))
525 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
528 * This might access klass->_byval_arg for recursion generated by generic constraints,
529 * so it has to come after setup_mono_type ().
531 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
532 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
533 if (!is_ok (error)) {
534 /*FIXME implement a mono_class_set_failure_from_mono_error */
535 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
536 mono_loader_unlock ();
537 MONO_PROFILER_RAISE (class_failed, (klass));
538 return NULL;
542 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
543 klass->unicode = 1;
545 #ifdef HOST_WIN32
546 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
547 klass->unicode = 1;
548 #endif
550 klass->cast_class = klass->element_class = klass;
551 if (mono_is_corlib_image (klass->image)) {
552 switch (m_class_get_byval_arg (klass)->type) {
553 case MONO_TYPE_I1:
554 if (mono_defaults.byte_class)
555 klass->cast_class = mono_defaults.byte_class;
556 break;
557 case MONO_TYPE_U1:
558 if (mono_defaults.sbyte_class)
559 mono_defaults.sbyte_class = klass;
560 break;
561 case MONO_TYPE_I2:
562 if (mono_defaults.uint16_class)
563 mono_defaults.uint16_class = klass;
564 break;
565 case MONO_TYPE_U2:
566 if (mono_defaults.int16_class)
567 klass->cast_class = mono_defaults.int16_class;
568 break;
569 case MONO_TYPE_I4:
570 if (mono_defaults.uint32_class)
571 mono_defaults.uint32_class = klass;
572 break;
573 case MONO_TYPE_U4:
574 if (mono_defaults.int32_class)
575 klass->cast_class = mono_defaults.int32_class;
576 break;
577 case MONO_TYPE_I8:
578 if (mono_defaults.uint64_class)
579 mono_defaults.uint64_class = klass;
580 break;
581 case MONO_TYPE_U8:
582 if (mono_defaults.int64_class)
583 klass->cast_class = mono_defaults.int64_class;
584 break;
585 default:
586 break;
590 if (!klass->enumtype) {
591 if (!mono_metadata_interfaces_from_typedef_full (
592 image, type_token, &interfaces, &icount, FALSE, context, error)){
594 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
595 mono_loader_unlock ();
596 MONO_PROFILER_RAISE (class_failed, (klass));
597 return NULL;
600 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
601 g_assert(icount <= 65535);
603 klass->interfaces = interfaces;
604 klass->interface_count = icount;
605 klass->interfaces_inited = 1;
608 /*g_print ("Load class %s\n", name);*/
611 * Compute the field and method lists
613 int first_field_idx;
614 first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
615 mono_class_set_first_field_idx (klass, first_field_idx);
616 int first_method_idx;
617 first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
618 mono_class_set_first_method_idx (klass, first_method_idx);
620 if (tt->rows > tidx){
621 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
622 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
623 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
624 } else {
625 field_last = image->tables [MONO_TABLE_FIELD].rows;
626 method_last = image->tables [MONO_TABLE_METHOD].rows;
629 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
630 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
631 mono_class_set_field_count (klass, field_last - first_field_idx);
632 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
633 mono_class_set_method_count (klass, method_last - first_method_idx);
635 /* reserve space to store vector pointer in arrays */
636 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
637 klass->instance_size += 2 * TARGET_SIZEOF_VOID_P;
638 #ifndef ENABLE_NETCORE
639 g_assert (mono_class_get_field_count (klass) == 0);
640 #else
641 /* TODO: check that array has 0 non-const fields */
642 #endif
645 if (klass->enumtype) {
646 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
647 if (!enum_basetype) {
648 /*set it to a default value as the whole runtime can't handle this to be null*/
649 klass->cast_class = klass->element_class = mono_defaults.int32_class;
650 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
651 mono_loader_unlock ();
652 MONO_PROFILER_RAISE (class_failed, (klass));
653 return NULL;
655 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (enum_basetype);
659 * If we're a generic type definition, load the constraints.
660 * We must do this after the class has been constructed to make certain recursive scenarios
661 * work.
663 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
664 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
665 mono_loader_unlock ();
666 MONO_PROFILER_RAISE (class_failed, (klass));
667 return NULL;
670 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
671 if (!strncmp (name, "Vector", 6))
672 klass->simd_type = !strcmp (name + 6, "2d") || !strcmp (name + 6, "2ul") || !strcmp (name + 6, "2l") || !strcmp (name + 6, "4f") || !strcmp (name + 6, "4ui") || !strcmp (name + 6, "4i") || !strcmp (name + 6, "8s") || !strcmp (name + 6, "8us") || !strcmp (name + 6, "16b") || !strcmp (name + 6, "16sb");
673 } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
674 /* The JIT can't handle SIMD types with != 16 size yet */
675 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
676 if (!strcmp (name, "Vector4"))
677 klass->simd_type = 1;
680 // compute is_byreflike
681 if (m_class_is_valuetype (klass))
682 if (class_has_isbyreflike_attribute (klass))
683 klass->is_byreflike = 1;
685 mono_loader_unlock ();
687 MONO_PROFILER_RAISE (class_loaded, (klass));
689 return klass;
691 parent_failure:
692 if (mono_class_is_gtd (klass))
693 disable_gclass_recording (discard_gclass_due_to_failure, klass);
695 mono_class_setup_mono_type (klass);
696 mono_loader_unlock ();
697 MONO_PROFILER_RAISE (class_failed, (klass));
698 return NULL;
702 static void
703 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
705 if (gtd->parent) {
706 ERROR_DECL (error);
707 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
709 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), error);
710 if (!is_ok (error)) {
711 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
712 klass->parent = mono_defaults.object_class;
713 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error));
714 mono_error_cleanup (error);
717 mono_loader_lock ();
718 if (klass->parent)
719 mono_class_setup_parent (klass, klass->parent);
721 if (klass->enumtype) {
722 klass->cast_class = gtd->cast_class;
723 klass->element_class = gtd->element_class;
725 mono_loader_unlock ();
728 struct HasIsByrefLikeUD {
729 gboolean has_isbyreflike;
732 static gboolean
733 has_isbyreflike_attribute_func (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
735 struct HasIsByrefLikeUD *has_isbyreflike = (struct HasIsByrefLikeUD *)user_data;
736 if (!strcmp (name, "IsByRefLikeAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
737 has_isbyreflike->has_isbyreflike = TRUE;
738 return TRUE;
740 return FALSE;
743 static gboolean
744 class_has_isbyreflike_attribute (MonoClass *klass)
746 struct HasIsByrefLikeUD has_isbyreflike;
747 has_isbyreflike.has_isbyreflike = FALSE;
748 mono_class_metadata_foreach_custom_attr (klass, has_isbyreflike_attribute_func, &has_isbyreflike);
749 return has_isbyreflike.has_isbyreflike;
753 static gboolean
754 check_valid_generic_inst_arguments (MonoGenericInst *inst, MonoError *error)
756 for (int i = 0; i < inst->type_argc; i++) {
757 if (!mono_type_is_valid_generic_argument (inst->type_argv [i])) {
758 char *type_name = mono_type_full_name (inst->type_argv [i]);
759 mono_error_set_invalid_program (error, "generic type cannot be instantiated with type '%s'", type_name);
760 g_free (type_name);
761 return FALSE;
764 return TRUE;
768 * Create the `MonoClass' for an instantiation of a generic type.
769 * We only do this if we actually need it.
770 * This will sometimes return a GTD due to checking the cached_class.
772 MonoClass*
773 mono_class_create_generic_inst (MonoGenericClass *gclass)
775 MonoClass *klass, *gklass;
777 if (gclass->cached_class)
778 return gclass->cached_class;
780 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
782 gklass = gclass->container_class;
784 if (gklass->nested_in) {
785 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
786 klass->nested_in = gklass->nested_in;
789 klass->name = gklass->name;
790 klass->name_space = gklass->name_space;
792 klass->image = gklass->image;
793 klass->type_token = gklass->type_token;
795 klass->class_kind = MONO_CLASS_GINST;
796 //FIXME add setter
797 ((MonoClassGenericInst*)klass)->generic_class = gclass;
799 klass->_byval_arg.type = MONO_TYPE_GENERICINST;
800 klass->this_arg.type = m_class_get_byval_arg (klass)->type;
801 klass->this_arg.data.generic_class = klass->_byval_arg.data.generic_class = gclass;
802 klass->this_arg.byref = TRUE;
803 klass->enumtype = gklass->enumtype;
804 klass->valuetype = gklass->valuetype;
807 if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
808 g_assert (gclass->context.class_inst);
809 g_assert (gclass->context.class_inst->type_argc > 0);
810 if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
811 klass->simd_type = 1;
813 #ifdef ENABLE_NETCORE
814 if (mono_is_corlib_image (gklass->image) &&
815 (!strcmp (gklass->name, "Vector`1") || !strcmp (gklass->name, "Vector128`1") || !strcmp (gklass->name, "Vector256`1"))) {
816 MonoType *etype = gclass->context.class_inst->type_argv [0];
817 if (mono_type_is_primitive (etype) && etype->type != MONO_TYPE_CHAR && etype->type != MONO_TYPE_BOOLEAN)
818 klass->simd_type = 1;
820 #endif
822 klass->is_array_special_interface = gklass->is_array_special_interface;
824 klass->cast_class = klass->element_class = klass;
826 if (m_class_is_valuetype (klass)) {
827 klass->is_byreflike = gklass->is_byreflike;
830 if (gclass->is_dynamic) {
832 * We don't need to do any init workf with unbaked typebuilders. Generic instances created at this point will be later unregistered and/or fixed.
833 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
834 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
836 if (!gklass->wastypebuilder)
837 klass->inited = 1;
839 if (klass->enumtype) {
841 * For enums, gklass->fields might not been set, but instance_size etc. is
842 * already set in mono_reflection_create_internal_class (). For non-enums,
843 * these will be computed normally in mono_class_layout_fields ().
845 klass->instance_size = gklass->instance_size;
846 klass->sizes.class_size = gklass->sizes.class_size;
847 klass->size_inited = 1;
852 ERROR_DECL (error_inst);
853 if (!check_valid_generic_inst_arguments (gclass->context.class_inst, error_inst)) {
854 char *gklass_name = mono_type_get_full_name (gklass);
855 mono_class_set_type_load_failure (klass, "Could not instantiate %s due to %s", gklass_name, mono_error_get_message (error_inst));
856 g_free (gklass_name);
857 mono_error_cleanup (error_inst);
861 mono_loader_lock ();
863 if (gclass->cached_class) {
864 mono_loader_unlock ();
865 return gclass->cached_class;
868 if (record_gclass_instantiation > 0)
869 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
871 if (mono_class_is_nullable (klass))
872 klass->cast_class = klass->element_class = mono_class_get_nullable_param_internal (klass);
874 MONO_PROFILER_RAISE (class_loading, (klass));
876 mono_generic_class_setup_parent (klass, gklass);
878 if (gclass->is_dynamic)
879 mono_class_setup_supertypes (klass);
881 mono_memory_barrier ();
882 gclass->cached_class = klass;
884 MONO_PROFILER_RAISE (class_loaded, (klass));
886 ++class_ginst_count;
887 inflated_classes_size += sizeof (MonoClassGenericInst);
889 mono_loader_unlock ();
891 return klass;
894 static gboolean
895 class_kind_may_contain_generic_instances (MonoTypeKind kind)
897 /* classes of type generic inst may contain generic arguments from other images,
898 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
899 return (kind == MONO_CLASS_GINST || kind == MONO_CLASS_ARRAY || kind == MONO_CLASS_POINTER);
903 * mono_class_create_bounded_array:
904 * \param element_class element class
905 * \param rank the dimension of the array class
906 * \param bounded whenever the array has non-zero bounds
907 * \returns A class object describing the array with element type \p element_type and
908 * dimension \p rank.
910 MonoClass *
911 mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bounded)
913 MonoImage *image;
914 MonoClass *klass, *cached, *k;
915 MonoClass *parent = NULL;
916 GSList *list, *rootlist = NULL;
917 int nsize;
918 char *name;
919 MonoImageSet* image_set;
921 g_assert (rank <= 255);
923 if (rank > 1)
924 /* bounded only matters for one-dimensional arrays */
925 bounded = FALSE;
927 image = eclass->image;
928 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)eclass->class_kind) ? mono_metadata_get_image_set_for_class (eclass) : NULL;
930 /* Check cache */
931 cached = NULL;
932 if (rank == 1 && !bounded) {
933 if (image_set) {
934 mono_image_set_lock (image_set);
935 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
936 mono_image_set_unlock (image_set);
937 } else {
939 * This case is very frequent not just during compilation because of calls
940 * from mono_class_from_mono_type_internal (), mono_array_new (),
941 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
943 mono_os_mutex_lock (&image->szarray_cache_lock);
944 if (!image->szarray_cache)
945 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
946 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
947 mono_os_mutex_unlock (&image->szarray_cache_lock);
949 } else {
950 if (image_set) {
951 mono_image_set_lock (image_set);
952 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
953 for (list = rootlist; list; list = list->next) {
954 k = (MonoClass *)list->data;
955 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
956 cached = k;
957 break;
960 mono_image_set_unlock (image_set);
961 } else {
962 mono_loader_lock ();
963 if (!image->array_cache)
964 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
965 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
966 for (list = rootlist; list; list = list->next) {
967 k = (MonoClass *)list->data;
968 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
969 cached = k;
970 break;
973 mono_loader_unlock ();
976 if (cached)
977 return cached;
979 parent = mono_defaults.array_class;
980 if (!parent->inited)
981 mono_class_init_internal (parent);
983 klass = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
985 klass->image = image;
986 klass->name_space = eclass->name_space;
987 klass->class_kind = MONO_CLASS_ARRAY;
989 nsize = strlen (eclass->name);
990 name = (char *)g_malloc (nsize + 2 + rank + 1);
991 memcpy (name, eclass->name, nsize);
992 name [nsize] = '[';
993 if (rank > 1)
994 memset (name + nsize + 1, ',', rank - 1);
995 if (bounded)
996 name [nsize + rank] = '*';
997 name [nsize + rank + bounded] = ']';
998 name [nsize + rank + bounded + 1] = 0;
999 klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
1000 g_free (name);
1002 klass->type_token = 0;
1003 klass->parent = parent;
1004 klass->instance_size = mono_class_instance_size (klass->parent);
1006 if (m_class_get_byval_arg (eclass)->type == MONO_TYPE_TYPEDBYREF) {
1007 /*Arrays of those two types are invalid.*/
1008 ERROR_DECL (prepared_error);
1009 mono_error_set_invalid_program (prepared_error, "Arrays of System.TypedReference types are invalid.");
1010 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
1011 mono_error_cleanup (prepared_error);
1012 } else if (m_class_is_byreflike (eclass)) {
1013 /* .NET Core throws a type load exception: "Could not create array type 'fullname[]'" */
1014 char *full_name = mono_type_get_full_name (eclass);
1015 mono_class_set_type_load_failure (klass, "Could not create array type '%s[]'", full_name);
1016 g_free (full_name);
1017 } else if (eclass->enumtype && !mono_class_enum_basetype_internal (eclass)) {
1018 guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass);
1019 if (!ref_info_handle || eclass->wastypebuilder) {
1020 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
1021 g_assert (ref_info_handle && !eclass->wastypebuilder);
1023 /* element_size -1 is ok as this is not an instantitable type*/
1024 klass->sizes.element_size = -1;
1025 } else
1026 klass->sizes.element_size = -1;
1028 mono_class_setup_supertypes (klass);
1030 if (mono_class_is_ginst (eclass))
1031 mono_class_init_internal (eclass);
1032 if (!eclass->size_inited)
1033 mono_class_setup_fields (eclass);
1034 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
1035 /*FIXME we fail the array type, but we have to let other fields be set.*/
1037 klass->has_references = MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (eclass)) || m_class_has_references (eclass)? TRUE: FALSE;
1039 klass->rank = rank;
1041 if (eclass->enumtype)
1042 klass->cast_class = eclass->element_class;
1043 else
1044 klass->cast_class = eclass;
1046 switch (m_class_get_byval_arg (m_class_get_cast_class (klass))->type) {
1047 case MONO_TYPE_I1:
1048 klass->cast_class = mono_defaults.byte_class;
1049 break;
1050 case MONO_TYPE_U2:
1051 klass->cast_class = mono_defaults.int16_class;
1052 break;
1053 case MONO_TYPE_U4:
1054 #if TARGET_SIZEOF_VOID_P == 4
1055 case MONO_TYPE_I:
1056 case MONO_TYPE_U:
1057 #endif
1058 klass->cast_class = mono_defaults.int32_class;
1059 break;
1060 case MONO_TYPE_U8:
1061 #if TARGET_SIZEOF_VOID_P == 8
1062 case MONO_TYPE_I:
1063 case MONO_TYPE_U:
1064 #endif
1065 klass->cast_class = mono_defaults.int64_class;
1066 break;
1067 default:
1068 break;
1071 klass->element_class = eclass;
1073 if ((rank > 1) || bounded) {
1074 MonoArrayType *at = image_set ? (MonoArrayType *)mono_image_set_alloc0 (image_set, sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
1075 klass->_byval_arg.type = MONO_TYPE_ARRAY;
1076 klass->_byval_arg.data.array = at;
1077 at->eklass = eclass;
1078 at->rank = rank;
1079 /* FIXME: complete.... */
1080 } else {
1081 klass->_byval_arg.type = MONO_TYPE_SZARRAY;
1082 klass->_byval_arg.data.klass = eclass;
1084 klass->this_arg = klass->_byval_arg;
1085 klass->this_arg.byref = 1;
1087 if (rank > 32) {
1088 ERROR_DECL (prepared_error);
1089 name = mono_type_get_full_name (klass);
1090 mono_error_set_type_load_class (prepared_error, klass, "%s has too many dimensions.", name);
1091 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
1092 mono_error_cleanup (prepared_error);
1093 g_free (name);
1096 mono_loader_lock ();
1098 /* Check cache again */
1099 cached = NULL;
1100 if (rank == 1 && !bounded) {
1101 if (image_set) {
1102 mono_image_set_lock (image_set);
1103 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
1104 mono_image_set_unlock (image_set);
1105 } else {
1106 mono_os_mutex_lock (&image->szarray_cache_lock);
1107 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
1108 mono_os_mutex_unlock (&image->szarray_cache_lock);
1110 } else {
1111 if (image_set) {
1112 mono_image_set_lock (image_set);
1113 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
1114 for (list = rootlist; list; list = list->next) {
1115 k = (MonoClass *)list->data;
1116 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1117 cached = k;
1118 break;
1121 mono_image_set_unlock (image_set);
1122 } else {
1123 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
1124 for (list = rootlist; list; list = list->next) {
1125 k = (MonoClass *)list->data;
1126 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1127 cached = k;
1128 break;
1133 if (cached) {
1134 mono_loader_unlock ();
1135 return cached;
1138 MONO_PROFILER_RAISE (class_loading, (klass));
1140 UnlockedAdd (&classes_size, sizeof (MonoClassArray));
1141 ++class_array_count;
1143 if (rank == 1 && !bounded) {
1144 if (image_set) {
1145 mono_image_set_lock (image_set);
1146 g_hash_table_insert (image_set->szarray_cache, eclass, klass);
1147 mono_image_set_unlock (image_set);
1148 } else {
1149 mono_os_mutex_lock (&image->szarray_cache_lock);
1150 g_hash_table_insert (image->szarray_cache, eclass, klass);
1151 mono_os_mutex_unlock (&image->szarray_cache_lock);
1153 } else {
1154 if (image_set) {
1155 mono_image_set_lock (image_set);
1156 list = g_slist_append (rootlist, klass);
1157 g_hash_table_insert (image_set->array_cache, eclass, list);
1158 mono_image_set_unlock (image_set);
1159 } else {
1160 list = g_slist_append (rootlist, klass);
1161 g_hash_table_insert (image->array_cache, eclass, list);
1165 mono_loader_unlock ();
1167 MONO_PROFILER_RAISE (class_loaded, (klass));
1169 return klass;
1173 * mono_class_create_array:
1174 * \param element_class element class
1175 * \param rank the dimension of the array class
1176 * \returns A class object describing the array with element type \p element_type and
1177 * dimension \p rank.
1179 MonoClass *
1180 mono_class_create_array (MonoClass *eclass, guint32 rank)
1182 return mono_class_create_bounded_array (eclass, rank, FALSE);
1185 // This is called by mono_class_create_generic_parameter when a new class must be created.
1186 static MonoClass*
1187 make_generic_param_class (MonoGenericParam *param)
1189 MonoClass *klass, **ptr;
1190 int count, pos, i, min_align;
1191 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1192 MonoGenericContainer *container = mono_generic_param_owner (param);
1193 g_assert_checked (container);
1195 MonoImage *image = mono_get_image_for_generic_param (param);
1196 gboolean is_mvar = container->is_method;
1197 gboolean is_anonymous = container->is_anonymous;
1199 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
1200 klass->class_kind = MONO_CLASS_GPARAM;
1201 UnlockedAdd (&classes_size, sizeof (MonoClassGenericParam));
1202 UnlockedIncrement (&class_gparam_count);
1204 if (!is_anonymous) {
1205 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
1206 } else {
1207 int n = mono_generic_param_num (param);
1208 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , mono_make_generic_name_string (image, n) );
1211 if (is_anonymous) {
1212 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
1213 } else if (is_mvar) {
1214 MonoMethod *omethod = container->owner.method;
1215 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
1216 } else {
1217 MonoClass *oklass = container->owner.klass;
1218 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
1221 MONO_PROFILER_RAISE (class_loading, (klass));
1223 // Count non-NULL items in pinfo->constraints
1224 count = 0;
1225 if (!is_anonymous)
1226 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
1229 pos = 0;
1230 if ((count > 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo->constraints [0])) {
1231 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
1232 pos++;
1233 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
1234 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
1235 } else {
1236 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
1239 if (count - pos > 0) {
1240 klass->interface_count = count - pos;
1241 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
1242 klass->interfaces_inited = TRUE;
1243 for (i = pos; i < count; i++)
1244 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
1247 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
1249 klass->inited = TRUE;
1250 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
1251 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
1253 MonoTypeEnum t = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
1254 klass->_byval_arg.type = t;
1255 klass->this_arg.type = t;
1256 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
1257 CHECKED_METADATA_WRITE_PTR ( klass->_byval_arg.data.generic_param , param );
1258 klass->this_arg.byref = TRUE;
1260 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1261 klass->sizes.generic_param_token = !is_anonymous ? pinfo->token : 0;
1263 if (param->gshared_constraint) {
1264 MonoClass *constraint_class = mono_class_from_mono_type_internal (param->gshared_constraint);
1265 mono_class_init_sizes (constraint_class);
1266 klass->has_references = m_class_has_references (constraint_class);
1269 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1270 * constrained to, the JIT depends on this.
1272 klass->instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_size (m_class_get_byval_arg (klass), &min_align);
1273 klass->min_align = min_align;
1274 mono_memory_barrier ();
1275 klass->size_inited = 1;
1277 mono_class_setup_supertypes (klass);
1279 if (count - pos > 0) {
1280 mono_class_setup_vtable (klass->parent);
1281 if (mono_class_has_failure (klass->parent))
1282 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
1283 else
1284 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
1287 return klass;
1291 * LOCKING: Acquires the image lock (@image).
1293 MonoClass *
1294 mono_class_create_generic_parameter (MonoGenericParam *param)
1296 MonoImage *image = mono_get_image_for_generic_param (param);
1297 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1298 MonoClass *klass, *klass2;
1300 // If a klass already exists for this object and is cached, return it.
1301 klass = pinfo->pklass;
1303 if (klass)
1304 return klass;
1306 // Create a new klass
1307 klass = make_generic_param_class (param);
1309 // Now we need to cache the klass we created.
1310 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1311 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1312 // and allow our newly-created klass object to just leak.
1313 mono_memory_barrier ();
1315 mono_image_lock (image);
1317 // Here "klass2" refers to the klass potentially created by the other thread.
1318 klass2 = pinfo->pklass;
1320 if (klass2) {
1321 klass = klass2;
1322 } else {
1323 pinfo->pklass = klass;
1325 mono_image_unlock (image);
1327 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1328 if (klass2)
1329 MONO_PROFILER_RAISE (class_failed, (klass2));
1330 else
1331 MONO_PROFILER_RAISE (class_loaded, (klass));
1333 return klass;
1337 * mono_class_create_ptr:
1339 MonoClass *
1340 mono_class_create_ptr (MonoType *type)
1342 MonoClass *result;
1343 MonoClass *el_class;
1344 MonoImage *image;
1345 char *name;
1346 MonoImageSet* image_set;
1348 el_class = mono_class_from_mono_type_internal (type);
1349 image = el_class->image;
1350 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)el_class->class_kind) ? mono_metadata_get_image_set_for_class (el_class) : NULL;
1352 if (image_set) {
1353 mono_image_set_lock (image_set);
1354 if (image_set->ptr_cache) {
1355 if ((result = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1356 mono_image_set_unlock (image_set);
1357 return result;
1360 mono_image_set_unlock (image_set);
1361 } else {
1362 mono_image_lock (image);
1363 if (image->ptr_cache) {
1364 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1365 mono_image_unlock (image);
1366 return result;
1369 mono_image_unlock (image);
1372 result = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
1374 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1375 ++class_pointer_count;
1377 result->parent = NULL; /* no parent for PTR types */
1378 result->name_space = el_class->name_space;
1379 name = g_strdup_printf ("%s*", el_class->name);
1380 result->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
1381 result->class_kind = MONO_CLASS_POINTER;
1382 g_free (name);
1384 MONO_PROFILER_RAISE (class_loading, (result));
1386 result->image = el_class->image;
1387 result->inited = TRUE;
1388 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1389 result->min_align = sizeof (gpointer);
1390 result->cast_class = result->element_class = el_class;
1391 result->blittable = TRUE;
1393 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_PTR;
1394 result->this_arg.data.type = result->_byval_arg.data.type = m_class_get_byval_arg (el_class);
1395 result->this_arg.byref = TRUE;
1397 mono_class_setup_supertypes (result);
1399 if (image_set) {
1400 mono_image_set_lock (image_set);
1401 if (image_set->ptr_cache) {
1402 MonoClass *result2;
1403 if ((result2 = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1404 mono_image_set_unlock (image_set);
1405 MONO_PROFILER_RAISE (class_failed, (result));
1406 return result2;
1409 else {
1410 image_set->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1412 g_hash_table_insert (image_set->ptr_cache, el_class, result);
1413 mono_image_set_unlock (image_set);
1414 } else {
1415 mono_image_lock (image);
1416 if (image->ptr_cache) {
1417 MonoClass *result2;
1418 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1419 mono_image_unlock (image);
1420 MONO_PROFILER_RAISE (class_failed, (result));
1421 return result2;
1423 } else {
1424 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1426 g_hash_table_insert (image->ptr_cache, el_class, result);
1427 mono_image_unlock (image);
1430 MONO_PROFILER_RAISE (class_loaded, (result));
1432 return result;
1435 MonoClass *
1436 mono_class_create_fnptr (MonoMethodSignature *sig)
1438 MonoClass *result, *cached;
1439 static GHashTable *ptr_hash = NULL;
1441 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1443 mono_loader_lock ();
1444 if (!ptr_hash)
1445 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1446 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1447 mono_loader_unlock ();
1448 if (cached)
1449 return cached;
1451 result = g_new0 (MonoClass, 1);
1453 result->parent = NULL; /* no parent for PTR types */
1454 result->name_space = "System";
1455 result->name = "MonoFNPtrFakeClass";
1456 result->class_kind = MONO_CLASS_POINTER;
1458 result->image = mono_defaults.corlib; /* need to fix... */
1459 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1460 result->min_align = sizeof (gpointer);
1461 result->cast_class = result->element_class = result;
1462 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_FNPTR;
1463 result->this_arg.data.method = result->_byval_arg.data.method = sig;
1464 result->this_arg.byref = TRUE;
1465 result->blittable = TRUE;
1466 result->inited = TRUE;
1468 mono_class_setup_supertypes (result);
1470 mono_loader_lock ();
1472 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1473 if (cached) {
1474 g_free (result);
1475 mono_loader_unlock ();
1476 return cached;
1479 MONO_PROFILER_RAISE (class_loading, (result));
1481 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1482 ++class_pointer_count;
1484 g_hash_table_insert (ptr_hash, sig, result);
1486 mono_loader_unlock ();
1488 MONO_PROFILER_RAISE (class_loaded, (result));
1490 return result;
1494 static void
1495 print_implemented_interfaces (MonoClass *klass)
1497 char *name;
1498 ERROR_DECL (error);
1499 GPtrArray *ifaces = NULL;
1500 int i;
1501 int ancestor_level = 0;
1503 name = mono_type_get_full_name (klass);
1504 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
1505 g_free (name);
1507 for (i = 0; i < klass->interface_offsets_count; i++) {
1508 char *ic_name = mono_type_get_full_name (klass->interfaces_packed [i]);
1509 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i,
1510 klass->interfaces_packed [i]->interface_id,
1511 klass->interface_offsets_packed [i],
1512 mono_class_get_method_count (klass->interfaces_packed [i]),
1513 ic_name);
1514 g_free (ic_name);
1516 printf ("Interface flags: ");
1517 for (i = 0; i <= klass->max_interface_id; i++)
1518 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
1519 printf ("(%d,T)", i);
1520 else
1521 printf ("(%d,F)", i);
1522 printf ("\n");
1523 printf ("Dump interface flags:");
1524 #ifdef COMPRESSED_INTERFACE_BITMAP
1526 const uint8_t* p = klass->interface_bitmap;
1527 i = klass->max_interface_id;
1528 while (i > 0) {
1529 printf (" %d x 00 %02X", p [0], p [1]);
1530 i -= p [0] * 8;
1531 i -= 8;
1534 #else
1535 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
1536 printf (" %02X", klass->interface_bitmap [i]);
1537 #endif
1538 printf ("\n");
1539 while (klass != NULL) {
1540 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
1541 ifaces = mono_class_get_implemented_interfaces (klass, error);
1542 if (!is_ok (error)) {
1543 printf (" Type failed due to %s\n", mono_error_get_message (error));
1544 mono_error_cleanup (error);
1545 } else if (ifaces) {
1546 for (i = 0; i < ifaces->len; i++) {
1547 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1548 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
1549 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
1550 ic->interface_id,
1551 mono_class_interface_offset (klass, ic),
1552 mono_class_get_method_count (ic),
1553 ic->name_space,
1554 ic->name );
1556 g_ptr_array_free (ifaces, TRUE);
1558 ancestor_level ++;
1559 klass = klass->parent;
1563 static gboolean
1564 method_is_reabstracted (guint16 flags)
1566 if ((flags & METHOD_ATTRIBUTE_ABSTRACT && flags & METHOD_ATTRIBUTE_FINAL))
1567 return TRUE;
1568 return FALSE;
1572 * Return the number of virtual methods.
1573 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1574 * Return -1 on failure.
1575 * FIXME It would be nice if this information could be cached somewhere.
1577 static int
1578 count_virtual_methods (MonoClass *klass)
1580 int i, mcount, vcount = 0;
1581 guint32 flags;
1582 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
1584 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
1585 mono_class_setup_methods (klass);
1586 if (mono_class_has_failure (klass))
1587 return -1;
1589 mcount = mono_class_get_method_count (klass);
1590 for (i = 0; i < mcount; ++i) {
1591 flags = klass->methods [i]->flags;
1592 if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1593 if (method_is_reabstracted (flags))
1594 continue;
1595 ++vcount;
1598 } else {
1599 int first_idx = mono_class_get_first_method_idx (klass);
1600 mcount = mono_class_get_method_count (klass);
1601 for (i = 0; i < mcount; ++i) {
1602 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
1604 if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1605 if (method_is_reabstracted (flags))
1606 continue;
1607 ++vcount;
1611 return vcount;
1614 static mono_bool
1615 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
1617 int i;
1618 for (i = 0; i < num_ifaces; ++i) {
1619 if (interfaces_full [i] && interfaces_full [i]->interface_id == ic->interface_id) {
1620 if (!force_set)
1621 return TRUE;
1622 interface_offsets_full [i] = offset;
1623 return FALSE;
1625 if (interfaces_full [i])
1626 continue;
1627 interfaces_full [i] = ic;
1628 interface_offsets_full [i] = offset;
1629 break;
1631 return FALSE;
1634 #ifdef COMPRESSED_INTERFACE_BITMAP
1637 * Compressed interface bitmap design.
1639 * Interface bitmaps take a large amount of memory, because their size is
1640 * linear with the maximum interface id assigned in the process (each interface
1641 * is assigned a unique id as it is loaded). The number of interface classes
1642 * is high because of the many implicit interfaces implemented by arrays (we'll
1643 * need to lazy-load them in the future).
1644 * Most classes implement a very small number of interfaces, so the bitmap is
1645 * sparse. This bitmap needs to be checked by interface casts, so access to the
1646 * needed bit must be fast and doable with few jit instructions.
1648 * The current compression format is as follows:
1649 * *) it is a sequence of one or more two-byte elements
1650 * *) the first byte in the element is the count of empty bitmap bytes
1651 * at the current bitmap position
1652 * *) the second byte in the element is an actual bitmap byte at the current
1653 * bitmap position
1655 * As an example, the following compressed bitmap bytes:
1656 * 0x07 0x01 0x00 0x7
1657 * correspond to the following bitmap:
1658 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1660 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1661 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1662 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1666 * mono_compress_bitmap:
1667 * \param dest destination buffer
1668 * \param bitmap bitmap buffer
1669 * \param size size of \p bitmap in bytes
1671 * This is a mono internal function.
1672 * The \p bitmap data is compressed into a format that is small but
1673 * still searchable in few instructions by the JIT and runtime.
1674 * The compressed data is stored in the buffer pointed to by the
1675 * \p dest array. Passing a NULL value for \p dest allows to just compute
1676 * the size of the buffer.
1677 * This compression algorithm assumes the bits set in the bitmap are
1678 * few and far between, like in interface bitmaps.
1679 * \returns The size of the compressed bitmap in bytes.
1682 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
1684 int numz = 0;
1685 int res = 0;
1686 const uint8_t *end = bitmap + size;
1687 while (bitmap < end) {
1688 if (*bitmap || numz == 255) {
1689 if (dest) {
1690 *dest++ = numz;
1691 *dest++ = *bitmap;
1693 res += 2;
1694 numz = 0;
1695 bitmap++;
1696 continue;
1698 bitmap++;
1699 numz++;
1701 if (numz) {
1702 res += 2;
1703 if (dest) {
1704 *dest++ = numz;
1705 *dest++ = 0;
1708 return res;
1712 * mono_class_interface_match:
1713 * \param bitmap a compressed bitmap buffer
1714 * \param id the index to check in the bitmap
1716 * This is a mono internal function.
1717 * Checks if a bit is set in a compressed interface bitmap. \p id must
1718 * be already checked for being smaller than the maximum id encoded in the
1719 * bitmap.
1721 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1722 * FALSE otherwise.
1725 mono_class_interface_match (const uint8_t *bitmap, int id)
1727 while (TRUE) {
1728 id -= bitmap [0] * 8;
1729 if (id < 8) {
1730 if (id < 0)
1731 return 0;
1732 return bitmap [1] & (1 << id);
1734 bitmap += 2;
1735 id -= 8;
1738 #endif
1741 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1742 * LOCKING: Acquires the loader lock.
1744 static int
1745 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
1747 ERROR_DECL (error);
1748 MonoClass *k, *ic;
1749 int i, j, num_ifaces;
1750 guint32 max_iid;
1751 MonoClass **interfaces_full = NULL;
1752 int *interface_offsets_full = NULL;
1753 GPtrArray *ifaces;
1754 GPtrArray **ifaces_array = NULL;
1755 int interface_offsets_count;
1756 max_iid = 0;
1757 num_ifaces = interface_offsets_count = 0;
1759 mono_loader_lock ();
1761 mono_class_setup_supertypes (klass);
1763 if (mono_class_is_ginst (klass)) {
1764 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1766 interface_offsets_count = num_ifaces = gklass->interface_offsets_count;
1767 interfaces_full = (MonoClass **)g_malloc (sizeof (MonoClass*) * num_ifaces);
1768 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1770 cur_slot = 0;
1771 for (int i = 0; i < num_ifaces; ++i) {
1772 MonoClass *gklass_ic = gklass->interfaces_packed [i];
1773 MonoClass *inflated = mono_class_inflate_generic_class_checked (gklass_ic, mono_class_get_context(klass), error);
1774 if (!is_ok (error)) {
1775 char *name = mono_type_get_full_name (gklass_ic);
1776 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1777 g_free (name);
1778 cur_slot = -1;
1779 goto end;
1782 mono_class_setup_interface_id_internal (inflated);
1784 interfaces_full [i] = inflated;
1785 interface_offsets_full [i] = gklass->interface_offsets_packed [i];
1787 int count = count_virtual_methods (inflated);
1788 if (count == -1) {
1789 char *name = mono_type_get_full_name (inflated);
1790 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1791 g_free (name);
1792 cur_slot = -1;
1793 goto end;
1796 cur_slot = MAX (cur_slot, interface_offsets_full [i] + count);
1797 max_iid = MAX (max_iid, inflated->interface_id);
1800 goto publish;
1802 /* compute maximum number of slots and maximum interface id */
1803 max_iid = 0;
1804 num_ifaces = 0; /* this can include duplicated ones */
1805 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
1806 for (j = 0; j < klass->idepth; j++) {
1807 k = klass->supertypes [j];
1808 g_assert (k);
1809 num_ifaces += k->interface_count;
1810 for (i = 0; i < k->interface_count; i++) {
1811 ic = k->interfaces [i];
1813 /* A gparam does not have any interface_id set. */
1814 if (! mono_class_is_gparam (ic))
1815 mono_class_setup_interface_id_internal (ic);
1817 if (max_iid < ic->interface_id)
1818 max_iid = ic->interface_id;
1820 ifaces = mono_class_get_implemented_interfaces (k, error);
1821 if (!is_ok (error)) {
1822 char *name = mono_type_get_full_name (k);
1823 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (error));
1824 g_free (name);
1825 mono_error_cleanup (error);
1826 cur_slot = -1;
1827 goto end;
1829 if (ifaces) {
1830 num_ifaces += ifaces->len;
1831 for (i = 0; i < ifaces->len; ++i) {
1832 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1833 if (max_iid < ic->interface_id)
1834 max_iid = ic->interface_id;
1836 ifaces_array [j] = ifaces;
1840 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
1841 num_ifaces++;
1842 if (max_iid < klass->interface_id)
1843 max_iid = klass->interface_id;
1846 /* compute vtable offset for interfaces */
1847 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
1848 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1850 for (i = 0; i < num_ifaces; i++)
1851 interface_offsets_full [i] = -1;
1853 /* skip the current class */
1854 for (j = 0; j < klass->idepth - 1; j++) {
1855 k = klass->supertypes [j];
1856 ifaces = ifaces_array [j];
1858 if (ifaces) {
1859 for (i = 0; i < ifaces->len; ++i) {
1860 int io;
1861 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1863 /*Force the sharing of interface offsets between parent and subtypes.*/
1864 io = mono_class_interface_offset (k, ic);
1865 g_assertf (io >= 0, "class %s parent %s has no offset for iface %s",
1866 mono_type_get_full_name (klass),
1867 mono_type_get_full_name (k),
1868 mono_type_get_full_name (ic));
1870 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
1875 g_assert (klass == klass->supertypes [klass->idepth - 1]);
1876 ifaces = ifaces_array [klass->idepth - 1];
1877 if (ifaces) {
1878 for (i = 0; i < ifaces->len; ++i) {
1879 int count;
1880 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1881 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
1882 continue;
1883 count = count_virtual_methods (ic);
1884 if (count == -1) {
1885 char *name = mono_type_get_full_name (ic);
1886 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1887 g_free (name);
1888 cur_slot = -1;
1889 goto end;
1891 cur_slot += count;
1895 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass))
1896 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
1898 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
1899 if (interface_offsets_full [i] != -1)
1900 interface_offsets_count ++;
1903 publish:
1904 /* Publish the data */
1905 klass->max_interface_id = max_iid;
1907 * We might get called multiple times:
1908 * - mono_class_init_internal ()
1909 * - mono_class_setup_vtable ().
1910 * - mono_class_setup_interface_offsets ().
1911 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1912 * means we have to overwrite those when called from other places (#4440).
1914 if (klass->interfaces_packed) {
1915 if (!overwrite)
1916 g_assert (klass->interface_offsets_count == interface_offsets_count);
1917 } else {
1918 uint8_t *bitmap;
1919 int bsize;
1920 klass->interface_offsets_count = interface_offsets_count;
1921 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
1922 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
1923 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
1924 #ifdef COMPRESSED_INTERFACE_BITMAP
1925 bitmap = g_malloc0 (bsize);
1926 #else
1927 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
1928 #endif
1929 for (i = 0; i < interface_offsets_count; i++) {
1930 guint32 id = interfaces_full [i]->interface_id;
1931 bitmap [id >> 3] |= (1 << (id & 7));
1932 klass->interfaces_packed [i] = interfaces_full [i];
1933 klass->interface_offsets_packed [i] = interface_offsets_full [i];
1935 #ifdef COMPRESSED_INTERFACE_BITMAP
1936 i = mono_compress_bitmap (NULL, bitmap, bsize);
1937 klass->interface_bitmap = mono_class_alloc0 (klass, i);
1938 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
1939 g_free (bitmap);
1940 #else
1941 klass->interface_bitmap = bitmap;
1942 #endif
1944 end:
1945 mono_loader_unlock ();
1947 g_free (interfaces_full);
1948 g_free (interface_offsets_full);
1949 if (ifaces_array) {
1950 for (i = 0; i < klass->idepth; i++) {
1951 ifaces = ifaces_array [i];
1952 if (ifaces)
1953 g_ptr_array_free (ifaces, TRUE);
1955 g_free (ifaces_array);
1958 //printf ("JUST DONE: ");
1959 //print_implemented_interfaces (klass);
1961 return cur_slot;
1965 * Setup interface offsets for interfaces.
1966 * Initializes:
1967 * - klass->max_interface_id
1968 * - klass->interface_offsets_count
1969 * - klass->interfaces_packed
1970 * - klass->interface_offsets_packed
1971 * - klass->interface_bitmap
1973 * This function can fail @class.
1976 void
1977 mono_class_setup_interface_offsets (MonoClass *klass)
1979 /* NOTE: This function is only correct for interfaces.
1981 * It assumes that klass's interfaces can be assigned offsets starting
1982 * from 0. That assumption is incorrect for classes and valuetypes.
1984 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && !mono_class_is_ginst (klass));
1985 setup_interface_offsets (klass, 0, FALSE);
1988 #define DEBUG_INTERFACE_VTABLE_CODE 0
1989 #define TRACE_INTERFACE_VTABLE_CODE 0
1990 #define VERIFY_INTERFACE_VTABLE_CODE 0
1991 #define VTABLE_SELECTOR (1)
1993 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
1994 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
1995 if (!(VTABLE_SELECTOR)) break; \
1996 stmt;\
1997 } while (0)
1998 #else
1999 #define DEBUG_INTERFACE_VTABLE(stmt)
2000 #endif
2002 #if TRACE_INTERFACE_VTABLE_CODE
2003 #define TRACE_INTERFACE_VTABLE(stmt) do {\
2004 if (!(VTABLE_SELECTOR)) break; \
2005 stmt;\
2006 } while (0)
2007 #else
2008 #define TRACE_INTERFACE_VTABLE(stmt)
2009 #endif
2011 #if VERIFY_INTERFACE_VTABLE_CODE
2012 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
2013 if (!(VTABLE_SELECTOR)) break; \
2014 stmt;\
2015 } while (0)
2016 #else
2017 #define VERIFY_INTERFACE_VTABLE(stmt)
2018 #endif
2021 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2022 static char*
2023 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
2025 int i;
2026 char *result;
2027 GString *res = g_string_new ("");
2029 g_string_append_c (res, '(');
2030 for (i = 0; i < sig->param_count; ++i) {
2031 if (i > 0)
2032 g_string_append_c (res, ',');
2033 mono_type_get_desc (res, sig->params [i], include_namespace);
2035 g_string_append (res, ")=>");
2036 if (sig->ret != NULL) {
2037 mono_type_get_desc (res, sig->ret, include_namespace);
2038 } else {
2039 g_string_append (res, "NULL");
2041 result = res->str;
2042 g_string_free (res, FALSE);
2043 return result;
2045 static void
2046 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
2047 char *im_sig = mono_signature_get_full_desc (mono_method_signature_internal (im), TRUE);
2048 char *cm_sig = mono_signature_get_full_desc (mono_method_signature_internal (cm), TRUE);
2049 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
2050 g_free (im_sig);
2051 g_free (cm_sig);
2055 #endif
2057 static gboolean
2058 is_wcf_hack_disabled (void)
2060 static char disabled;
2061 if (!disabled)
2062 disabled = g_hasenv ("MONO_DISABLE_WCF_HACK") ? 1 : 2;
2063 return disabled == 1;
2066 static gboolean
2067 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
2069 MonoMethodSignature *cmsig, *imsig;
2070 if (strcmp (im->name, cm->name) == 0) {
2071 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
2072 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2073 return FALSE;
2075 if (! slot_is_empty) {
2076 if (require_newslot) {
2077 if (! interface_is_explicitly_implemented_by_class) {
2078 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2079 return FALSE;
2081 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
2082 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2083 return FALSE;
2085 } else {
2086 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2089 cmsig = mono_method_signature_internal (cm);
2090 imsig = mono_method_signature_internal (im);
2091 if (!cmsig || !imsig) {
2092 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2093 return FALSE;
2096 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2097 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2098 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2099 TRACE_INTERFACE_VTABLE (printf ("]"));
2100 return FALSE;
2102 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2103 if (mono_security_core_clr_enabled ())
2104 mono_security_core_clr_check_override (klass, cm, im);
2106 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2107 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2108 char *body_name = mono_method_full_name (cm, TRUE);
2109 char *decl_name = mono_method_full_name (im, TRUE);
2110 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2111 g_free (body_name);
2112 g_free (decl_name);
2113 return FALSE;
2116 return TRUE;
2117 } else {
2118 MonoClass *ic = im->klass;
2119 const char *ic_name_space = ic->name_space;
2120 const char *ic_name = ic->name;
2121 char *subname;
2123 if (! require_newslot) {
2124 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2125 return FALSE;
2127 if (cm->klass->rank == 0) {
2128 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2129 return FALSE;
2131 cmsig = mono_method_signature_internal (cm);
2132 imsig = mono_method_signature_internal (im);
2133 if (!cmsig || !imsig) {
2134 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2135 return FALSE;
2138 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2139 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2140 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2141 TRACE_INTERFACE_VTABLE (printf ("]"));
2142 return FALSE;
2144 if (mono_class_get_image (ic) != mono_defaults.corlib) {
2145 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2146 return FALSE;
2148 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
2149 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2150 return FALSE;
2152 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))) {
2153 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2154 return FALSE;
2157 subname = (char*)strstr (cm->name, ic_name_space);
2158 if (subname != cm->name) {
2159 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2160 return FALSE;
2162 subname += strlen (ic_name_space);
2163 if (subname [0] != '.') {
2164 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2165 return FALSE;
2167 subname ++;
2168 if (strstr (subname, ic_name) != subname) {
2169 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2170 return FALSE;
2172 subname += strlen (ic_name);
2173 if (subname [0] != '.') {
2174 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2175 return FALSE;
2177 subname ++;
2178 if (strcmp (subname, im->name) != 0) {
2179 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2180 return FALSE;
2183 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2184 if (mono_security_core_clr_enabled ())
2185 mono_security_core_clr_check_override (klass, cm, im);
2187 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2188 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2189 char *body_name = mono_method_full_name (cm, TRUE);
2190 char *decl_name = mono_method_full_name (im, TRUE);
2191 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2192 g_free (body_name);
2193 g_free (decl_name);
2194 return FALSE;
2197 return TRUE;
2201 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2202 static void
2203 foreach_override (gpointer key, gpointer value, gpointer user_data)
2205 MonoMethod *method = key;
2206 MonoMethod *override = value;
2208 char *method_name = mono_method_get_full_name (method);
2209 char *override_name = mono_method_get_full_name (override);
2210 printf (" Method '%s' has override '%s'\n", method_name, override_name);
2211 g_free (method_name);
2212 g_free (override_name);
2215 static void
2216 print_overrides (GHashTable *override_map, const char *message)
2218 if (override_map) {
2219 printf ("Override map \"%s\" START:\n", message);
2220 g_hash_table_foreach (override_map, foreach_override, NULL);
2221 printf ("Override map \"%s\" END.\n", message);
2222 } else {
2223 printf ("Override map \"%s\" EMPTY.\n", message);
2227 static void
2228 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces)
2230 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2231 int i;
2232 int parent_size;
2234 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
2236 if (print_interfaces) {
2237 print_implemented_interfaces (klass);
2238 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
2241 if (klass->parent) {
2242 parent_size = klass->parent->vtable_size;
2243 } else {
2244 parent_size = 0;
2246 for (i = 0; i < size; ++i) {
2247 MonoMethod *cm = vtable [i];
2248 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
2249 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
2251 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
2252 g_free (cm_name);
2255 g_free (full_name);
2257 #endif
2259 #if VERIFY_INTERFACE_VTABLE_CODE
2260 static int
2261 mono_method_try_get_vtable_index (MonoMethod *method)
2263 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2264 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
2265 if (imethod->declaring->is_generic)
2266 return imethod->declaring->slot;
2268 return method->slot;
2271 static void
2272 mono_class_verify_vtable (MonoClass *klass)
2274 int i, count;
2275 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2277 printf ("*** Verifying VTable of class '%s' \n", full_name);
2278 g_free (full_name);
2279 full_name = NULL;
2281 if (!klass->methods)
2282 return;
2284 count = mono_class_get_method_count (klass);
2285 for (i = 0; i < count; ++i) {
2286 MonoMethod *cm = klass->methods [i];
2287 int slot;
2289 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2290 continue;
2292 g_free (full_name);
2293 full_name = mono_method_full_name (cm, TRUE);
2295 slot = mono_method_try_get_vtable_index (cm);
2296 if (slot >= 0) {
2297 if (slot >= klass->vtable_size) {
2298 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
2299 continue;
2302 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
2303 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
2304 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
2305 g_free (other_name);
2307 } else
2308 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
2310 g_free (full_name);
2312 #endif
2314 static MonoMethod*
2315 mono_method_get_method_definition (MonoMethod *method)
2317 while (method->is_inflated)
2318 method = ((MonoMethodInflated*)method)->declaring;
2319 return method;
2322 static gboolean
2323 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
2325 int i;
2327 for (i = 0; i < onum; ++i) {
2328 MonoMethod *decl = overrides [i * 2];
2329 MonoMethod *body = overrides [i * 2 + 1];
2331 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
2332 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
2333 return FALSE;
2336 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
2337 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2338 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
2339 else
2340 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
2341 return FALSE;
2344 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
2345 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2346 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
2347 else
2348 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
2349 return FALSE;
2352 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
2353 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
2354 return FALSE;
2357 body = mono_method_get_method_definition (body);
2358 decl = mono_method_get_method_definition (decl);
2360 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
2361 char *body_name = mono_method_full_name (body, TRUE);
2362 char *decl_name = mono_method_full_name (decl, TRUE);
2363 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2364 g_free (body_name);
2365 g_free (decl_name);
2366 return FALSE;
2369 return TRUE;
2372 /*Checks if @klass has @parent as one of it's parents type gtd
2374 * For example:
2375 * Foo<T>
2376 * Bar<T> : Foo<Bar<Bar<T>>>
2379 static gboolean
2380 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
2382 klass = mono_class_get_generic_type_definition (klass);
2383 parent = mono_class_get_generic_type_definition (parent);
2384 mono_class_setup_supertypes (klass);
2385 mono_class_setup_supertypes (parent);
2387 return klass->idepth >= parent->idepth &&
2388 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
2391 gboolean
2392 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
2394 MonoGenericInst *ginst;
2395 int i;
2397 if (!mono_class_is_ginst (klass)) {
2398 mono_class_setup_vtable_full (klass, in_setup);
2399 return !mono_class_has_failure (klass);
2402 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
2403 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
2404 return FALSE;
2406 ginst = mono_class_get_generic_class (klass)->context.class_inst;
2407 for (i = 0; i < ginst->type_argc; ++i) {
2408 MonoClass *arg;
2409 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
2410 continue;
2411 arg = mono_class_from_mono_type_internal (ginst->type_argv [i]);
2412 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2413 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
2414 continue;
2415 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
2416 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
2417 return FALSE;
2420 return TRUE;
2424 * mono_class_setup_vtable:
2426 * Creates the generic vtable of CLASS.
2427 * Initializes the following fields in MonoClass:
2428 * - vtable
2429 * - vtable_size
2430 * Plus all the fields initialized by setup_interface_offsets ().
2431 * If there is an error during vtable construction, klass->has_failure
2432 * is set and details are stored in a MonoErrorBoxed.
2434 * LOCKING: Acquires the loader lock.
2436 void
2437 mono_class_setup_vtable (MonoClass *klass)
2439 mono_class_setup_vtable_full (klass, NULL);
2442 static void
2443 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
2445 ERROR_DECL (error);
2446 MonoMethod **overrides = NULL;
2447 MonoGenericContext *context;
2448 guint32 type_token;
2449 int onum = 0;
2451 if (klass->vtable)
2452 return;
2454 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
2455 /* This sets method->slot for all methods if this is an interface */
2456 mono_class_setup_methods (klass);
2457 return;
2460 if (mono_class_has_failure (klass))
2461 return;
2463 if (g_list_find (in_setup, klass))
2464 return;
2466 mono_loader_lock ();
2468 if (klass->vtable) {
2469 mono_loader_unlock ();
2470 return;
2473 UnlockedIncrement (&mono_stats.generic_vtable_count);
2474 in_setup = g_list_prepend (in_setup, klass);
2476 if (mono_class_is_ginst (klass)) {
2477 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
2478 mono_loader_unlock ();
2479 g_list_remove (in_setup, klass);
2480 return;
2483 context = mono_class_get_context (klass);
2484 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
2485 } else {
2486 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
2487 type_token = klass->type_token;
2490 if (image_is_dynamic (klass->image)) {
2491 /* Generic instances can have zero method overrides without causing any harm.
2492 * This is true since we don't do layout all over again for them, we simply inflate
2493 * the layout of the parent.
2495 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, error);
2496 if (!is_ok (error)) {
2497 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2498 goto done;
2500 } else {
2501 /* The following call fails if there are missing methods in the type */
2502 /* FIXME it's probably a good idea to avoid this for generic instances. */
2503 mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context, error);
2504 if (!is_ok (error)) {
2505 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2506 goto done;
2510 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
2512 done:
2513 g_free (overrides);
2514 mono_error_cleanup (error);
2516 mono_loader_unlock ();
2517 g_list_remove (in_setup, klass);
2519 return;
2522 static gboolean
2523 mono_class_need_stelemref_method (MonoClass *klass)
2525 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass)));
2528 static int
2529 apply_override (MonoClass *klass, MonoClass *override_class, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override,
2530 GHashTable **override_map, GHashTable **override_class_map, GHashTable **conflict_map)
2532 int dslot;
2533 dslot = mono_method_get_vtable_slot (decl);
2534 if (dslot == -1) {
2535 mono_class_set_type_load_failure (klass, "");
2536 return FALSE;
2539 dslot += mono_class_interface_offset (klass, decl->klass);
2541 //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
2542 if (vtable [dslot] && vtable [dslot]->klass && MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (vtable [dslot]->klass))
2543 return TRUE;
2545 vtable [dslot] = override;
2546 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass)) {
2548 * If override from an interface, then it is an override of a default interface method,
2549 * don't override its slot.
2551 vtable [dslot]->slot = dslot;
2554 if (!*override_map) {
2555 *override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2556 *override_class_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2558 GHashTable *map = *override_map;
2559 GHashTable *class_map = *override_class_map;
2561 MonoMethod *prev_override = (MonoMethod*)g_hash_table_lookup (map, decl);
2562 MonoClass *prev_override_class = (MonoClass*)g_hash_table_lookup (class_map, decl);
2564 g_hash_table_insert (map, decl, override);
2565 g_hash_table_insert (class_map, decl, override_class);
2567 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2568 if (prev_override) {
2569 ERROR_DECL (error);
2572 * The override methods are part of the generic definition, need to inflate them so their
2573 * parent class becomes the actual interface/class containing the override, i.e.
2574 * IFace<T> in:
2575 * class Foo<T> : IFace<T>
2576 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2577 * conflict resolution work.
2579 if (mono_class_is_ginst (override_class)) {
2580 override = mono_class_inflate_generic_method_checked (override, &mono_class_get_generic_class (override_class)->context, error);
2581 mono_error_assert_ok (error);
2584 if (mono_class_is_ginst (prev_override_class)) {
2585 prev_override = mono_class_inflate_generic_method_checked (prev_override, &mono_class_get_generic_class (prev_override_class)->context, error);
2586 mono_error_assert_ok (error);
2589 if (!*conflict_map)
2590 *conflict_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2591 GHashTable *cmap = *conflict_map;
2592 GSList *entries = (GSList*)g_hash_table_lookup (cmap, decl);
2593 if (!(decl->flags & METHOD_ATTRIBUTE_ABSTRACT))
2594 entries = g_slist_prepend (entries, decl);
2595 entries = g_slist_prepend (entries, prev_override);
2596 entries = g_slist_prepend (entries, override);
2598 g_hash_table_insert (cmap, decl, entries);
2601 return TRUE;
2604 static void
2605 handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflict_map)
2607 GHashTableIter iter;
2608 MonoMethod *decl;
2609 GSList *entries, *l, *l2;
2610 GSList *dim_conflicts = NULL;
2612 g_hash_table_iter_init (&iter, conflict_map);
2613 while (g_hash_table_iter_next (&iter, (gpointer*)&decl, (gpointer*)&entries)) {
2615 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2616 * class of another one.
2618 /* This is O(n^2), but that shouldn't be a problem in practice */
2619 for (l = entries; l; l = l->next) {
2620 for (l2 = entries; l2; l2 = l2->next) {
2621 MonoMethod *m1 = (MonoMethod*)l->data;
2622 MonoMethod *m2 = (MonoMethod*)l2->data;
2623 if (!m1 || !m2 || m1 == m2)
2624 continue;
2625 if (mono_class_is_assignable_from_internal (m1->klass, m2->klass))
2626 l->data = NULL;
2627 else if (mono_class_is_assignable_from_internal (m2->klass, m1->klass))
2628 l2->data = NULL;
2631 int nentries = 0;
2632 MonoMethod *impl = NULL;
2633 for (l = entries; l; l = l->next) {
2634 if (l->data) {
2635 nentries ++;
2636 impl = (MonoMethod*)l->data;
2639 if (nentries > 1) {
2640 /* If more than one method is left, we have a conflict */
2641 if (decl->is_inflated)
2642 decl = ((MonoMethodInflated*)decl)->declaring;
2643 dim_conflicts = g_slist_prepend (dim_conflicts, decl);
2645 for (l = entries; l; l = l->next) {
2646 if (l->data)
2647 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2650 } else {
2652 * Use the implementing method computed above instead of the already
2653 * computed one, which depends on interface ordering.
2655 int ic_offset = mono_class_interface_offset (klass, decl->klass);
2656 int im_slot = ic_offset + decl->slot;
2657 vtable [im_slot] = impl;
2659 g_slist_free (entries);
2661 if (dim_conflicts) {
2662 mono_loader_lock ();
2663 klass->has_dim_conflicts = 1;
2664 mono_loader_unlock ();
2667 * Exceptions are thrown at method call time and only for the methods which have
2668 * conflicts, so just save them in the class.
2671 /* Make a copy of the list from the class mempool */
2672 GSList *conflicts = (GSList*)mono_class_alloc0 (klass, g_slist_length (dim_conflicts) * sizeof (GSList));
2673 int i = 0;
2674 for (l = dim_conflicts; l; l = l->next) {
2675 conflicts [i].data = l->data;
2676 conflicts [i].next = &conflicts [i + 1];
2677 i ++;
2679 conflicts [i - 1].next = NULL;
2681 mono_class_set_dim_conflicts (klass, conflicts);
2682 g_slist_free (dim_conflicts);
2686 static void
2687 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
2689 int index, mcount;
2690 char *method_signature;
2691 char *type_name;
2693 for (index = 0; index < onum; ++index) {
2694 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name,
2695 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
2697 method_signature = mono_signature_get_desc (mono_method_signature_internal (im), FALSE);
2698 type_name = mono_type_full_name (m_class_get_byval_arg (klass));
2699 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s",
2700 mono_type_get_name (m_class_get_byval_arg (ic)), im->name, method_signature, type_name);
2701 g_free (method_signature);
2702 g_free (type_name);
2703 mono_class_setup_methods (klass);
2704 if (mono_class_has_failure (klass)) {
2705 char *name = mono_type_get_full_name (klass);
2706 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name);
2707 g_free (name);
2708 return;
2710 mcount = mono_class_get_method_count (klass);
2711 for (index = 0; index < mcount; ++index) {
2712 MonoMethod *cm = klass->methods [index];
2713 method_signature = mono_signature_get_desc (mono_method_signature_internal (cm), TRUE);
2715 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature);
2716 g_free (method_signature);
2721 * mono_class_get_virtual_methods:
2723 * Iterate over the virtual methods of KLASS.
2725 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2727 static MonoMethod*
2728 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
2730 // FIXME move state to caller
2731 gboolean static_iter = FALSE;
2733 if (!iter)
2734 return NULL;
2737 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2738 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2739 * klass->methods.
2741 if ((gsize)(*iter) & 1)
2742 static_iter = TRUE;
2743 /* Use the static metadata only if klass->methods is not yet initialized */
2744 if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
2745 static_iter = TRUE;
2747 if (!static_iter) {
2748 MonoMethod** methodptr;
2750 if (!*iter) {
2751 mono_class_setup_methods (klass);
2753 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2754 * FIXME we should better report this error to the caller
2756 if (!klass->methods)
2757 return NULL;
2758 /* start from the first */
2759 methodptr = &klass->methods [0];
2760 } else {
2761 methodptr = (MonoMethod **)*iter;
2762 methodptr++;
2764 if (*iter)
2765 g_assert ((guint64)(*iter) > 0x100);
2766 int mcount = mono_class_get_method_count (klass);
2767 while (methodptr < &klass->methods [mcount]) {
2768 if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
2769 break;
2770 methodptr ++;
2772 if (methodptr < &klass->methods [mcount]) {
2773 *iter = methodptr;
2774 return *methodptr;
2775 } else {
2776 return NULL;
2778 } else {
2779 /* Search directly in metadata to avoid calling setup_methods () */
2780 MonoMethod *res = NULL;
2781 int i, start_index;
2783 if (!*iter) {
2784 start_index = 0;
2785 } else {
2786 start_index = GPOINTER_TO_UINT (*iter) >> 1;
2789 int first_idx = mono_class_get_first_method_idx (klass);
2790 int mcount = mono_class_get_method_count (klass);
2791 for (i = start_index; i < mcount; ++i) {
2792 guint32 flags;
2794 /* first_idx points into the methodptr table */
2795 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
2797 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2798 break;
2801 if (i < mcount) {
2802 ERROR_DECL (error);
2803 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
2804 mono_error_cleanup (error); /* FIXME don't swallow the error */
2806 /* Add 1 here so the if (*iter) check fails */
2807 *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1);
2808 return res;
2809 } else {
2810 return NULL;
2815 static void
2816 print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot)
2818 int i, icount = 0;
2820 print_implemented_interfaces (klass);
2822 for (i = 0; i <= klass->max_interface_id; i++)
2823 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2824 icount++;
2826 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass)),
2827 klass->vtable_size, icount);
2829 for (i = 0; i < cur_slot; ++i) {
2830 MonoMethod *cm;
2832 cm = vtable [i];
2833 if (cm) {
2834 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
2835 mono_method_get_full_name (cm));
2836 } else {
2837 printf (" slot assigned: %03d, <null>\n", i);
2842 if (icount) {
2843 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
2844 klass->name, klass->max_interface_id);
2846 for (i = 0; i < klass->interface_count; i++) {
2847 MonoClass *ic = klass->interfaces [i];
2848 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2849 mono_class_interface_offset (klass, ic),
2850 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2853 for (MonoClass *k = klass->parent; k ; k = k->parent) {
2854 for (i = 0; i < k->interface_count; i++) {
2855 MonoClass *ic = k->interfaces [i];
2856 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2857 mono_class_interface_offset (klass, ic),
2858 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2865 * LOCKING: this is supposed to be called with the loader lock held.
2867 static int
2868 setup_class_vtsize (MonoClass *klass, GList *in_setup, int *cur_slot, int *stelemref_slot, MonoError *error)
2870 GPtrArray *ifaces = NULL;
2871 int i, max_vtsize = 0;
2872 ifaces = mono_class_get_implemented_interfaces (klass, error);
2873 if (!is_ok (error)) {
2874 char *name = mono_type_get_full_name (klass);
2875 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (error));
2876 g_free (name);
2877 mono_error_cleanup (error);
2878 return -1;
2879 } else if (ifaces) {
2880 for (i = 0; i < ifaces->len; i++) {
2881 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2882 max_vtsize += mono_class_get_method_count (ic);
2884 g_ptr_array_free (ifaces, TRUE);
2885 ifaces = NULL;
2888 if (klass->parent) {
2889 mono_class_init_internal (klass->parent);
2890 mono_class_setup_vtable_full (klass->parent, in_setup);
2892 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
2893 return -1;
2895 max_vtsize += klass->parent->vtable_size;
2896 *cur_slot = klass->parent->vtable_size;
2899 max_vtsize += mono_class_get_method_count (klass);
2901 /*Array have a slot for stelemref*/
2902 if (mono_class_need_stelemref_method (klass)) {
2903 *stelemref_slot = *cur_slot;
2904 ++max_vtsize;
2905 ++*cur_slot;
2907 return max_vtsize;
2911 * LOCKING: this is supposed to be called with the loader lock held.
2913 static void
2914 mono_class_setup_vtable_ginst (MonoClass *klass, GList *in_setup)
2916 ERROR_DECL (error);
2917 int i;
2918 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2919 MonoMethod **tmp;
2921 mono_class_setup_vtable_full (gklass, in_setup);
2922 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
2923 return;
2925 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
2926 klass->vtable_size = gklass->vtable_size;
2927 for (i = 0; i < gklass->vtable_size; ++i)
2928 if (gklass->vtable [i]) {
2929 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), error);
2930 if (!is_ok (error)) {
2931 char *name = mono_type_get_full_name (klass);
2932 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (error));
2933 mono_error_cleanup (error);
2934 g_free (name);
2935 return;
2937 tmp [i] = inflated;
2938 tmp [i]->slot = gklass->vtable [i]->slot;
2940 mono_memory_barrier ();
2941 klass->vtable = tmp;
2943 mono_loader_lock ();
2944 klass->has_dim_conflicts = gklass->has_dim_conflicts;
2945 mono_loader_unlock ();
2947 /* Have to set method->slot for abstract virtual methods */
2948 if (klass->methods && gklass->methods) {
2949 int mcount = mono_class_get_method_count (klass);
2950 for (i = 0; i < mcount; ++i)
2951 if (klass->methods [i]->slot == -1)
2952 klass->methods [i]->slot = gklass->methods [i]->slot;
2955 if (mono_print_vtable)
2956 print_vtable_layout_result (klass, klass->vtable, gklass->vtable_size);
2961 * LOCKING: this is supposed to be called with the loader lock held.
2963 void
2964 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
2966 ERROR_DECL (error);
2967 MonoClass *k, *ic;
2968 MonoMethod **vtable = NULL;
2969 int i, max_vtsize = 0, cur_slot = 0;
2970 GHashTable *override_map = NULL;
2971 GHashTable *override_class_map = NULL;
2972 GHashTable *conflict_map = NULL;
2973 MonoMethod *cm;
2974 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2975 int first_non_interface_slot;
2976 #endif
2977 GSList *virt_methods = NULL, *l;
2978 int stelemref_slot = 0;
2980 if (klass->vtable)
2981 return;
2983 if (overrides && !verify_class_overrides (klass, overrides, onum))
2984 return;
2986 max_vtsize = setup_class_vtsize (klass, in_setup, &cur_slot, &stelemref_slot, error);
2987 if (max_vtsize == -1)
2988 return;
2990 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
2991 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
2992 return;
2994 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
2996 /* Optimized version for generic instances */
2997 if (mono_class_is_ginst (klass)) {
2998 mono_class_setup_vtable_ginst (klass, in_setup);
2999 return;
3002 vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize);
3004 if (klass->parent && klass->parent->vtable_size)
3005 memcpy (vtable, klass->parent->vtable, sizeof (gpointer) * klass->parent->vtable_size);
3007 /*Array have a slot for stelemref*/
3008 if (mono_class_need_stelemref_method (klass)) {
3009 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
3010 if (!method->slot)
3011 method->slot = stelemref_slot;
3012 else
3013 g_assert (method->slot == stelemref_slot);
3015 vtable [stelemref_slot] = method;
3018 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
3020 /* Process overrides from interface default methods */
3021 // FIXME: Ordering between interfaces
3022 for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
3023 ic = klass->interfaces_packed [ifindex];
3025 mono_class_setup_methods (ic);
3026 if (mono_class_has_failure (ic))
3027 goto fail;
3029 MonoMethod **iface_overrides;
3030 int iface_onum;
3031 mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic), error);
3032 goto_if_nok (error, fail);
3033 for (int i = 0; i < iface_onum; i++) {
3034 MonoMethod *decl = iface_overrides [i*2];
3035 MonoMethod *override = iface_overrides [i*2 + 1];
3036 if (decl->is_inflated) {
3037 override = mono_class_inflate_generic_method_checked (override, mono_method_get_context (decl), error);
3038 mono_error_assert_ok (error);
3039 } else if (mono_class_is_gtd (override->klass)) {
3040 override = mono_class_inflate_generic_method_full_checked (override, ic, mono_class_get_context (ic), error);
3042 if (!apply_override (klass, ic, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3043 goto fail;
3045 g_free (iface_overrides);
3048 /* override interface methods */
3049 for (i = 0; i < onum; i++) {
3050 MonoMethod *decl = overrides [i*2];
3051 MonoMethod *override = overrides [i*2 + 1];
3052 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3053 if (!apply_override (klass, klass, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3054 goto fail;
3058 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
3059 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
3062 * Create a list of virtual methods to avoid calling
3063 * mono_class_get_virtual_methods () which is slow because of the metadata
3064 * optimization.
3067 gpointer iter = NULL;
3068 MonoMethod *cm;
3070 virt_methods = NULL;
3071 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
3072 virt_methods = g_slist_prepend (virt_methods, cm);
3074 if (mono_class_has_failure (klass))
3075 goto fail;
3078 // Loop on all implemented interfaces...
3079 for (i = 0; i < klass->interface_offsets_count; i++) {
3080 MonoClass *parent = klass->parent;
3081 int ic_offset;
3082 gboolean interface_is_explicitly_implemented_by_class;
3083 int im_index;
3085 ic = klass->interfaces_packed [i];
3086 ic_offset = mono_class_interface_offset (klass, ic);
3088 mono_class_setup_methods (ic);
3089 if (mono_class_has_failure (ic))
3090 goto fail;
3092 // Check if this interface is explicitly implemented (instead of just inherited)
3093 if (parent != NULL) {
3094 int implemented_interfaces_index;
3095 interface_is_explicitly_implemented_by_class = FALSE;
3096 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
3097 if (ic == klass->interfaces [implemented_interfaces_index]) {
3098 interface_is_explicitly_implemented_by_class = TRUE;
3099 break;
3102 } else {
3103 interface_is_explicitly_implemented_by_class = TRUE;
3106 // Loop on all interface methods...
3107 int mcount = mono_class_get_method_count (ic);
3108 for (im_index = 0; im_index < mcount; im_index++) {
3109 MonoMethod *im = ic->methods [im_index];
3110 int im_slot = ic_offset + im->slot;
3111 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
3113 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3114 continue;
3116 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
3118 if (override_im == NULL || (override_im && MONO_CLASS_IS_INTERFACE_INTERNAL(override_im->klass))) {
3119 int cm_index;
3120 MonoMethod *cm;
3122 // First look for a suitable method among the class methods
3123 for (l = virt_methods; l; l = l->next) {
3124 cm = (MonoMethod *)l->data;
3125 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)));
3126 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
3127 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3128 vtable [im_slot] = cm;
3129 /* Why do we need this? */
3130 if (cm->slot < 0) {
3131 cm->slot = im_slot;
3133 if (conflict_map)
3134 g_hash_table_remove(conflict_map, im);
3135 break;
3137 TRACE_INTERFACE_VTABLE (printf ("\n"));
3138 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3139 goto fail;
3142 // If the slot is still empty, look in all the inherited virtual methods...
3143 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
3144 MonoClass *parent = klass->parent;
3145 // Reverse order, so that last added methods are preferred
3146 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
3147 MonoMethod *cm = parent->vtable [cm_index];
3149 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));
3150 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
3151 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3152 vtable [im_slot] = cm;
3153 /* Why do we need this? */
3154 if (cm->slot < 0) {
3155 cm->slot = im_slot;
3157 break;
3159 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3160 goto fail;
3161 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
3165 if (vtable [im_slot] == NULL) {
3166 if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
3167 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im, 1)));
3168 vtable [im_slot] = im;
3171 } else {
3172 g_assert (vtable [im_slot] == override_im);
3177 // If the class is not abstract, check that all its interface slots are full.
3178 // The check is done here and not directly at the end of the loop above because
3179 // it can happen (for injected generic array interfaces) that the same slot is
3180 // processed multiple times (those interfaces have overlapping slots), and it
3181 // will not always be the first pass the one that fills the slot.
3182 // 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
3183 if (!mono_class_is_abstract (klass)) {
3184 for (i = 0; i < klass->interface_offsets_count; i++) {
3185 int ic_offset;
3186 int im_index;
3188 ic = klass->interfaces_packed [i];
3189 ic_offset = mono_class_interface_offset (klass, ic);
3191 int mcount = mono_class_get_method_count (ic);
3192 for (im_index = 0; im_index < mcount; im_index++) {
3193 MonoMethod *im = ic->methods [im_index];
3194 int im_slot = ic_offset + im->slot;
3196 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3197 continue;
3198 if (im->is_reabstracted == 1)
3199 continue;
3201 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3202 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
3203 if (vtable [im_slot] == NULL) {
3204 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
3205 goto fail;
3211 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
3212 for (l = virt_methods; l; l = l->next) {
3213 cm = (MonoMethod *)l->data;
3215 * If the method is REUSE_SLOT, we must check in the
3216 * base class for a method to override.
3218 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3219 int slot = -1;
3220 for (k = klass->parent; k ; k = k->parent) {
3221 gpointer k_iter;
3222 MonoMethod *m1;
3224 k_iter = NULL;
3225 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
3226 MonoMethodSignature *cmsig, *m1sig;
3228 cmsig = mono_method_signature_internal (cm);
3229 m1sig = mono_method_signature_internal (m1);
3231 if (!cmsig || !m1sig) /* FIXME proper error message, use signature_checked? */
3232 goto fail;
3234 if (!strcmp(cm->name, m1->name) &&
3235 mono_metadata_signature_equal (cmsig, m1sig)) {
3237 if (mono_security_core_clr_enabled ())
3238 mono_security_core_clr_check_override (klass, cm, m1);
3240 slot = mono_method_get_vtable_slot (m1);
3241 if (slot == -1)
3242 goto fail;
3244 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
3245 char *body_name = mono_method_full_name (cm, TRUE);
3246 char *decl_name = mono_method_full_name (m1, TRUE);
3247 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3248 g_free (body_name);
3249 g_free (decl_name);
3250 goto fail;
3253 g_assert (cm->slot < max_vtsize);
3254 if (!override_map)
3255 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3256 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3257 mono_method_full_name (m1, 1), m1,
3258 mono_method_full_name (cm, 1), cm));
3259 g_hash_table_insert (override_map, m1, cm);
3260 break;
3263 if (mono_class_has_failure (k))
3264 goto fail;
3266 if (slot >= 0)
3267 break;
3269 if (slot >= 0)
3270 cm->slot = slot;
3273 /*Non final newslot methods must be given a non-interface vtable slot*/
3274 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
3275 cm->slot = -1;
3277 if (cm->slot < 0)
3278 cm->slot = cur_slot++;
3280 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
3281 vtable [cm->slot] = cm;
3284 /* override non interface methods */
3285 for (i = 0; i < onum; i++) {
3286 MonoMethod *decl = overrides [i*2];
3287 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3288 g_assert (decl->slot != -1);
3289 vtable [decl->slot] = overrides [i*2 + 1];
3290 overrides [i * 2 + 1]->slot = decl->slot;
3291 if (!override_map)
3292 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3293 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3294 mono_method_full_name (decl, 1), decl,
3295 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
3296 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
3298 if (mono_security_core_clr_enabled ())
3299 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
3304 * If a method occupies more than one place in the vtable, and it is
3305 * overriden, then change the other occurrences too.
3307 if (override_map) {
3308 MonoMethod *cm;
3310 for (i = 0; i < max_vtsize; ++i)
3311 if (vtable [i]) {
3312 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
3314 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
3315 if (cm)
3316 vtable [i] = cm;
3319 g_hash_table_destroy (override_map);
3320 override_map = NULL;
3323 if (override_class_map)
3324 g_hash_table_destroy (override_class_map);
3326 if (conflict_map) {
3327 handle_dim_conflicts (vtable, klass, conflict_map);
3328 g_hash_table_destroy (conflict_map);
3331 g_slist_free (virt_methods);
3332 virt_methods = NULL;
3334 g_assert (cur_slot <= max_vtsize);
3336 /* Ensure that all vtable slots are filled with concrete instance methods */
3337 // 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
3338 if (!mono_class_is_abstract (klass)) {
3339 for (i = 0; i < cur_slot; ++i) {
3340 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
3341 if (vtable [i] != NULL && vtable [i]->is_reabstracted == 1)
3342 continue;
3343 char *type_name = mono_type_get_full_name (klass);
3344 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
3345 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
3346 g_free (type_name);
3347 g_free (method_name);
3349 if (mono_print_vtable)
3350 print_vtable_layout_result (klass, vtable, cur_slot);
3352 g_free (vtable);
3353 return;
3358 if (mono_class_is_ginst (klass)) {
3359 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3361 mono_class_init_internal (gklass);
3363 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
3364 } else {
3365 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
3366 if (klass->vtable_size)
3367 g_assert (cur_slot == klass->vtable_size);
3368 klass->vtable_size = cur_slot;
3371 /* Try to share the vtable with our parent. */
3372 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
3373 mono_memory_barrier ();
3374 klass->vtable = klass->parent->vtable;
3375 } else {
3376 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
3377 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
3378 mono_memory_barrier ();
3379 klass->vtable = tmp;
3382 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
3383 if (mono_print_vtable)
3384 print_vtable_layout_result (klass, vtable, cur_slot);
3386 g_free (vtable);
3388 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
3389 return;
3391 fail:
3393 char *name = mono_type_get_full_name (klass);
3394 if (!is_ok (error))
3395 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (error));
3396 else
3397 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
3398 mono_error_cleanup (error);
3399 g_free (name);
3400 if (mono_print_vtable)
3401 print_vtable_layout_result (klass, vtable, cur_slot);
3404 g_free (vtable);
3405 if (override_map)
3406 g_hash_table_destroy (override_map);
3407 if (virt_methods)
3408 g_slist_free (virt_methods);
3412 static char*
3413 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
3415 int null_length = strlen ("(null)");
3416 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
3417 char *s = (char *)mono_image_alloc (image, len);
3418 int result;
3420 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
3421 g_assert (result == len - 1);
3423 return s;
3427 static void
3428 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
3430 if (cached_info) {
3431 mono_loader_lock ();
3432 klass->instance_size = cached_info->instance_size;
3433 klass->sizes.class_size = cached_info->class_size;
3434 klass->packing_size = cached_info->packing_size;
3435 klass->min_align = cached_info->min_align;
3436 klass->blittable = cached_info->blittable;
3437 klass->has_references = cached_info->has_references;
3438 klass->has_static_refs = cached_info->has_static_refs;
3439 klass->no_special_static_fields = cached_info->no_special_static_fields;
3440 klass->has_weak_fields = cached_info->has_weak_fields;
3441 mono_loader_unlock ();
3443 else {
3444 if (!klass->size_inited)
3445 mono_class_setup_fields (klass);
3450 * mono_class_init_sizes:
3452 * Initializes the size related fields of @klass without loading all field data if possible.
3453 * Sets the following fields in @klass:
3454 * - instance_size
3455 * - sizes.class_size
3456 * - packing_size
3457 * - min_align
3458 * - blittable
3459 * - has_references
3460 * - has_static_refs
3461 * - size_inited
3462 * Can fail the class.
3464 * LOCKING: Acquires the loader lock.
3466 void
3467 mono_class_init_sizes (MonoClass *klass)
3469 MonoCachedClassInfo cached_info;
3470 gboolean has_cached_info;
3472 if (klass->size_inited)
3473 return;
3475 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
3477 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
3481 static gboolean
3482 class_has_references (MonoClass *klass)
3484 mono_class_init_sizes (klass);
3487 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3488 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3489 * embed themselves.
3491 return klass->has_references;
3494 static gboolean
3495 type_has_references (MonoClass *klass, MonoType *ftype)
3497 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type_internal (ftype)))))
3498 return TRUE;
3499 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
3500 MonoGenericParam *gparam = ftype->data.generic_param;
3502 if (gparam->gshared_constraint)
3503 return class_has_references (mono_class_from_mono_type_internal (gparam->gshared_constraint));
3505 return FALSE;
3509 * mono_class_is_gparam_with_nonblittable_parent:
3510 * \param klass a generic parameter
3512 * \returns TRUE if \p klass is definitely not blittable.
3514 * A parameter is definitely not blittable if it has the IL 'reference'
3515 * constraint, or if it has a class specified as a parent. If it has an IL
3516 * 'valuetype' constraint or no constraint at all or only interfaces as
3517 * constraints, we return FALSE because the parameter may be instantiated both
3518 * with blittable and non-blittable types.
3520 * If the paramter is a generic sharing parameter, we look at its gshared_constraint->blittable bit.
3522 static gboolean
3523 mono_class_is_gparam_with_nonblittable_parent (MonoClass *klass)
3525 MonoType *type = m_class_get_byval_arg (klass);
3526 g_assert (mono_type_is_generic_parameter (type));
3527 MonoGenericParam *gparam = type->data.generic_param;
3528 if ((mono_generic_param_info (gparam)->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0)
3529 return TRUE;
3530 if ((mono_generic_param_info (gparam)->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0)
3531 return FALSE;
3533 if (gparam->gshared_constraint) {
3534 MonoClass *constraint_class = mono_class_from_mono_type_internal (gparam->gshared_constraint);
3535 return !m_class_is_blittable (constraint_class);
3538 if (mono_generic_param_owner (gparam)->is_anonymous)
3539 return FALSE;
3541 /* We could have: T : U, U : Base. So have to follow the constraints. */
3542 MonoClass *parent_class = mono_generic_param_get_base_type (klass);
3543 g_assert (!MONO_CLASS_IS_INTERFACE_INTERNAL (parent_class));
3544 /* Parent can only be: System.Object, System.ValueType or some specific base class.
3546 * If the parent_class is ValueType, the valuetype constraint would be set, above, so
3547 * we wouldn't get here.
3549 * If there was a reference constraint, the parent_class would be System.Object,
3550 * but we would have returned early above.
3552 * So if we get here, there is either no base class constraint at all,
3553 * in which case parent_class would be set to System.Object, or there is none at all.
3555 return parent_class != mono_defaults.object_class;
3559 * mono_class_layout_fields:
3560 * @class: a class
3561 * @base_instance_size: base instance size
3562 * @packing_size:
3564 * This contains the common code for computing the layout of classes and sizes.
3565 * This should only be called from mono_class_setup_fields () and
3566 * typebuilder_setup_fields ().
3568 * LOCKING: Acquires the loader lock
3570 void
3571 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int explicit_size, gboolean sre)
3573 int i;
3574 const int top = mono_class_get_field_count (klass);
3575 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
3576 guint32 pass, passes, real_size;
3577 gboolean gc_aware_layout = FALSE;
3578 gboolean has_static_fields = FALSE;
3579 gboolean has_references = FALSE;
3580 gboolean has_static_refs = FALSE;
3581 MonoClassField *field;
3582 gboolean blittable;
3583 int instance_size = base_instance_size;
3584 int element_size = -1;
3585 int class_size, min_align;
3586 int *field_offsets;
3587 gboolean *fields_has_references;
3590 * We want to avoid doing complicated work inside locks, so we compute all the required
3591 * information and write it to @klass inside a lock.
3593 if (klass->fields_inited)
3594 return;
3596 if ((packing_size & 0xffffff00) != 0) {
3597 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
3598 return;
3601 if (klass->parent) {
3602 min_align = klass->parent->min_align;
3603 /* we use | since it may have been set already */
3604 has_references = klass->has_references | klass->parent->has_references;
3605 } else {
3606 min_align = 1;
3608 /* We can't really enable 16 bytes alignment until the GC supports it.
3609 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3610 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3611 Bug #506144 is an example of this issue.
3613 if (klass->simd_type)
3614 min_align = 16;
3618 * When we do generic sharing we need to have layout
3619 * information for open generic classes (either with a generic
3620 * context containing type variables or with a generic
3621 * container), so we don't return in that case anymore.
3624 if (klass->enumtype) {
3625 for (i = 0; i < top; i++) {
3626 field = &klass->fields [i];
3627 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3628 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (field->type);
3629 break;
3633 if (!mono_class_enum_basetype_internal (klass)) {
3634 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
3635 return;
3640 * Enable GC aware auto layout: in this mode, reference
3641 * fields are grouped together inside objects, increasing collector
3642 * performance.
3643 * Requires that all classes whose layout is known to native code be annotated
3644 * with [StructLayout (LayoutKind.Sequential)]
3645 * Value types have gc_aware_layout disabled by default, as per
3646 * what the default is for other runtimes.
3648 /* corlib is missing [StructLayout] directives in many places */
3649 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
3650 if (!klass->valuetype)
3651 gc_aware_layout = TRUE;
3654 /* Compute klass->blittable */
3655 blittable = TRUE;
3656 if (klass->parent)
3657 blittable = klass->parent->blittable;
3658 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
3659 blittable = FALSE;
3660 for (i = 0; i < top; i++) {
3661 field = &klass->fields [i];
3663 if (mono_field_is_deleted (field))
3664 continue;
3665 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3666 continue;
3667 if (blittable) {
3668 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
3669 blittable = FALSE;
3670 } else if (mono_type_is_generic_parameter (field->type) &&
3671 mono_class_is_gparam_with_nonblittable_parent (mono_class_from_mono_type_internal (field->type))) {
3672 blittable = FALSE;
3673 } else {
3674 MonoClass *field_class = mono_class_from_mono_type_internal (field->type);
3675 if (field_class) {
3676 mono_class_setup_fields (field_class);
3677 if (mono_class_has_failure (field_class)) {
3678 ERROR_DECL (field_error);
3679 mono_error_set_for_class_failure (field_error, field_class);
3680 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (field_error));
3681 mono_error_cleanup (field_error);
3682 break;
3685 if (!field_class || !field_class->blittable)
3686 blittable = FALSE;
3689 if (klass->enumtype)
3690 blittable = klass->element_class->blittable;
3692 if (mono_class_has_failure (klass))
3693 return;
3694 if (klass == mono_defaults.string_class)
3695 blittable = FALSE;
3697 /* Compute klass->has_references */
3699 * Process non-static fields first, since static fields might recursively
3700 * refer to the class itself.
3702 for (i = 0; i < top; i++) {
3703 MonoType *ftype;
3705 field = &klass->fields [i];
3707 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3708 ftype = mono_type_get_underlying_type (field->type);
3709 ftype = mono_type_get_basic_type_from_generic (ftype);
3710 if (type_has_references (klass, ftype))
3711 has_references = TRUE;
3716 * Compute field layout and total size (not considering static fields)
3718 field_offsets = g_new0 (int, top);
3719 fields_has_references = g_new0 (gboolean, top);
3720 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
3721 switch (layout) {
3722 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
3723 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
3724 if (gc_aware_layout)
3725 passes = 2;
3726 else
3727 passes = 1;
3729 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
3730 passes = 1;
3732 if (klass->parent) {
3733 mono_class_setup_fields (klass->parent);
3734 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
3735 return;
3736 real_size = klass->parent->instance_size;
3737 } else {
3738 real_size = MONO_ABI_SIZEOF (MonoObject);
3741 for (pass = 0; pass < passes; ++pass) {
3742 for (i = 0; i < top; i++){
3743 gint32 align;
3744 guint32 size;
3745 MonoType *ftype;
3747 field = &klass->fields [i];
3749 if (mono_field_is_deleted (field))
3750 continue;
3751 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3752 continue;
3754 ftype = mono_type_get_underlying_type (field->type);
3755 ftype = mono_type_get_basic_type_from_generic (ftype);
3756 if (gc_aware_layout) {
3757 fields_has_references [i] = type_has_references (klass, ftype);
3758 if (fields_has_references [i]) {
3759 if (pass == 1)
3760 continue;
3761 } else {
3762 if (pass == 0)
3763 continue;
3767 if ((top == 1) && (instance_size == MONO_ABI_SIZEOF (MonoObject)) &&
3768 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
3769 /* This field is a hack inserted by MCS to empty structures */
3770 continue;
3773 size = mono_type_size (field->type, &align);
3775 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3776 align = packing_size ? MIN (packing_size, align): align;
3777 /* if the field has managed references, we need to force-align it
3778 * see bug #77788
3780 if (type_has_references (klass, ftype))
3781 align = MAX (align, TARGET_SIZEOF_VOID_P);
3783 min_align = MAX (align, min_align);
3784 field_offsets [i] = real_size;
3785 if (align) {
3786 field_offsets [i] += align - 1;
3787 field_offsets [i] &= ~(align - 1);
3789 /*TypeBuilders produce all sort of weird things*/
3790 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
3791 real_size = field_offsets [i] + size;
3794 instance_size = MAX (real_size, instance_size);
3796 if (instance_size & (min_align - 1)) {
3797 instance_size += min_align - 1;
3798 instance_size &= ~(min_align - 1);
3801 break;
3802 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
3803 guint8 *ref_bitmap;
3805 real_size = 0;
3806 for (i = 0; i < top; i++) {
3807 gint32 align;
3808 guint32 size;
3809 MonoType *ftype;
3811 field = &klass->fields [i];
3814 * There must be info about all the fields in a type if it
3815 * uses explicit layout.
3817 if (mono_field_is_deleted (field))
3818 continue;
3819 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3820 continue;
3822 size = mono_type_size (field->type, &align);
3823 align = packing_size ? MIN (packing_size, align): align;
3824 min_align = MAX (align, min_align);
3826 if (sre) {
3827 /* Already set by typebuilder_setup_fields () */
3828 field_offsets [i] = field->offset + MONO_ABI_SIZEOF (MonoObject);
3829 } else {
3830 int idx = first_field_idx + i;
3831 guint32 offset;
3832 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
3833 field_offsets [i] = offset + MONO_ABI_SIZEOF (MonoObject);
3835 ftype = mono_type_get_underlying_type (field->type);
3836 ftype = mono_type_get_basic_type_from_generic (ftype);
3837 if (type_has_references (klass, ftype)) {
3838 if (field_offsets [i] % TARGET_SIZEOF_VOID_P) {
3839 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
3844 * Calc max size.
3846 real_size = MAX (real_size, size + field_offsets [i]);
3849 if (klass->has_references) {
3850 ref_bitmap = g_new0 (guint8, real_size / TARGET_SIZEOF_VOID_P);
3852 /* Check for overlapping reference and non-reference fields */
3853 for (i = 0; i < top; i++) {
3854 MonoType *ftype;
3856 field = &klass->fields [i];
3858 if (mono_field_is_deleted (field))
3859 continue;
3860 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3861 continue;
3862 ftype = mono_type_get_underlying_type (field->type);
3863 if (MONO_TYPE_IS_REFERENCE (ftype))
3864 ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P] = 1;
3866 for (i = 0; i < top; i++) {
3867 field = &klass->fields [i];
3869 if (mono_field_is_deleted (field))
3870 continue;
3871 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3872 continue;
3874 // FIXME: Too much code does this
3875 #if 0
3876 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P]) {
3877 mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]);
3879 #endif
3881 g_free (ref_bitmap);
3884 instance_size = MAX (real_size, instance_size);
3885 if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) {
3886 if (instance_size & (min_align - 1)) {
3887 instance_size += min_align - 1;
3888 instance_size &= ~(min_align - 1);
3891 break;
3895 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
3897 * This leads to all kinds of problems with nested structs, so only
3898 * enable it when a MONO_DEBUG property is set.
3900 * For small structs, set min_align to at least the struct size to improve
3901 * performance, and since the JIT memset/memcpy code assumes this and generates
3902 * unaligned accesses otherwise. See #78990 for a testcase.
3904 if (mono_align_small_structs && top) {
3905 if (instance_size <= MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer))
3906 min_align = MAX (min_align, instance_size - MONO_ABI_SIZEOF (MonoObject));
3910 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3911 if (klass_byval_arg->type == MONO_TYPE_VAR || klass_byval_arg->type == MONO_TYPE_MVAR)
3912 instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_size (klass_byval_arg, &min_align);
3913 else if (klass_byval_arg->type == MONO_TYPE_PTR)
3914 instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
3916 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3917 element_size = mono_class_array_element_size (klass->element_class);
3919 /* Publish the data */
3920 mono_loader_lock ();
3921 if (klass->instance_size && !klass->image->dynamic) {
3922 /* Might be already set using cached info */
3923 if (klass->instance_size != instance_size) {
3924 /* Emit info to help debugging */
3925 g_print ("%s\n", mono_class_full_name (klass));
3926 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
3927 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
3928 g_print ("%d %d\n", klass->min_align, min_align);
3929 for (i = 0; i < top; ++i) {
3930 field = &klass->fields [i];
3931 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3932 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
3935 g_assert (klass->instance_size == instance_size);
3936 } else {
3937 klass->instance_size = instance_size;
3939 klass->blittable = blittable;
3940 klass->has_references = has_references;
3941 klass->packing_size = packing_size;
3942 klass->min_align = min_align;
3943 for (i = 0; i < top; ++i) {
3944 field = &klass->fields [i];
3945 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3946 klass->fields [i].offset = field_offsets [i];
3949 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3950 klass->sizes.element_size = element_size;
3952 mono_memory_barrier ();
3953 klass->size_inited = 1;
3954 mono_loader_unlock ();
3957 * Compute static field layout and size
3958 * Static fields can reference the class itself, so this has to be
3959 * done after instance_size etc. are initialized.
3961 class_size = 0;
3962 for (i = 0; i < top; i++) {
3963 gint32 align;
3964 guint32 size;
3966 field = &klass->fields [i];
3968 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3969 continue;
3970 if (mono_field_is_deleted (field))
3971 continue;
3973 if (mono_type_has_exceptions (field->type)) {
3974 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
3975 break;
3978 has_static_fields = TRUE;
3980 size = mono_type_size (field->type, &align);
3981 field_offsets [i] = class_size;
3982 /*align is always non-zero here*/
3983 field_offsets [i] += align - 1;
3984 field_offsets [i] &= ~(align - 1);
3985 class_size = field_offsets [i] + size;
3988 if (has_static_fields && class_size == 0)
3989 /* Simplify code which depends on class_size != 0 if the class has static fields */
3990 class_size = 8;
3992 /* Compute klass->has_static_refs */
3993 has_static_refs = FALSE;
3994 for (i = 0; i < top; i++) {
3995 MonoType *ftype;
3997 field = &klass->fields [i];
3999 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
4000 ftype = mono_type_get_underlying_type (field->type);
4001 ftype = mono_type_get_basic_type_from_generic (ftype);
4002 if (type_has_references (klass, ftype))
4003 has_static_refs = TRUE;
4007 /*valuetypes can't be neither bigger than 1Mb or empty. */
4008 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + MONO_ABI_SIZEOF (MonoObject)))) {
4009 /* Special case compiler generated types */
4010 /* Hard to check for [CompilerGenerated] here */
4011 if (!strstr (klass->name, "StaticArrayInitTypeSize") && !strstr (klass->name, "$ArrayType"))
4012 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
4015 // Weak field support
4017 // FIXME:
4018 // - generic instances
4019 // - Disallow on structs/static fields/nonref fields
4020 gboolean has_weak_fields = FALSE;
4022 if (mono_class_has_static_metadata (klass)) {
4023 for (MonoClass *p = klass; p != NULL; p = p->parent) {
4024 gpointer iter = NULL;
4025 guint32 first_field_idx = mono_class_get_first_field_idx (p);
4027 while ((field = mono_class_get_fields_internal (p, &iter))) {
4028 guint32 field_idx = first_field_idx + (field - p->fields);
4029 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
4030 has_weak_fields = TRUE;
4031 mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
4038 * Check that any fields of IsByRefLike type are instance
4039 * fields and only inside other IsByRefLike structs.
4041 * (Has to be done late because we call
4042 * mono_class_from_mono_type_internal which may recursively
4043 * refer to the current class)
4045 gboolean allow_isbyreflike_fields = m_class_is_byreflike (klass);
4046 for (i = 0; i < top; i++) {
4047 field = &klass->fields [i];
4049 if (mono_field_is_deleted (field))
4050 continue;
4051 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
4052 continue;
4053 MonoClass *field_class = NULL;
4054 /* have to be careful not to recursively invoke mono_class_init on a static field.
4055 * for example - if the field is an array of a subclass of klass, we can loop.
4057 switch (field->type->type) {
4058 case MONO_TYPE_TYPEDBYREF:
4059 case MONO_TYPE_VALUETYPE:
4060 case MONO_TYPE_GENERICINST:
4061 field_class = mono_class_from_mono_type_internal (field->type);
4062 break;
4063 default:
4064 break;
4066 if (!field_class || !m_class_is_byreflike (field_class))
4067 continue;
4068 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
4069 mono_class_set_type_load_failure (klass, "Static ByRefLike field '%s' is not allowed", field->name);
4070 return;
4071 } else {
4072 /* instance field */
4073 if (allow_isbyreflike_fields)
4074 continue;
4075 mono_class_set_type_load_failure (klass, "Instance ByRefLike field '%s' not in a ref struct", field->name);
4076 return;
4080 /* Publish the data */
4081 mono_loader_lock ();
4082 if (!klass->rank)
4083 klass->sizes.class_size = class_size;
4084 klass->has_static_refs = has_static_refs;
4085 klass->has_weak_fields = has_weak_fields;
4086 for (i = 0; i < top; ++i) {
4087 field = &klass->fields [i];
4089 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
4090 field->offset = field_offsets [i];
4092 mono_memory_barrier ();
4093 klass->fields_inited = 1;
4094 mono_loader_unlock ();
4096 g_free (field_offsets);
4097 g_free (fields_has_references);
4100 static int finalize_slot = -1;
4102 static void
4103 initialize_object_slots (MonoClass *klass)
4105 int i;
4107 if (klass != mono_defaults.object_class || finalize_slot >= 0)
4108 return;
4110 mono_class_setup_vtable (klass);
4112 for (i = 0; i < klass->vtable_size; ++i) {
4113 if (!strcmp (klass->vtable [i]->name, "Finalize")) {
4114 int const j = finalize_slot;
4115 g_assert (j == -1 || j == i);
4116 finalize_slot = i;
4120 g_assert (finalize_slot >= 0);
4124 mono_class_get_object_finalize_slot ()
4126 return finalize_slot;
4129 MonoMethod *
4130 mono_class_get_default_finalize_method ()
4132 int const i = finalize_slot;
4133 return (i < 0) ? NULL : mono_defaults.object_class->vtable [i];
4136 typedef struct {
4137 MonoMethod *array_method;
4138 char *name;
4139 } GenericArrayMethodInfo;
4141 static int generic_array_method_num = 0;
4142 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4144 static void
4145 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
4147 MonoGenericContext tmp_context;
4148 MonoGenericClass *gclass;
4149 int i;
4151 // The interface can sometimes be a GTD in cases like IList
4152 // See: https://github.com/mono/mono/issues/7095#issuecomment-470465597
4153 if (mono_class_is_gtd (iface)) {
4154 MonoType *ty = mono_class_gtd_get_canonical_inst (iface);
4155 g_assert (ty->type == MONO_TYPE_GENERICINST);
4156 gclass = ty->data.generic_class;
4157 } else
4158 gclass = mono_class_get_generic_class (iface);
4160 tmp_context.class_inst = NULL;
4161 tmp_context.method_inst = gclass->context.class_inst;
4162 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4164 for (i = 0; i < generic_array_method_num; i++) {
4165 ERROR_DECL (error);
4166 MonoMethod *m = generic_array_method_info [i].array_method;
4167 MonoMethod *inflated, *helper;
4169 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, error);
4170 mono_error_assert_ok (error);
4171 helper = (MonoMethod*)g_hash_table_lookup (cache, inflated);
4172 if (!helper) {
4173 helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
4174 g_hash_table_insert (cache, inflated, helper);
4176 methods [pos ++] = helper;
4180 static int
4181 generic_array_methods (MonoClass *klass)
4183 int i, count_generic = 0, mcount;
4184 GList *list = NULL, *tmp;
4185 if (generic_array_method_num)
4186 return generic_array_method_num;
4187 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4188 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4189 mcount = mono_class_get_method_count (klass->parent);
4190 for (i = 0; i < mcount; i++) {
4191 MonoMethod *m = klass->parent->methods [i];
4192 if (!strncmp (m->name, "InternalArray__", 15)) {
4193 count_generic++;
4194 list = g_list_prepend (list, m);
4197 list = g_list_reverse (list);
4198 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4199 i = 0;
4200 for (tmp = list; tmp; tmp = tmp->next) {
4201 const char *mname, *iname;
4202 gchar *name;
4203 MonoMethod *m = (MonoMethod *)tmp->data;
4204 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4205 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4207 generic_array_method_info [i].array_method = m;
4208 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4209 iname = "System.Collections.Generic.ICollection`1.";
4210 mname = m->name + 27;
4211 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4212 iname = "System.Collections.Generic.IEnumerable`1.";
4213 mname = m->name + 27;
4214 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4215 iname = "System.Collections.Generic.IReadOnlyList`1.";
4216 mname = m->name + strlen (ireadonlylist_prefix);
4217 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4218 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4219 mname = m->name + strlen (ireadonlycollection_prefix);
4220 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4221 iname = "System.Collections.Generic.IList`1.";
4222 mname = m->name + 15;
4223 } else {
4224 g_assert_not_reached ();
4227 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4228 strcpy (name, iname);
4229 strcpy (name + strlen (iname), mname);
4230 generic_array_method_info [i].name = name;
4231 i++;
4233 /*g_print ("array generic methods: %d\n", count_generic);*/
4235 generic_array_method_num = count_generic;
4236 g_list_free (list);
4237 return generic_array_method_num;
4241 * Global pool of interface IDs, represented as a bitset.
4242 * LOCKING: Protected by the classes lock.
4244 static MonoBitSet *global_interface_bitset = NULL;
4247 * mono_unload_interface_ids:
4248 * @bitset: bit set of interface IDs
4250 * When an image is unloaded, the interface IDs associated with
4251 * the image are put back in the global pool of IDs so the numbers
4252 * can be reused.
4254 void
4255 mono_unload_interface_ids (MonoBitSet *bitset)
4257 classes_lock ();
4258 mono_bitset_sub (global_interface_bitset, bitset);
4259 classes_unlock ();
4262 void
4263 mono_unload_interface_id (MonoClass *klass)
4265 if (global_interface_bitset && klass->interface_id) {
4266 classes_lock ();
4267 mono_bitset_clear (global_interface_bitset, klass->interface_id);
4268 classes_unlock ();
4273 * mono_get_unique_iid:
4274 * \param klass interface
4276 * Assign a unique integer ID to the interface represented by \p klass.
4277 * The ID will positive and as small as possible.
4278 * LOCKING: Acquires the classes lock.
4279 * \returns The new ID.
4281 static guint32
4282 mono_get_unique_iid (MonoClass *klass)
4284 int iid;
4286 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
4288 classes_lock ();
4290 if (!global_interface_bitset) {
4291 global_interface_bitset = mono_bitset_new (128, 0);
4292 mono_bitset_set (global_interface_bitset, 0); //don't let 0 be a valid iid
4295 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
4296 if (iid < 0) {
4297 int old_size = mono_bitset_size (global_interface_bitset);
4298 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
4299 mono_bitset_free (global_interface_bitset);
4300 global_interface_bitset = new_set;
4301 iid = old_size;
4303 mono_bitset_set (global_interface_bitset, iid);
4304 /* set the bit also in the per-image set */
4305 if (!mono_class_is_ginst (klass)) {
4306 if (klass->image->interface_bitset) {
4307 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
4308 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
4309 mono_bitset_free (klass->image->interface_bitset);
4310 klass->image->interface_bitset = new_set;
4312 } else {
4313 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
4315 mono_bitset_set (klass->image->interface_bitset, iid);
4318 classes_unlock ();
4320 #ifndef MONO_SMALL_CONFIG
4321 if (mono_print_vtable) {
4322 int generic_id;
4323 char *type_name = mono_type_full_name (m_class_get_byval_arg (klass));
4324 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
4325 if (gklass && !gklass->context.class_inst->is_open) {
4326 generic_id = gklass->context.class_inst->id;
4327 g_assert (generic_id != 0);
4328 } else {
4329 generic_id = 0;
4331 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->assembly_name, type_name, generic_id);
4332 g_free (type_name);
4334 #endif
4336 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4337 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4338 g_assert (iid < INT_MAX);
4339 return iid;
4343 * mono_class_init_internal:
4344 * \param klass the class to initialize
4346 * Compute the \c instance_size, \c class_size and other infos that cannot be
4347 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4348 * Initializes the following fields in \p klass:
4349 * - all the fields initialized by \c mono_class_init_sizes
4350 * - has_cctor
4351 * - ghcimpl
4352 * - inited
4354 * LOCKING: Acquires the loader lock.
4356 * \returns TRUE on success or FALSE if there was a problem in loading
4357 * the type (incorrect assemblies, missing assemblies, methods, etc).
4359 gboolean
4360 mono_class_init_internal (MonoClass *klass)
4362 int i, vtable_size = 0, array_method_count = 0;
4363 MonoCachedClassInfo cached_info;
4364 gboolean has_cached_info;
4365 gboolean locked = FALSE;
4366 gboolean ghcimpl = FALSE;
4367 gboolean has_cctor = FALSE;
4368 int first_iface_slot = 0;
4370 g_assert (klass);
4372 /* Double-checking locking pattern */
4373 if (klass->inited || mono_class_has_failure (klass))
4374 return !mono_class_has_failure (klass);
4376 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4379 * This function can recursively call itself.
4381 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
4382 if (g_slist_find (init_list, klass)) {
4383 mono_class_set_type_load_failure (klass, "Recursive type definition detected %s.%s", klass->name_space, klass->name);
4384 goto leave_no_init_pending;
4386 init_list = g_slist_prepend (init_list, klass);
4387 mono_native_tls_set_value (init_pending_tls_id, init_list);
4390 * We want to avoid doing complicated work inside locks, so we compute all the required
4391 * information and write it to @klass inside a lock.
4394 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
4395 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
4396 goto leave;
4399 MonoType *klass_byval_arg;
4400 klass_byval_arg = m_class_get_byval_arg (klass);
4401 if (klass_byval_arg->type == MONO_TYPE_ARRAY || klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4402 MonoClass *element_class = klass->element_class;
4403 MonoClass *cast_class = klass->cast_class;
4405 if (!element_class->inited)
4406 mono_class_init_internal (element_class);
4407 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
4408 goto leave;
4409 if (!cast_class->inited)
4410 mono_class_init_internal (cast_class);
4411 if (mono_class_set_type_load_failure_causedby_class (klass, cast_class, "Could not load array cast class"))
4412 goto leave;
4415 UnlockedIncrement (&mono_stats.initialized_class_count);
4417 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
4418 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4420 mono_class_init_internal (gklass);
4421 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
4422 goto leave;
4424 mono_loader_lock ();
4425 mono_class_setup_interface_id_internal (klass);
4426 mono_loader_unlock ();
4429 if (klass->parent && !klass->parent->inited)
4430 mono_class_init_internal (klass->parent);
4432 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
4434 /* Compute instance size etc. */
4435 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
4436 if (mono_class_has_failure (klass))
4437 goto leave;
4439 mono_class_setup_supertypes (klass);
4441 initialize_object_slots (klass);
4444 * Initialize the rest of the data without creating a generic vtable if possible.
4445 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4446 * also avoid computing a generic vtable.
4448 if (has_cached_info) {
4449 /* AOT case */
4450 vtable_size = cached_info.vtable_size;
4451 ghcimpl = cached_info.ghcimpl;
4452 has_cctor = cached_info.has_cctor;
4453 } else if (klass->rank == 1 && klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4454 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4455 * The first slot if for array with.
4457 static int szarray_vtable_size[3] = { 0 };
4459 int slot;
4461 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass))))
4462 slot = 0;
4463 else if (klass->element_class->enumtype)
4464 slot = 1;
4465 else
4466 slot = 2;
4468 /* SZARRAY case */
4469 if (!szarray_vtable_size [slot]) {
4470 mono_class_setup_vtable (klass);
4471 szarray_vtable_size [slot] = klass->vtable_size;
4472 vtable_size = klass->vtable_size;
4473 } else {
4474 vtable_size = szarray_vtable_size[slot];
4476 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4477 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4479 /* Generic instance case */
4480 ghcimpl = gklass->ghcimpl;
4481 has_cctor = gklass->has_cctor;
4483 mono_class_setup_vtable (gklass);
4484 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
4485 goto leave;
4487 vtable_size = gklass->vtable_size;
4488 } else {
4489 /* General case */
4491 /* C# doesn't allow interfaces to have cctors */
4492 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->image != mono_defaults.corlib) {
4493 MonoMethod *cmethod = NULL;
4495 if (mono_class_is_ginst (klass)) {
4496 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4498 /* Generic instance case */
4499 ghcimpl = gklass->ghcimpl;
4500 has_cctor = gklass->has_cctor;
4501 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
4502 cmethod = mono_find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
4503 /* The find_method function ignores the 'flags' argument */
4504 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
4505 has_cctor = 1;
4506 } else {
4507 mono_class_setup_methods (klass);
4508 if (mono_class_has_failure (klass))
4509 goto leave;
4511 int mcount = mono_class_get_method_count (klass);
4512 for (i = 0; i < mcount; ++i) {
4513 MonoMethod *method = klass->methods [i];
4514 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
4515 (strcmp (".cctor", method->name) == 0)) {
4516 has_cctor = 1;
4517 break;
4524 if (klass->rank) {
4525 array_method_count = 3 + (klass->rank > 1? 2: 1);
4527 if (klass->interface_count) {
4528 int count_generic = generic_array_methods (klass);
4529 array_method_count += klass->interface_count * count_generic;
4533 if (klass->parent) {
4534 if (!klass->parent->vtable_size)
4535 mono_class_setup_vtable (klass->parent);
4536 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
4537 goto leave;
4538 g_assert (klass->parent->vtable_size);
4539 first_iface_slot = klass->parent->vtable_size;
4540 if (mono_class_need_stelemref_method (klass))
4541 ++first_iface_slot;
4545 * Do the actual changes to @klass inside the loader lock
4547 mono_loader_lock ();
4548 locked = TRUE;
4550 if (klass->inited || mono_class_has_failure (klass)) {
4551 /* Somebody might have gotten in before us */
4552 goto leave;
4555 UnlockedIncrement (&mono_stats.initialized_class_count);
4557 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
4558 UnlockedIncrement (&mono_stats.generic_class_count);
4560 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
4561 klass->nested_classes_inited = TRUE;
4562 klass->ghcimpl = ghcimpl;
4563 klass->has_cctor = has_cctor;
4564 if (vtable_size)
4565 klass->vtable_size = vtable_size;
4566 if (has_cached_info) {
4567 klass->has_finalize = cached_info.has_finalize;
4568 klass->has_finalize_inited = TRUE;
4570 if (klass->rank)
4571 mono_class_set_method_count (klass, array_method_count);
4573 mono_loader_unlock ();
4574 locked = FALSE;
4576 setup_interface_offsets (klass, first_iface_slot, TRUE);
4578 if (mono_security_core_clr_enabled ())
4579 mono_security_core_clr_check_inheritance (klass);
4581 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
4582 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
4584 goto leave;
4586 leave:
4587 init_list = (GSList*)mono_native_tls_get_value (init_pending_tls_id);
4588 init_list = g_slist_remove (init_list, klass);
4589 mono_native_tls_set_value (init_pending_tls_id, init_list);
4591 leave_no_init_pending:
4592 if (locked)
4593 mono_loader_unlock ();
4595 /* Leave this for last */
4596 mono_loader_lock ();
4597 klass->inited = 1;
4598 mono_loader_unlock ();
4600 return !mono_class_has_failure (klass);
4603 gboolean
4604 mono_class_init_checked (MonoClass *klass, MonoError *error)
4606 error_init (error);
4607 gboolean const success = mono_class_init_internal (klass);
4608 if (!success)
4609 mono_error_set_for_class_failure (error, klass);
4610 return success;
4613 #ifndef DISABLE_COM
4615 * COM initialization is delayed until needed.
4616 * However when a [ComImport] attribute is present on a type it will trigger
4617 * the initialization. This is not a problem unless the BCL being executed
4618 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4620 static void
4621 init_com_from_comimport (MonoClass *klass)
4623 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4624 if (mono_security_core_clr_enabled ()) {
4625 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4626 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
4627 /* but it can not be made available for application (i.e. user code) since all COM calls
4628 * are considered native calls. In this case we fail with a TypeLoadException (just like
4629 * Silverlight 2 does */
4630 mono_class_set_type_load_failure (klass, "");
4631 return;
4635 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4637 #endif /*DISABLE_COM*/
4640 * LOCKING: this assumes the loader lock is held
4642 void
4643 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
4645 gboolean system_namespace;
4646 gboolean is_corlib = mono_is_corlib_image (klass->image);
4648 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
4650 /* if root of the hierarchy */
4651 if (system_namespace && !strcmp (klass->name, "Object")) {
4652 klass->parent = NULL;
4653 klass->instance_size = MONO_ABI_SIZEOF (MonoObject);
4654 return;
4656 if (!strcmp (klass->name, "<Module>")) {
4657 klass->parent = NULL;
4658 klass->instance_size = 0;
4659 return;
4662 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4663 /* Imported COM Objects always derive from __ComObject. */
4664 #ifndef DISABLE_COM
4665 if (MONO_CLASS_IS_IMPORT (klass)) {
4666 init_com_from_comimport (klass);
4667 if (parent == mono_defaults.object_class)
4668 parent = mono_class_get_com_object_class ();
4670 #endif
4671 if (!parent) {
4672 /* set the parent to something useful and safe, but mark the type as broken */
4673 parent = mono_defaults.object_class;
4674 mono_class_set_type_load_failure (klass, "");
4675 g_assert (parent);
4678 klass->parent = parent;
4680 if (mono_class_is_ginst (parent) && !parent->name) {
4682 * If the parent is a generic instance, we may get
4683 * called before it is fully initialized, especially
4684 * before it has its name.
4686 return;
4689 #ifndef DISABLE_REMOTING
4690 klass->marshalbyref = parent->marshalbyref;
4691 klass->contextbound = parent->contextbound;
4692 #endif
4694 klass->delegate = parent->delegate;
4696 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
4697 mono_class_set_is_com_object (klass);
4699 if (system_namespace) {
4700 #ifndef DISABLE_REMOTING
4701 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
4702 klass->marshalbyref = 1;
4704 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
4705 klass->contextbound = 1;
4706 #endif
4707 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
4708 klass->delegate = 1;
4711 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
4712 (strcmp (klass->parent->name_space, "System") == 0)))
4713 klass->valuetype = 1;
4714 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
4715 klass->valuetype = klass->enumtype = 1;
4717 /*klass->enumtype = klass->parent->enumtype; */
4718 } else {
4719 /* initialize com types if COM interfaces are present */
4720 #ifndef DISABLE_COM
4721 if (MONO_CLASS_IS_IMPORT (klass))
4722 init_com_from_comimport (klass);
4723 #endif
4724 klass->parent = NULL;
4729 /* Locking: must be called with the loader lock held. */
4730 static void
4731 mono_class_setup_interface_id_internal (MonoClass *klass)
4733 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->interface_id)
4734 return;
4735 klass->interface_id = mono_get_unique_iid (klass);
4737 if (mono_is_corlib_image (klass->image) && !strcmp (m_class_get_name_space (klass), "System.Collections.Generic")) {
4738 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4739 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4740 * MS returns diferrent types based on which instance is called. For example:
4741 * object obj = new byte[10][];
4742 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4743 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4744 * a != b ==> true
4746 const char *name = m_class_get_name (klass);
4747 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
4748 klass->is_array_special_interface = 1;
4754 * LOCKING: this assumes the loader lock is held
4756 void
4757 mono_class_setup_mono_type (MonoClass *klass)
4759 const char *name = klass->name;
4760 const char *nspace = klass->name_space;
4761 gboolean is_corlib = mono_is_corlib_image (klass->image);
4763 klass->this_arg.byref = 1;
4764 klass->this_arg.data.klass = klass;
4765 klass->this_arg.type = MONO_TYPE_CLASS;
4766 klass->_byval_arg.data.klass = klass;
4767 klass->_byval_arg.type = MONO_TYPE_CLASS;
4769 if (is_corlib && !strcmp (nspace, "System")) {
4770 if (!strcmp (name, "ValueType")) {
4772 * do not set the valuetype bit for System.ValueType.
4773 * klass->valuetype = 1;
4775 klass->blittable = TRUE;
4776 } else if (!strcmp (name, "Enum")) {
4778 * do not set the valuetype bit for System.Enum.
4779 * klass->valuetype = 1;
4781 klass->valuetype = 0;
4782 klass->enumtype = 0;
4783 } else if (!strcmp (name, "Object")) {
4784 klass->_byval_arg.type = MONO_TYPE_OBJECT;
4785 klass->this_arg.type = MONO_TYPE_OBJECT;
4786 } else if (!strcmp (name, "String")) {
4787 klass->_byval_arg.type = MONO_TYPE_STRING;
4788 klass->this_arg.type = MONO_TYPE_STRING;
4789 } else if (!strcmp (name, "TypedReference")) {
4790 klass->_byval_arg.type = MONO_TYPE_TYPEDBYREF;
4791 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
4795 if (klass->valuetype) {
4796 int t = MONO_TYPE_VALUETYPE;
4798 if (is_corlib && !strcmp (nspace, "System")) {
4799 switch (*name) {
4800 case 'B':
4801 if (!strcmp (name, "Boolean")) {
4802 t = MONO_TYPE_BOOLEAN;
4803 } else if (!strcmp(name, "Byte")) {
4804 t = MONO_TYPE_U1;
4805 klass->blittable = TRUE;
4807 break;
4808 case 'C':
4809 if (!strcmp (name, "Char")) {
4810 t = MONO_TYPE_CHAR;
4812 break;
4813 case 'D':
4814 if (!strcmp (name, "Double")) {
4815 t = MONO_TYPE_R8;
4816 klass->blittable = TRUE;
4818 break;
4819 case 'I':
4820 if (!strcmp (name, "Int32")) {
4821 t = MONO_TYPE_I4;
4822 klass->blittable = TRUE;
4823 } else if (!strcmp(name, "Int16")) {
4824 t = MONO_TYPE_I2;
4825 klass->blittable = TRUE;
4826 } else if (!strcmp(name, "Int64")) {
4827 t = MONO_TYPE_I8;
4828 klass->blittable = TRUE;
4829 } else if (!strcmp(name, "IntPtr")) {
4830 t = MONO_TYPE_I;
4831 klass->blittable = TRUE;
4833 break;
4834 case 'S':
4835 if (!strcmp (name, "Single")) {
4836 t = MONO_TYPE_R4;
4837 klass->blittable = TRUE;
4838 } else if (!strcmp(name, "SByte")) {
4839 t = MONO_TYPE_I1;
4840 klass->blittable = TRUE;
4842 break;
4843 case 'U':
4844 if (!strcmp (name, "UInt32")) {
4845 t = MONO_TYPE_U4;
4846 klass->blittable = TRUE;
4847 } else if (!strcmp(name, "UInt16")) {
4848 t = MONO_TYPE_U2;
4849 klass->blittable = TRUE;
4850 } else if (!strcmp(name, "UInt64")) {
4851 t = MONO_TYPE_U8;
4852 klass->blittable = TRUE;
4853 } else if (!strcmp(name, "UIntPtr")) {
4854 t = MONO_TYPE_U;
4855 klass->blittable = TRUE;
4857 break;
4858 case 'T':
4859 if (!strcmp (name, "TypedReference")) {
4860 t = MONO_TYPE_TYPEDBYREF;
4861 klass->blittable = TRUE;
4863 break;
4864 case 'V':
4865 if (!strcmp (name, "Void")) {
4866 t = MONO_TYPE_VOID;
4868 break;
4869 default:
4870 break;
4873 klass->_byval_arg.type = (MonoTypeEnum)t;
4874 klass->this_arg.type = (MonoTypeEnum)t;
4877 mono_class_setup_interface_id_internal (klass);
4880 static MonoMethod*
4881 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
4883 MonoMethod *method;
4885 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
4886 method->klass = klass;
4887 method->flags = METHOD_ATTRIBUTE_PUBLIC;
4888 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
4889 method->signature = sig;
4890 method->name = name;
4891 method->slot = -1;
4892 /* .ctor */
4893 if (name [0] == '.') {
4894 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
4895 } else {
4896 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
4898 return method;
4902 * mono_class_setup_methods:
4903 * @class: a class
4905 * Initializes the 'methods' array in CLASS.
4906 * Calling this method should be avoided if possible since it allocates a lot
4907 * of long-living MonoMethod structures.
4908 * Methods belonging to an interface are assigned a sequential slot starting
4909 * from 0.
4911 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4913 void
4914 mono_class_setup_methods (MonoClass *klass)
4916 int i, count;
4917 MonoMethod **methods;
4919 if (klass->methods)
4920 return;
4922 if (mono_class_is_ginst (klass)) {
4923 ERROR_DECL (error);
4924 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4926 mono_class_init_internal (gklass);
4927 if (!mono_class_has_failure (gklass))
4928 mono_class_setup_methods (gklass);
4929 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
4930 return;
4932 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4933 count = mono_class_get_method_count (gklass);
4934 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
4936 for (i = 0; i < count; i++) {
4937 methods [i] = mono_class_inflate_generic_method_full_checked (
4938 gklass->methods [i], klass, mono_class_get_context (klass), error);
4939 if (!is_ok (error)) {
4940 char *method = mono_method_full_name (gklass->methods [i], TRUE);
4941 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (error));
4943 g_free (method);
4944 mono_error_cleanup (error);
4945 return;
4948 } else if (klass->rank) {
4949 ERROR_DECL (error);
4950 MonoMethod *amethod;
4951 MonoMethodSignature *sig;
4952 int count_generic = 0, first_generic = 0;
4953 int method_num = 0;
4954 gboolean jagged_ctor = FALSE;
4956 count = 3 + (klass->rank > 1? 2: 1);
4958 mono_class_setup_interfaces (klass, error);
4959 g_assert (is_ok (error)); /*FIXME can this fail for array types?*/
4961 if (klass->rank == 1 && klass->element_class->rank) {
4962 jagged_ctor = TRUE;
4963 count ++;
4966 if (klass->interface_count) {
4967 count_generic = generic_array_methods (klass);
4968 first_generic = count;
4969 count += klass->interface_count * count_generic;
4972 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
4974 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4975 sig->ret = mono_get_void_type ();
4976 sig->pinvoke = TRUE;
4977 sig->hasthis = TRUE;
4978 for (i = 0; i < klass->rank; ++i)
4979 sig->params [i] = mono_get_int32_type ();
4981 amethod = create_array_method (klass, ".ctor", sig);
4982 methods [method_num++] = amethod;
4983 if (klass->rank > 1) {
4984 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
4985 sig->ret = mono_get_void_type ();
4986 sig->pinvoke = TRUE;
4987 sig->hasthis = TRUE;
4988 for (i = 0; i < klass->rank * 2; ++i)
4989 sig->params [i] = mono_get_int32_type ();
4991 amethod = create_array_method (klass, ".ctor", sig);
4992 methods [method_num++] = amethod;
4995 if (jagged_ctor) {
4996 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4997 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4998 sig->ret = mono_get_void_type ();
4999 sig->pinvoke = TRUE;
5000 sig->hasthis = TRUE;
5001 for (i = 0; i < klass->rank + 1; ++i)
5002 sig->params [i] = mono_get_int32_type ();
5003 amethod = create_array_method (klass, ".ctor", sig);
5004 methods [method_num++] = amethod;
5007 /* element Get (idx11, [idx2, ...]) */
5008 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
5009 sig->ret = m_class_get_byval_arg (m_class_get_element_class (klass));
5010 sig->pinvoke = TRUE;
5011 sig->hasthis = TRUE;
5012 for (i = 0; i < klass->rank; ++i)
5013 sig->params [i] = mono_get_int32_type ();
5014 amethod = create_array_method (klass, "Get", sig);
5015 methods [method_num++] = amethod;
5016 /* element& Address (idx11, [idx2, ...]) */
5017 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
5018 sig->ret = &klass->element_class->this_arg;
5019 sig->pinvoke = TRUE;
5020 sig->hasthis = TRUE;
5021 for (i = 0; i < klass->rank; ++i)
5022 sig->params [i] = mono_get_int32_type ();
5023 amethod = create_array_method (klass, "Address", sig);
5024 methods [method_num++] = amethod;
5025 /* void Set (idx11, [idx2, ...], element) */
5026 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
5027 sig->ret = mono_get_void_type ();
5028 sig->pinvoke = TRUE;
5029 sig->hasthis = TRUE;
5030 for (i = 0; i < klass->rank; ++i)
5031 sig->params [i] = mono_get_int32_type ();
5032 sig->params [i] = m_class_get_byval_arg (m_class_get_element_class (klass));
5033 amethod = create_array_method (klass, "Set", sig);
5034 methods [method_num++] = amethod;
5036 GHashTable *cache = g_hash_table_new (NULL, NULL);
5037 for (i = 0; i < klass->interface_count; i++)
5038 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
5039 g_hash_table_destroy (cache);
5040 } else if (mono_class_has_static_metadata (klass)) {
5041 ERROR_DECL (error);
5042 int first_idx = mono_class_get_first_method_idx (klass);
5044 count = mono_class_get_method_count (klass);
5045 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
5046 for (i = 0; i < count; ++i) {
5047 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
5048 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, error);
5049 if (!methods [i]) {
5050 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (error));
5051 mono_error_cleanup (error);
5054 } else {
5055 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
5056 count = 0;
5059 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
5060 int slot = 0;
5061 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
5062 for (i = 0; i < count; ++i) {
5063 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
5065 if (method_is_reabstracted (methods[i]->flags)) {
5066 methods [i]->is_reabstracted = 1;
5067 continue;
5069 methods [i]->slot = slot++;
5074 mono_image_lock (klass->image);
5076 if (!klass->methods) {
5077 mono_class_set_method_count (klass, count);
5079 /* Needed because of the double-checking locking pattern */
5080 mono_memory_barrier ();
5082 klass->methods = methods;
5085 mono_image_unlock (klass->image);
5089 * mono_class_setup_properties:
5091 * Initialize klass->ext.property and klass->ext.properties.
5093 * This method can fail the class.
5095 void
5096 mono_class_setup_properties (MonoClass *klass)
5098 guint startm, endm, i, j;
5099 guint32 cols [MONO_PROPERTY_SIZE];
5100 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5101 MonoProperty *properties;
5102 guint32 last;
5103 int first, count;
5104 MonoClassPropertyInfo *info;
5106 info = mono_class_get_property_info (klass);
5107 if (info)
5108 return;
5110 if (mono_class_is_ginst (klass)) {
5111 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5113 mono_class_init_internal (gklass);
5114 mono_class_setup_properties (gklass);
5115 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5116 return;
5118 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
5119 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
5121 for (i = 0; i < ginfo->count; i++) {
5122 ERROR_DECL (error);
5123 MonoProperty *prop = &properties [i];
5125 *prop = ginfo->properties [i];
5127 if (prop->get)
5128 prop->get = mono_class_inflate_generic_method_full_checked (
5129 prop->get, klass, mono_class_get_context (klass), error);
5130 if (prop->set)
5131 prop->set = mono_class_inflate_generic_method_full_checked (
5132 prop->set, klass, mono_class_get_context (klass), error);
5134 g_assert (is_ok (error)); /*FIXME proper error handling*/
5135 prop->parent = klass;
5138 first = ginfo->first;
5139 count = ginfo->count;
5140 } else {
5141 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5142 count = last - first;
5144 if (count) {
5145 mono_class_setup_methods (klass);
5146 if (mono_class_has_failure (klass))
5147 return;
5150 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
5151 for (i = first; i < last; ++i) {
5152 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
5153 properties [i - first].parent = klass;
5154 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
5155 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
5157 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
5158 int first_idx = mono_class_get_first_method_idx (klass);
5159 for (j = startm; j < endm; ++j) {
5160 MonoMethod *method;
5162 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5164 if (klass->image->uncompressed_metadata) {
5165 ERROR_DECL (error);
5166 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5167 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5168 mono_error_cleanup (error); /* FIXME don't swallow this error */
5169 } else {
5170 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5173 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5174 case METHOD_SEMANTIC_SETTER:
5175 properties [i - first].set = method;
5176 break;
5177 case METHOD_SEMANTIC_GETTER:
5178 properties [i - first].get = method;
5179 break;
5180 default:
5181 break;
5187 info = (MonoClassPropertyInfo*)mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
5188 info->first = first;
5189 info->count = count;
5190 info->properties = properties;
5191 mono_memory_barrier ();
5193 /* This might leak 'info' which was allocated from the image mempool */
5194 mono_class_set_property_info (klass, info);
5197 static MonoMethod**
5198 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
5200 MonoMethod **om, **retval;
5201 int count;
5203 for (om = methods, count = 0; *om; ++om, ++count)
5206 retval = g_new0 (MonoMethod*, count + 1);
5207 count = 0;
5208 for (om = methods, count = 0; *om; ++om, ++count) {
5209 ERROR_DECL (error);
5210 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, error);
5211 g_assert (is_ok (error)); /*FIXME proper error handling*/
5214 return retval;
5217 /*This method can fail the class.*/
5218 void
5219 mono_class_setup_events (MonoClass *klass)
5221 int first, count;
5222 guint startm, endm, i, j;
5223 guint32 cols [MONO_EVENT_SIZE];
5224 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5225 guint32 last;
5226 MonoEvent *events;
5228 MonoClassEventInfo *info = mono_class_get_event_info (klass);
5229 if (info)
5230 return;
5232 if (mono_class_is_ginst (klass)) {
5233 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5234 MonoGenericContext *context = NULL;
5236 mono_class_setup_events (gklass);
5237 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5238 return;
5240 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
5241 first = ginfo->first;
5242 count = ginfo->count;
5244 events = mono_class_new0 (klass, MonoEvent, count);
5246 if (count)
5247 context = mono_class_get_context (klass);
5249 for (i = 0; i < count; i++) {
5250 ERROR_DECL (error);
5251 MonoEvent *event = &events [i];
5252 MonoEvent *gevent = &ginfo->events [i];
5254 event->parent = klass;
5255 event->name = gevent->name;
5256 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, error) : NULL;
5257 g_assert (is_ok (error)); /*FIXME proper error handling*/
5258 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, error) : NULL;
5259 g_assert (is_ok (error)); /*FIXME proper error handling*/
5260 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, error) : NULL;
5261 g_assert (is_ok (error)); /*FIXME proper error handling*/
5263 #ifndef MONO_SMALL_CONFIG
5264 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
5265 #endif
5266 event->attrs = gevent->attrs;
5268 } else {
5269 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5270 count = last - first;
5272 if (count) {
5273 mono_class_setup_methods (klass);
5274 if (mono_class_has_failure (klass)) {
5275 return;
5279 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
5280 for (i = first; i < last; ++i) {
5281 MonoEvent *event = &events [i - first];
5283 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
5284 event->parent = klass;
5285 event->attrs = cols [MONO_EVENT_FLAGS];
5286 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
5288 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
5289 int first_idx = mono_class_get_first_method_idx (klass);
5290 for (j = startm; j < endm; ++j) {
5291 MonoMethod *method;
5293 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5295 if (klass->image->uncompressed_metadata) {
5296 ERROR_DECL (error);
5297 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5298 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5299 mono_error_cleanup (error); /* FIXME don't swallow this error */
5300 } else {
5301 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5304 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5305 case METHOD_SEMANTIC_ADD_ON:
5306 event->add = method;
5307 break;
5308 case METHOD_SEMANTIC_REMOVE_ON:
5309 event->remove = method;
5310 break;
5311 case METHOD_SEMANTIC_FIRE:
5312 event->raise = method;
5313 break;
5314 case METHOD_SEMANTIC_OTHER: {
5315 #ifndef MONO_SMALL_CONFIG
5316 int n = 0;
5318 if (event->other == NULL) {
5319 event->other = g_new0 (MonoMethod*, 2);
5320 } else {
5321 while (event->other [n])
5322 n++;
5323 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
5325 event->other [n] = method;
5326 /* NULL terminated */
5327 event->other [n + 1] = NULL;
5328 #endif
5329 break;
5331 default:
5332 break;
5338 info = (MonoClassEventInfo*)mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
5339 info->events = events;
5340 info->first = first;
5341 info->count = count;
5343 mono_memory_barrier ();
5345 mono_class_set_event_info (klass, info);
5350 * mono_class_setup_interface_id:
5352 * Initializes MonoClass::interface_id if required.
5354 * LOCKING: Acquires the loader lock.
5356 void
5357 mono_class_setup_interface_id (MonoClass *klass)
5359 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
5360 mono_loader_lock ();
5361 mono_class_setup_interface_id_internal (klass);
5362 mono_loader_unlock ();
5366 * mono_class_setup_interfaces:
5368 * Initialize klass->interfaces/interfaces_count.
5369 * LOCKING: Acquires the loader lock.
5370 * This function can fail the type.
5372 void
5373 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
5375 int i, interface_count;
5376 MonoClass **interfaces;
5378 error_init (error);
5380 if (klass->interfaces_inited)
5381 return;
5383 if (klass->rank == 1 && m_class_get_byval_arg (klass)->type != MONO_TYPE_ARRAY) {
5384 MonoType *args [1];
5386 /* IList and IReadOnlyList -> 2x if enum*/
5387 interface_count = klass->element_class->enumtype ? 4 : 2;
5388 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
5390 args [0] = m_class_get_byval_arg (m_class_get_element_class (klass));
5391 interfaces [0] = mono_class_bind_generic_parameters (
5392 mono_defaults.generic_ilist_class, 1, args, FALSE);
5393 interfaces [1] = mono_class_bind_generic_parameters (
5394 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5395 if (klass->element_class->enumtype) {
5396 args [0] = mono_class_enum_basetype_internal (klass->element_class);
5397 interfaces [2] = mono_class_bind_generic_parameters (
5398 mono_defaults.generic_ilist_class, 1, args, FALSE);
5399 interfaces [3] = mono_class_bind_generic_parameters (
5400 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5402 } else if (mono_class_is_ginst (klass)) {
5403 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5405 mono_class_setup_interfaces (gklass, error);
5406 if (!is_ok (error)) {
5407 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5408 return;
5411 interface_count = gklass->interface_count;
5412 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
5413 for (i = 0; i < interface_count; i++) {
5414 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
5415 if (!is_ok (error)) {
5416 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5417 return;
5420 } else {
5421 interface_count = 0;
5422 interfaces = NULL;
5425 mono_loader_lock ();
5426 if (!klass->interfaces_inited) {
5427 klass->interface_count = interface_count;
5428 klass->interfaces = interfaces;
5430 mono_memory_barrier ();
5432 klass->interfaces_inited = TRUE;
5434 mono_loader_unlock ();
5439 * mono_class_setup_has_finalizer:
5441 * Initialize klass->has_finalizer if it isn't already initialized.
5443 * LOCKING: Acquires the loader lock.
5445 void
5446 mono_class_setup_has_finalizer (MonoClass *klass)
5448 gboolean has_finalize = FALSE;
5450 if (m_class_is_has_finalize_inited (klass))
5451 return;
5453 /* Interfaces and valuetypes are not supposed to have finalizers */
5454 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_is_valuetype (klass))) {
5455 MonoMethod *cmethod = NULL;
5457 if (m_class_get_rank (klass) == 1 && m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
5458 } else if (mono_class_is_ginst (klass)) {
5459 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5461 has_finalize = mono_class_has_finalizer (gklass);
5462 } else if (m_class_get_parent (klass) && m_class_has_finalize (m_class_get_parent (klass))) {
5463 has_finalize = TRUE;
5464 } else {
5465 if (m_class_get_parent (klass)) {
5467 * Can't search in metadata for a method named Finalize, because that
5468 * ignores overrides.
5470 mono_class_setup_vtable (klass);
5471 if (mono_class_has_failure (klass))
5472 cmethod = NULL;
5473 else
5474 cmethod = m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
5477 if (cmethod) {
5478 g_assert (m_class_get_vtable_size (klass) > mono_class_get_object_finalize_slot ());
5480 if (m_class_get_parent (klass)) {
5481 if (cmethod->is_inflated)
5482 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5483 if (cmethod != mono_class_get_default_finalize_method ())
5484 has_finalize = TRUE;
5490 mono_loader_lock ();
5491 if (!m_class_is_has_finalize_inited (klass)) {
5492 klass->has_finalize = has_finalize ? 1 : 0;
5494 mono_memory_barrier ();
5495 klass->has_finalize_inited = TRUE;
5497 mono_loader_unlock ();
5501 * mono_class_setup_supertypes:
5502 * @class: a class
5504 * Build the data structure needed to make fast type checks work.
5505 * This currently sets two fields in @class:
5506 * - idepth: distance between @class and System.Object in the type
5507 * hierarchy + 1
5508 * - supertypes: array of classes: each element has a class in the hierarchy
5509 * starting from @class up to System.Object
5511 * LOCKING: Acquires the loader lock.
5513 void
5514 mono_class_setup_supertypes (MonoClass *klass)
5516 int ms, idepth;
5517 MonoClass **supertypes;
5519 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5520 if (supertypes)
5521 return;
5523 if (klass->parent && !klass->parent->supertypes)
5524 mono_class_setup_supertypes (klass->parent);
5525 if (klass->parent)
5526 idepth = klass->parent->idepth + 1;
5527 else
5528 idepth = 1;
5530 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5531 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5533 if (klass->parent) {
5534 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5536 int supertype_idx;
5537 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5538 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5539 } else {
5540 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5543 mono_memory_barrier ();
5545 mono_loader_lock ();
5546 klass->idepth = idepth;
5547 /* Needed so idepth is visible before supertypes is set */
5548 mono_memory_barrier ();
5549 klass->supertypes = supertypes;
5550 mono_loader_unlock ();
5553 /* mono_class_setup_nested_types:
5555 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5557 * LOCKING: Acquires the loader lock.
5559 void
5560 mono_class_setup_nested_types (MonoClass *klass)
5562 ERROR_DECL (error);
5563 GList *classes, *nested_classes, *l;
5564 int i;
5566 if (klass->nested_classes_inited)
5567 return;
5569 if (!klass->type_token) {
5570 mono_loader_lock ();
5571 klass->nested_classes_inited = TRUE;
5572 mono_loader_unlock ();
5573 return;
5576 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
5577 classes = NULL;
5578 while (i) {
5579 MonoClass* nclass;
5580 guint32 cols [MONO_NESTED_CLASS_SIZE];
5581 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
5582 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], error);
5583 if (!is_ok (error)) {
5584 /*FIXME don't swallow the error message*/
5585 mono_error_cleanup (error);
5587 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5588 continue;
5591 classes = g_list_prepend (classes, nclass);
5593 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5596 nested_classes = NULL;
5597 for (l = classes; l; l = l->next)
5598 nested_classes = mono_g_list_prepend_image (klass->image, nested_classes, l->data);
5599 g_list_free (classes);
5601 mono_loader_lock ();
5602 if (!klass->nested_classes_inited) {
5603 mono_class_set_nested_classes_property (klass, nested_classes);
5604 mono_memory_barrier ();
5605 klass->nested_classes_inited = TRUE;
5607 mono_loader_unlock ();
5611 * mono_class_setup_runtime_info:
5612 * \param klass the class to setup
5613 * \param domain the domain of the \p vtable
5614 * \param vtable
5616 * Store \p vtable in \c klass->runtime_info.
5618 * Sets the following field in MonoClass:
5619 * - runtime_info
5621 * LOCKING: domain lock and loaderlock must be held.
5623 void
5624 mono_class_setup_runtime_info (MonoClass *klass, MonoDomain *domain, MonoVTable *vtable)
5626 MonoClassRuntimeInfo *old_info = m_class_get_runtime_info (klass);
5627 if (old_info && old_info->max_domain >= domain->domain_id) {
5628 /* someone already created a large enough runtime info */
5629 old_info->domain_vtables [domain->domain_id] = vtable;
5630 } else {
5631 int new_size = domain->domain_id;
5632 if (old_info)
5633 new_size = MAX (new_size, old_info->max_domain);
5634 new_size++;
5635 /* make the new size a power of two */
5636 int i = 2;
5637 while (new_size > i)
5638 i <<= 1;
5639 new_size = i;
5640 /* this is a bounded memory retention issue: may want to
5641 * handle it differently when we'll have a rcu-like system.
5643 MonoClassRuntimeInfo *runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
5644 runtime_info->max_domain = new_size - 1;
5645 /* copy the stuff from the older info */
5646 if (old_info) {
5647 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
5649 runtime_info->domain_vtables [domain->domain_id] = vtable;
5650 /* keep this last*/
5651 mono_memory_barrier ();
5652 klass->runtime_info = runtime_info;
5657 * mono_class_create_array_fill_type:
5659 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5661 MonoClass *
5662 mono_class_create_array_fill_type (void)
5664 static MonoClass klass;
5666 klass.element_class = mono_defaults.int64_class;
5667 klass.rank = 1;
5668 klass.instance_size = MONO_SIZEOF_MONO_ARRAY;
5669 klass.sizes.element_size = 8;
5670 klass.size_inited = 1;
5671 klass.name = "array_filler_type";
5673 return &klass;
5677 * mono_classes_init:
5679 * Initialize the resources used by this module.
5680 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5682 MONO_NO_SANITIZE_THREAD
5683 void
5684 mono_classes_init (void)
5686 mono_os_mutex_init (&classes_mutex);
5688 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
5689 mono_native_tls_alloc (&init_pending_tls_id, NULL);
5691 mono_counters_register ("MonoClassDef count",
5692 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
5693 mono_counters_register ("MonoClassGtd count",
5694 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
5695 mono_counters_register ("MonoClassGenericInst count",
5696 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
5697 mono_counters_register ("MonoClassGenericParam count",
5698 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
5699 mono_counters_register ("MonoClassArray count",
5700 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
5701 mono_counters_register ("MonoClassPointer count",
5702 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
5703 mono_counters_register ("Inflated methods size",
5704 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mono_inflated_methods_size);
5705 mono_counters_register ("Inflated classes size",
5706 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
5707 mono_counters_register ("MonoClass size",
5708 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
5712 * mono_classes_cleanup:
5714 * Free the resources used by this module.
5716 void
5717 mono_classes_cleanup (void)
5719 mono_native_tls_free (setup_fields_tls_id);
5720 mono_native_tls_free (init_pending_tls_id);
5722 if (global_interface_bitset)
5723 mono_bitset_free (global_interface_bitset);
5724 global_interface_bitset = NULL;
5725 mono_os_mutex_destroy (&classes_mutex);