Revert some changes which don't have proper dependencies.
[mono-project.git] / mono / metadata / class-init.c
blob38f8dc048a6e9d95f6a3594610079668729a3e6e
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;
40 /* Statistics */
41 static gint32 classes_size;
42 static gint32 inflated_classes_size;
43 gint32 mono_inflated_methods_size;
44 static gint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
46 /* Low level lock which protects data structures in this module */
47 static mono_mutex_t classes_mutex;
49 static gboolean class_kind_may_contain_generic_instances (MonoTypeKind kind);
50 static int setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite);
51 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
52 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd);
53 static int generic_array_methods (MonoClass *klass);
54 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
55 static gboolean class_has_isbyreflike_attribute (MonoClass *klass);
56 static void mono_class_setup_interface_id_internal (MonoClass *klass);
58 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
59 static MonoNativeTlsKey setup_fields_tls_id;
61 static MonoNativeTlsKey init_pending_tls_id;
63 static inline void
64 classes_lock (void)
66 mono_locks_os_acquire (&classes_mutex, ClassesLock);
69 static inline void
70 classes_unlock (void)
72 mono_locks_os_release (&classes_mutex, ClassesLock);
76 We use gclass recording to allow recursive system f types to be referenced by a parent.
78 Given the following type hierarchy:
80 class TextBox : TextBoxBase<TextBox> {}
81 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
82 class TextInput<T> : Input<T> where T: TextInput<T> {}
83 class Input<T> {}
85 The runtime tries to load TextBoxBase<>.
86 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
87 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
88 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
90 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
91 at this point, iow, both are registered in the type map and both and a NULL parent. This means
92 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
94 To fix that what we do is to record all generic instantes created while resolving the parent of
95 any generic type definition and, after resolved, correct the parent field if needed.
98 static int record_gclass_instantiation;
99 static GSList *gclass_recorded_list;
100 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
103 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
105 static void
106 enable_gclass_recording (void)
108 ++record_gclass_instantiation;
112 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
114 static void
115 disable_gclass_recording (gclass_record_func func, void *user_data)
117 GSList **head = &gclass_recorded_list;
119 g_assert (record_gclass_instantiation > 0);
120 --record_gclass_instantiation;
122 while (*head) {
123 GSList *node = *head;
124 if (func ((MonoClass*)node->data, user_data)) {
125 *head = node->next;
126 g_slist_free_1 (node);
127 } else {
128 head = &node->next;
132 /* We automatically discard all recorded gclasses when disabled. */
133 if (!record_gclass_instantiation && gclass_recorded_list) {
134 g_slist_free (gclass_recorded_list);
135 gclass_recorded_list = NULL;
139 #define mono_class_new0(klass,struct_type, n_structs) \
140 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
143 * mono_class_setup_basic_field_info:
144 * \param class The class to initialize
146 * Initializes the following fields in MonoClass:
147 * * klass->fields (only field->parent and field->name)
148 * * klass->field.count
149 * * klass->first_field_idx
150 * LOCKING: Acquires the loader lock
152 void
153 mono_class_setup_basic_field_info (MonoClass *klass)
155 MonoGenericClass *gklass;
156 MonoClassField *field;
157 MonoClassField *fields;
158 MonoClass *gtd;
159 MonoImage *image;
160 int i, top;
162 if (klass->fields)
163 return;
165 gklass = mono_class_try_get_generic_class (klass);
166 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
167 image = klass->image;
170 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
172 * This happens when a generic instance of an unfinished generic typebuilder
173 * is used as an element type for creating an array type. We can't initialize
174 * the fields of this class using the fields of gklass, since gklass is not
175 * finished yet, fields could be added to it later.
177 return;
180 if (gtd) {
181 mono_class_setup_basic_field_info (gtd);
183 mono_loader_lock ();
184 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
185 mono_loader_unlock ();
188 top = mono_class_get_field_count (klass);
190 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
193 * Fetch all the field information.
195 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
196 for (i = 0; i < top; i++) {
197 field = &fields [i];
198 field->parent = klass;
200 if (gtd) {
201 field->name = mono_field_get_name (&gtd->fields [i]);
202 } else {
203 int idx = first_field_idx + i;
204 /* first_field_idx and idx points into the fieldptr table */
205 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
206 /* The name is needed for fieldrefs */
207 field->name = mono_metadata_string_heap (image, name_idx);
211 mono_memory_barrier ();
213 mono_loader_lock ();
214 if (!klass->fields)
215 klass->fields = fields;
216 mono_loader_unlock ();
220 * mono_class_setup_fields:
221 * \p klass The class to initialize
223 * Initializes klass->fields, computes class layout and sizes.
224 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
225 * Sets the following fields in \p klass:
226 * - all the fields initialized by mono_class_init_sizes ()
227 * - element_class/cast_class (for enums)
228 * - sizes:element_size (for arrays)
229 * - field->type/offset for all fields
230 * - fields_inited
232 * LOCKING: Acquires the loader lock.
234 void
235 mono_class_setup_fields (MonoClass *klass)
237 ERROR_DECL (error);
238 MonoImage *m = klass->image;
239 int top;
240 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
241 int i;
242 guint32 real_size = 0;
243 guint32 packing_size = 0;
244 int instance_size;
245 gboolean explicit_size;
246 MonoClassField *field;
247 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
248 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
250 if (klass->fields_inited)
251 return;
253 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
255 * This happens when a generic instance of an unfinished generic typebuilder
256 * is used as an element type for creating an array type. We can't initialize
257 * the fields of this class using the fields of gklass, since gklass is not
258 * finished yet, fields could be added to it later.
260 return;
263 mono_class_setup_basic_field_info (klass);
264 top = mono_class_get_field_count (klass);
266 if (gtd) {
267 mono_class_setup_fields (gtd);
268 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
269 return;
272 instance_size = 0;
273 if (klass->parent) {
274 /* For generic instances, klass->parent might not have been initialized */
275 mono_class_init_internal (klass->parent);
276 mono_class_setup_fields (klass->parent);
277 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
278 return;
279 instance_size = klass->parent->instance_size;
280 } else {
281 instance_size = MONO_ABI_SIZEOF (MonoObject);
284 /* Get the real size */
285 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
286 if (explicit_size)
287 instance_size += real_size;
290 * This function can recursively call itself.
291 * Prevent infinite recursion by using a list in TLS.
293 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
294 if (g_slist_find (init_list, klass))
295 return;
296 init_list = g_slist_prepend (init_list, klass);
297 mono_native_tls_set_value (setup_fields_tls_id, init_list);
300 * Fetch all the field information.
302 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
303 for (i = 0; i < top; i++) {
304 int idx = first_field_idx + i;
305 field = &klass->fields [i];
307 if (!field->type) {
308 mono_field_resolve_type (field, error);
309 if (!mono_error_ok (error)) {
310 /*mono_field_resolve_type already failed class*/
311 mono_error_cleanup (error);
312 break;
314 if (!field->type)
315 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
316 g_assert (field->type);
319 if (!mono_type_get_underlying_type (field->type)) {
320 mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
321 break;
324 if (mono_field_is_deleted (field))
325 continue;
326 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
327 guint32 uoffset;
328 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
329 int offset = uoffset;
331 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
332 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
333 break;
335 if (offset < -1) { /*-1 is used to encode special static fields */
336 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
337 break;
339 if (mono_class_is_gtd (klass)) {
340 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
341 break;
344 if (mono_type_has_exceptions (field->type)) {
345 char *class_name = mono_type_get_full_name (klass);
346 char *type_name = mono_type_full_name (field->type);
348 mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
349 g_free (class_name);
350 g_free (type_name);
351 break;
353 /* The def_value of fields is compute lazily during vtable creation */
356 if (!mono_class_has_failure (klass)) {
357 mono_loader_lock ();
358 mono_class_layout_fields (klass, instance_size, packing_size, real_size, FALSE);
359 mono_loader_unlock ();
362 init_list = g_slist_remove (init_list, klass);
363 mono_native_tls_set_value (setup_fields_tls_id, init_list);
366 static gboolean
367 discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
369 return mono_class_get_generic_class (gclass)->container_class == user_data;
372 static gboolean
373 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
375 MonoClass *gtd = (MonoClass*)user_data;
376 /* Only try to fix generic instances of @gtd */
377 if (mono_class_get_generic_class (gclass)->container_class != gtd)
378 return FALSE;
380 /* Check if the generic instance has no parent. */
381 if (gtd->parent && !gclass->parent)
382 mono_generic_class_setup_parent (gclass, gtd);
384 return TRUE;
387 static void
388 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
390 mono_class_set_type_load_failure (klass, "%s", msg);
391 mono_error_set_type_load_class (error, klass, "%s", msg);
395 * mono_class_create_from_typedef:
396 * \param image: image where the token is valid
397 * \param type_token: typedef token
398 * \param error: used to return any error found while creating the type
400 * Create the MonoClass* representing the specified type token.
401 * \p type_token must be a TypeDef token.
403 * FIXME: don't return NULL on failure, just let the caller figure it out.
405 MonoClass *
406 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
408 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
409 MonoClass *klass, *parent = NULL;
410 guint32 cols [MONO_TYPEDEF_SIZE];
411 guint32 cols_next [MONO_TYPEDEF_SIZE];
412 guint tidx = mono_metadata_token_index (type_token);
413 MonoGenericContext *context = NULL;
414 const char *name, *nspace;
415 guint icount = 0;
416 MonoClass **interfaces;
417 guint32 field_last, method_last;
418 guint32 nesting_tokeen;
420 error_init (error);
422 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
423 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
424 return NULL;
427 mono_loader_lock ();
429 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
430 mono_loader_unlock ();
431 return klass;
434 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
436 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
437 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
439 if (mono_metadata_has_generic_params (image, type_token)) {
440 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassGtd));
441 klass->class_kind = MONO_CLASS_GTD;
442 UnlockedAdd (&classes_size, sizeof (MonoClassGtd));
443 ++class_gtd_count;
444 } else {
445 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassDef));
446 klass->class_kind = MONO_CLASS_DEF;
447 UnlockedAdd (&classes_size, sizeof (MonoClassDef));
448 ++class_def_count;
451 klass->name = name;
452 klass->name_space = nspace;
454 MONO_PROFILER_RAISE (class_loading, (klass));
456 klass->image = image;
457 klass->type_token = type_token;
458 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
460 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
463 * Check whether we're a generic type definition.
465 if (mono_class_is_gtd (klass)) {
466 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL, klass);
467 context = &generic_container->context;
468 mono_class_set_generic_container (klass, generic_container);
469 MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
470 canonical_inst->type = MONO_TYPE_GENERICINST;
471 canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
472 enable_gclass_recording ();
475 if (cols [MONO_TYPEDEF_EXTENDS]) {
476 MonoClass *tmp;
477 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
479 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
480 /*WARNING: this must satisfy mono_metadata_type_hash*/
481 klass->this_arg.byref = 1;
482 klass->this_arg.data.klass = klass;
483 klass->this_arg.type = MONO_TYPE_CLASS;
484 klass->_byval_arg.data.klass = klass;
485 klass->_byval_arg.type = MONO_TYPE_CLASS;
487 parent = mono_class_get_checked (image, parent_token, error);
488 if (parent && context) /* Always inflate */
489 parent = mono_class_inflate_generic_class_checked (parent, context, error);
491 if (parent == NULL) {
492 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
493 goto parent_failure;
496 for (tmp = parent; tmp; tmp = tmp->parent) {
497 if (tmp == klass) {
498 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
499 goto parent_failure;
501 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
502 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
503 goto parent_failure;
508 mono_class_setup_parent (klass, parent);
510 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
511 mono_class_setup_mono_type (klass);
513 if (mono_class_is_gtd (klass))
514 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
517 * This might access klass->_byval_arg for recursion generated by generic constraints,
518 * so it has to come after setup_mono_type ().
520 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
521 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
522 if (!mono_error_ok (error)) {
523 /*FIXME implement a mono_class_set_failure_from_mono_error */
524 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
525 mono_loader_unlock ();
526 MONO_PROFILER_RAISE (class_failed, (klass));
527 return NULL;
531 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
532 klass->unicode = 1;
534 #ifdef HOST_WIN32
535 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
536 klass->unicode = 1;
537 #endif
539 klass->cast_class = klass->element_class = klass;
540 if (mono_is_corlib_image (klass->image)) {
541 switch (m_class_get_byval_arg (klass)->type) {
542 case MONO_TYPE_I1:
543 if (mono_defaults.byte_class)
544 klass->cast_class = mono_defaults.byte_class;
545 break;
546 case MONO_TYPE_U1:
547 if (mono_defaults.sbyte_class)
548 mono_defaults.sbyte_class = klass;
549 break;
550 case MONO_TYPE_I2:
551 if (mono_defaults.uint16_class)
552 mono_defaults.uint16_class = klass;
553 break;
554 case MONO_TYPE_U2:
555 if (mono_defaults.int16_class)
556 klass->cast_class = mono_defaults.int16_class;
557 break;
558 case MONO_TYPE_I4:
559 if (mono_defaults.uint32_class)
560 mono_defaults.uint32_class = klass;
561 break;
562 case MONO_TYPE_U4:
563 if (mono_defaults.int32_class)
564 klass->cast_class = mono_defaults.int32_class;
565 break;
566 case MONO_TYPE_I8:
567 if (mono_defaults.uint64_class)
568 mono_defaults.uint64_class = klass;
569 break;
570 case MONO_TYPE_U8:
571 if (mono_defaults.int64_class)
572 klass->cast_class = mono_defaults.int64_class;
573 break;
577 if (!klass->enumtype) {
578 if (!mono_metadata_interfaces_from_typedef_full (
579 image, type_token, &interfaces, &icount, FALSE, context, error)){
581 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
582 mono_loader_unlock ();
583 MONO_PROFILER_RAISE (class_failed, (klass));
584 return NULL;
587 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
588 g_assert(icount <= 65535);
590 klass->interfaces = interfaces;
591 klass->interface_count = icount;
592 klass->interfaces_inited = 1;
595 /*g_print ("Load class %s\n", name);*/
598 * Compute the field and method lists
600 int first_field_idx;
601 first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
602 mono_class_set_first_field_idx (klass, first_field_idx);
603 int first_method_idx;
604 first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
605 mono_class_set_first_method_idx (klass, first_method_idx);
607 if (tt->rows > tidx){
608 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
609 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
610 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
611 } else {
612 field_last = image->tables [MONO_TABLE_FIELD].rows;
613 method_last = image->tables [MONO_TABLE_METHOD].rows;
616 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
617 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
618 mono_class_set_field_count (klass, field_last - first_field_idx);
619 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
620 mono_class_set_method_count (klass, method_last - first_method_idx);
622 /* reserve space to store vector pointer in arrays */
623 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
624 klass->instance_size += 2 * TARGET_SIZEOF_VOID_P;
625 #ifndef ENABLE_NETCORE
626 g_assert (mono_class_get_field_count (klass) == 0);
627 #else
628 /* TODO: check that array has 0 non-const fields */
629 #endif
632 if (klass->enumtype) {
633 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
634 if (!enum_basetype) {
635 /*set it to a default value as the whole runtime can't handle this to be null*/
636 klass->cast_class = klass->element_class = mono_defaults.int32_class;
637 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
638 mono_loader_unlock ();
639 MONO_PROFILER_RAISE (class_failed, (klass));
640 return NULL;
642 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (enum_basetype);
646 * If we're a generic type definition, load the constraints.
647 * We must do this after the class has been constructed to make certain recursive scenarios
648 * work.
650 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
651 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
652 mono_loader_unlock ();
653 MONO_PROFILER_RAISE (class_failed, (klass));
654 return NULL;
657 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
658 if (!strncmp (name, "Vector", 6))
659 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");
660 } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
661 /* The JIT can't handle SIMD types with != 16 size yet */
662 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
663 if (!strcmp (name, "Vector4"))
664 klass->simd_type = 1;
667 // compute is_byreflike
668 if (m_class_is_valuetype (klass))
669 if (class_has_isbyreflike_attribute (klass))
670 klass->is_byreflike = 1;
672 mono_loader_unlock ();
674 MONO_PROFILER_RAISE (class_loaded, (klass));
676 return klass;
678 parent_failure:
679 if (mono_class_is_gtd (klass))
680 disable_gclass_recording (discard_gclass_due_to_failure, klass);
682 mono_class_setup_mono_type (klass);
683 mono_loader_unlock ();
684 MONO_PROFILER_RAISE (class_failed, (klass));
685 return NULL;
689 static void
690 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
692 if (gtd->parent) {
693 ERROR_DECL (error);
694 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
696 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), error);
697 if (!mono_error_ok (error)) {
698 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
699 klass->parent = mono_defaults.object_class;
700 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error));
701 mono_error_cleanup (error);
704 mono_loader_lock ();
705 if (klass->parent)
706 mono_class_setup_parent (klass, klass->parent);
708 if (klass->enumtype) {
709 klass->cast_class = gtd->cast_class;
710 klass->element_class = gtd->element_class;
712 mono_loader_unlock ();
715 struct HasIsByrefLikeUD {
716 gboolean has_isbyreflike;
719 static gboolean
720 has_isbyreflike_attribute_func (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
722 struct HasIsByrefLikeUD *has_isbyreflike = (struct HasIsByrefLikeUD *)user_data;
723 if (!strcmp (name, "IsByRefLikeAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
724 has_isbyreflike->has_isbyreflike = TRUE;
725 return TRUE;
727 return FALSE;
730 static gboolean
731 class_has_isbyreflike_attribute (MonoClass *klass)
733 struct HasIsByrefLikeUD has_isbyreflike;
734 has_isbyreflike.has_isbyreflike = FALSE;
735 mono_class_metadata_foreach_custom_attr (klass, has_isbyreflike_attribute_func, &has_isbyreflike);
736 return has_isbyreflike.has_isbyreflike;
740 static gboolean
741 check_valid_generic_inst_arguments (MonoGenericInst *inst, MonoError *error)
743 for (int i = 0; i < inst->type_argc; i++) {
744 if (!mono_type_is_valid_generic_argument (inst->type_argv [i])) {
745 char *type_name = mono_type_full_name (inst->type_argv [i]);
746 mono_error_set_invalid_program (error, "generic type cannot be instantiated with type '%s'", type_name);
747 g_free (type_name);
748 return FALSE;
751 return TRUE;
755 * Create the `MonoClass' for an instantiation of a generic type.
756 * We only do this if we actually need it.
758 MonoClass*
759 mono_class_create_generic_inst (MonoGenericClass *gclass)
761 MonoClass *klass, *gklass;
763 if (gclass->cached_class)
764 return gclass->cached_class;
766 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
768 gklass = gclass->container_class;
770 if (gklass->nested_in) {
771 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
772 klass->nested_in = gklass->nested_in;
775 klass->name = gklass->name;
776 klass->name_space = gklass->name_space;
778 klass->image = gklass->image;
779 klass->type_token = gklass->type_token;
781 klass->class_kind = MONO_CLASS_GINST;
782 //FIXME add setter
783 ((MonoClassGenericInst*)klass)->generic_class = gclass;
785 klass->_byval_arg.type = MONO_TYPE_GENERICINST;
786 klass->this_arg.type = m_class_get_byval_arg (klass)->type;
787 klass->this_arg.data.generic_class = klass->_byval_arg.data.generic_class = gclass;
788 klass->this_arg.byref = TRUE;
789 klass->enumtype = gklass->enumtype;
790 klass->valuetype = gklass->valuetype;
793 if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
794 g_assert (gclass->context.class_inst);
795 g_assert (gclass->context.class_inst->type_argc > 0);
796 if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
797 klass->simd_type = 1;
799 klass->is_array_special_interface = gklass->is_array_special_interface;
801 klass->cast_class = klass->element_class = klass;
803 if (m_class_is_valuetype (klass)) {
804 klass->is_byreflike = gklass->is_byreflike;
807 if (gclass->is_dynamic) {
809 * 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.
810 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
811 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
813 if (!gklass->wastypebuilder)
814 klass->inited = 1;
816 if (klass->enumtype) {
818 * For enums, gklass->fields might not been set, but instance_size etc. is
819 * already set in mono_reflection_create_internal_class (). For non-enums,
820 * these will be computed normally in mono_class_layout_fields ().
822 klass->instance_size = gklass->instance_size;
823 klass->sizes.class_size = gklass->sizes.class_size;
824 klass->size_inited = 1;
829 ERROR_DECL (error_inst);
830 if (!check_valid_generic_inst_arguments (gclass->context.class_inst, error_inst)) {
831 char *gklass_name = mono_type_get_full_name (gklass);
832 mono_class_set_type_load_failure (klass, "Could not instantiate %s due to %s", gklass_name, mono_error_get_message (error_inst));
833 g_free (gklass_name);
834 mono_error_cleanup (error_inst);
838 mono_loader_lock ();
840 if (gclass->cached_class) {
841 mono_loader_unlock ();
842 return gclass->cached_class;
845 if (record_gclass_instantiation > 0)
846 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
848 if (mono_class_is_nullable (klass))
849 klass->cast_class = klass->element_class = mono_class_get_nullable_param_internal (klass);
851 MONO_PROFILER_RAISE (class_loading, (klass));
853 mono_generic_class_setup_parent (klass, gklass);
855 if (gclass->is_dynamic)
856 mono_class_setup_supertypes (klass);
858 mono_memory_barrier ();
859 gclass->cached_class = klass;
861 MONO_PROFILER_RAISE (class_loaded, (klass));
863 ++class_ginst_count;
864 inflated_classes_size += sizeof (MonoClassGenericInst);
866 mono_loader_unlock ();
868 return klass;
871 static gboolean
872 class_kind_may_contain_generic_instances (MonoTypeKind kind)
874 /* classes of type generic inst may contain generic arguments from other images,
875 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
876 return (kind == MONO_CLASS_GINST || kind == MONO_CLASS_ARRAY || kind == MONO_CLASS_POINTER);
880 * mono_class_create_bounded_array:
881 * \param element_class element class
882 * \param rank the dimension of the array class
883 * \param bounded whenever the array has non-zero bounds
884 * \returns A class object describing the array with element type \p element_type and
885 * dimension \p rank.
887 MonoClass *
888 mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bounded)
890 MonoImage *image;
891 MonoClass *klass, *cached, *k;
892 MonoClass *parent = NULL;
893 GSList *list, *rootlist = NULL;
894 int nsize;
895 char *name;
896 MonoImageSet* image_set;
898 g_assert (rank <= 255);
900 if (rank > 1)
901 /* bounded only matters for one-dimensional arrays */
902 bounded = FALSE;
904 image = eclass->image;
905 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)eclass->class_kind) ? mono_metadata_get_image_set_for_class (eclass) : NULL;
907 /* Check cache */
908 cached = NULL;
909 if (rank == 1 && !bounded) {
910 if (image_set) {
911 mono_image_set_lock (image_set);
912 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
913 mono_image_set_unlock (image_set);
914 } else {
916 * This case is very frequent not just during compilation because of calls
917 * from mono_class_from_mono_type_internal (), mono_array_new (),
918 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
920 mono_os_mutex_lock (&image->szarray_cache_lock);
921 if (!image->szarray_cache)
922 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
923 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
924 mono_os_mutex_unlock (&image->szarray_cache_lock);
926 } else {
927 if (image_set) {
928 mono_image_set_lock (image_set);
929 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
930 for (list = rootlist; list; list = list->next) {
931 k = (MonoClass *)list->data;
932 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
933 cached = k;
934 break;
937 mono_image_set_unlock (image_set);
938 } else {
939 mono_loader_lock ();
940 if (!image->array_cache)
941 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
942 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
943 for (list = rootlist; list; list = list->next) {
944 k = (MonoClass *)list->data;
945 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
946 cached = k;
947 break;
950 mono_loader_unlock ();
953 if (cached)
954 return cached;
956 parent = mono_defaults.array_class;
957 if (!parent->inited)
958 mono_class_init_internal (parent);
960 klass = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
962 klass->image = image;
963 klass->name_space = eclass->name_space;
964 klass->class_kind = MONO_CLASS_ARRAY;
966 nsize = strlen (eclass->name);
967 name = (char *)g_malloc (nsize + 2 + rank + 1);
968 memcpy (name, eclass->name, nsize);
969 name [nsize] = '[';
970 if (rank > 1)
971 memset (name + nsize + 1, ',', rank - 1);
972 if (bounded)
973 name [nsize + rank] = '*';
974 name [nsize + rank + bounded] = ']';
975 name [nsize + rank + bounded + 1] = 0;
976 klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
977 g_free (name);
979 klass->type_token = 0;
980 klass->parent = parent;
981 klass->instance_size = mono_class_instance_size (klass->parent);
983 if (m_class_get_byval_arg (eclass)->type == MONO_TYPE_TYPEDBYREF) {
984 /*Arrays of those two types are invalid.*/
985 ERROR_DECL (prepared_error);
986 mono_error_set_invalid_program (prepared_error, "Arrays of System.TypedReference types are invalid.");
987 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
988 mono_error_cleanup (prepared_error);
989 } else if (m_class_is_byreflike (eclass)) {
990 /* .NET Core throws a type load exception: "Could not create array type 'fullname[]'" */
991 char *full_name = mono_type_get_full_name (eclass);
992 mono_class_set_type_load_failure (klass, "Could not create array type '%s[]'", full_name);
993 g_free (full_name);
994 } else if (eclass->enumtype && !mono_class_enum_basetype_internal (eclass)) {
995 guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass);
996 if (!ref_info_handle || eclass->wastypebuilder) {
997 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
998 g_assert (ref_info_handle && !eclass->wastypebuilder);
1000 /* element_size -1 is ok as this is not an instantitable type*/
1001 klass->sizes.element_size = -1;
1002 } else
1003 klass->sizes.element_size = -1;
1005 mono_class_setup_supertypes (klass);
1007 if (mono_class_is_ginst (eclass))
1008 mono_class_init_internal (eclass);
1009 if (!eclass->size_inited)
1010 mono_class_setup_fields (eclass);
1011 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
1012 /*FIXME we fail the array type, but we have to let other fields be set.*/
1014 klass->has_references = MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (eclass)) || m_class_has_references (eclass)? TRUE: FALSE;
1016 klass->rank = rank;
1018 if (eclass->enumtype)
1019 klass->cast_class = eclass->element_class;
1020 else
1021 klass->cast_class = eclass;
1023 switch (m_class_get_byval_arg (m_class_get_cast_class (klass))->type) {
1024 case MONO_TYPE_I1:
1025 klass->cast_class = mono_defaults.byte_class;
1026 break;
1027 case MONO_TYPE_U2:
1028 klass->cast_class = mono_defaults.int16_class;
1029 break;
1030 case MONO_TYPE_U4:
1031 #if TARGET_SIZEOF_VOID_P == 4
1032 case MONO_TYPE_I:
1033 case MONO_TYPE_U:
1034 #endif
1035 klass->cast_class = mono_defaults.int32_class;
1036 break;
1037 case MONO_TYPE_U8:
1038 #if TARGET_SIZEOF_VOID_P == 8
1039 case MONO_TYPE_I:
1040 case MONO_TYPE_U:
1041 #endif
1042 klass->cast_class = mono_defaults.int64_class;
1043 break;
1044 default:
1045 break;
1048 klass->element_class = eclass;
1050 if ((rank > 1) || bounded) {
1051 MonoArrayType *at = image_set ? (MonoArrayType *)mono_image_set_alloc0 (image_set, sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
1052 klass->_byval_arg.type = MONO_TYPE_ARRAY;
1053 klass->_byval_arg.data.array = at;
1054 at->eklass = eclass;
1055 at->rank = rank;
1056 /* FIXME: complete.... */
1057 } else {
1058 klass->_byval_arg.type = MONO_TYPE_SZARRAY;
1059 klass->_byval_arg.data.klass = eclass;
1061 klass->this_arg = klass->_byval_arg;
1062 klass->this_arg.byref = 1;
1064 if (rank > 32) {
1065 ERROR_DECL (prepared_error);
1066 name = mono_type_get_full_name (klass);
1067 mono_error_set_type_load_class (prepared_error, klass, "%s has too many dimensions.", name);
1068 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
1069 mono_error_cleanup (prepared_error);
1070 g_free (name);
1073 mono_loader_lock ();
1075 /* Check cache again */
1076 cached = NULL;
1077 if (rank == 1 && !bounded) {
1078 if (image_set) {
1079 mono_image_set_lock (image_set);
1080 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
1081 mono_image_set_unlock (image_set);
1082 } else {
1083 mono_os_mutex_lock (&image->szarray_cache_lock);
1084 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
1085 mono_os_mutex_unlock (&image->szarray_cache_lock);
1087 } else {
1088 if (image_set) {
1089 mono_image_set_lock (image_set);
1090 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
1091 for (list = rootlist; list; list = list->next) {
1092 k = (MonoClass *)list->data;
1093 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1094 cached = k;
1095 break;
1098 mono_image_set_unlock (image_set);
1099 } else {
1100 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
1101 for (list = rootlist; list; list = list->next) {
1102 k = (MonoClass *)list->data;
1103 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1104 cached = k;
1105 break;
1110 if (cached) {
1111 mono_loader_unlock ();
1112 return cached;
1115 MONO_PROFILER_RAISE (class_loading, (klass));
1117 UnlockedAdd (&classes_size, sizeof (MonoClassArray));
1118 ++class_array_count;
1120 if (rank == 1 && !bounded) {
1121 if (image_set) {
1122 mono_image_set_lock (image_set);
1123 g_hash_table_insert (image_set->szarray_cache, eclass, klass);
1124 mono_image_set_unlock (image_set);
1125 } else {
1126 mono_os_mutex_lock (&image->szarray_cache_lock);
1127 g_hash_table_insert (image->szarray_cache, eclass, klass);
1128 mono_os_mutex_unlock (&image->szarray_cache_lock);
1130 } else {
1131 if (image_set) {
1132 mono_image_set_lock (image_set);
1133 list = g_slist_append (rootlist, klass);
1134 g_hash_table_insert (image_set->array_cache, eclass, list);
1135 mono_image_set_unlock (image_set);
1136 } else {
1137 list = g_slist_append (rootlist, klass);
1138 g_hash_table_insert (image->array_cache, eclass, list);
1142 mono_loader_unlock ();
1144 MONO_PROFILER_RAISE (class_loaded, (klass));
1146 return klass;
1150 * mono_class_create_array:
1151 * \param element_class element class
1152 * \param rank the dimension of the array class
1153 * \returns A class object describing the array with element type \p element_type and
1154 * dimension \p rank.
1156 MonoClass *
1157 mono_class_create_array (MonoClass *eclass, guint32 rank)
1159 return mono_class_create_bounded_array (eclass, rank, FALSE);
1162 // This is called by mono_class_create_generic_parameter when a new class must be created.
1163 static MonoClass*
1164 make_generic_param_class (MonoGenericParam *param)
1166 MonoClass *klass, **ptr;
1167 int count, pos, i;
1168 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1169 MonoGenericContainer *container = mono_generic_param_owner (param);
1170 g_assert_checked (container);
1172 MonoImage *image = mono_get_image_for_generic_param (param);
1173 gboolean is_mvar = container->is_method;
1174 gboolean is_anonymous = container->is_anonymous;
1176 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
1177 klass->class_kind = MONO_CLASS_GPARAM;
1178 UnlockedAdd (&classes_size, sizeof (MonoClassGenericParam));
1179 UnlockedIncrement (&class_gparam_count);
1181 if (!is_anonymous) {
1182 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
1183 } else {
1184 int n = mono_generic_param_num (param);
1185 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , mono_make_generic_name_string (image, n) );
1188 if (is_anonymous) {
1189 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
1190 } else if (is_mvar) {
1191 MonoMethod *omethod = container->owner.method;
1192 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
1193 } else {
1194 MonoClass *oklass = container->owner.klass;
1195 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
1198 MONO_PROFILER_RAISE (class_loading, (klass));
1200 // Count non-NULL items in pinfo->constraints
1201 count = 0;
1202 if (!is_anonymous)
1203 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
1206 pos = 0;
1207 if ((count > 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo->constraints [0])) {
1208 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
1209 pos++;
1210 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
1211 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
1212 } else {
1213 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
1216 if (count - pos > 0) {
1217 klass->interface_count = count - pos;
1218 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
1219 klass->interfaces_inited = TRUE;
1220 for (i = pos; i < count; i++)
1221 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
1224 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
1226 klass->inited = TRUE;
1227 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
1228 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
1230 MonoTypeEnum t = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
1231 klass->_byval_arg.type = t;
1232 klass->this_arg.type = t;
1233 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
1234 CHECKED_METADATA_WRITE_PTR ( klass->_byval_arg.data.generic_param , param );
1235 klass->this_arg.byref = TRUE;
1237 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1238 klass->sizes.generic_param_token = !is_anonymous ? pinfo->token : 0;
1240 /*Init these fields to sane values*/
1241 klass->min_align = 1;
1243 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1244 * constrained to, the JIT depends on this.
1246 klass->instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_stack_size_internal (m_class_get_byval_arg (klass), NULL, TRUE);
1247 mono_memory_barrier ();
1248 klass->size_inited = 1;
1250 mono_class_setup_supertypes (klass);
1252 if (count - pos > 0) {
1253 mono_class_setup_vtable (klass->parent);
1254 if (mono_class_has_failure (klass->parent))
1255 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
1256 else
1257 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
1260 return klass;
1264 * LOCKING: Acquires the image lock (@image).
1266 MonoClass *
1267 mono_class_create_generic_parameter (MonoGenericParam *param)
1269 MonoImage *image = mono_get_image_for_generic_param (param);
1270 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1271 MonoClass *klass, *klass2;
1273 // If a klass already exists for this object and is cached, return it.
1274 klass = pinfo->pklass;
1276 if (klass)
1277 return klass;
1279 // Create a new klass
1280 klass = make_generic_param_class (param);
1282 // Now we need to cache the klass we created.
1283 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1284 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1285 // and allow our newly-created klass object to just leak.
1286 mono_memory_barrier ();
1288 mono_image_lock (image);
1290 // Here "klass2" refers to the klass potentially created by the other thread.
1291 klass2 = pinfo->pklass;
1293 if (klass2) {
1294 klass = klass2;
1295 } else {
1296 pinfo->pklass = klass;
1298 mono_image_unlock (image);
1300 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1301 if (klass2)
1302 MONO_PROFILER_RAISE (class_failed, (klass2));
1303 else
1304 MONO_PROFILER_RAISE (class_loaded, (klass));
1306 return klass;
1310 * mono_class_create_ptr:
1312 MonoClass *
1313 mono_class_create_ptr (MonoType *type)
1315 MonoClass *result;
1316 MonoClass *el_class;
1317 MonoImage *image;
1318 char *name;
1319 MonoImageSet* image_set;
1321 el_class = mono_class_from_mono_type_internal (type);
1322 image = el_class->image;
1323 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)el_class->class_kind) ? mono_metadata_get_image_set_for_class (el_class) : NULL;
1325 if (image_set) {
1326 mono_image_set_lock (image_set);
1327 if (image_set->ptr_cache) {
1328 if ((result = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1329 mono_image_set_unlock (image_set);
1330 return result;
1333 mono_image_set_unlock (image_set);
1334 } else {
1335 mono_image_lock (image);
1336 if (image->ptr_cache) {
1337 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1338 mono_image_unlock (image);
1339 return result;
1342 mono_image_unlock (image);
1345 result = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
1347 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1348 ++class_pointer_count;
1350 result->parent = NULL; /* no parent for PTR types */
1351 result->name_space = el_class->name_space;
1352 name = g_strdup_printf ("%s*", el_class->name);
1353 result->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
1354 result->class_kind = MONO_CLASS_POINTER;
1355 g_free (name);
1357 MONO_PROFILER_RAISE (class_loading, (result));
1359 result->image = el_class->image;
1360 result->inited = TRUE;
1361 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1362 result->min_align = sizeof (gpointer);
1363 result->cast_class = result->element_class = el_class;
1364 result->blittable = TRUE;
1366 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_PTR;
1367 result->this_arg.data.type = result->_byval_arg.data.type = m_class_get_byval_arg (el_class);
1368 result->this_arg.byref = TRUE;
1370 mono_class_setup_supertypes (result);
1372 if (image_set) {
1373 mono_image_set_lock (image_set);
1374 if (image_set->ptr_cache) {
1375 MonoClass *result2;
1376 if ((result2 = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1377 mono_image_set_unlock (image_set);
1378 MONO_PROFILER_RAISE (class_failed, (result));
1379 return result2;
1382 else {
1383 image_set->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1385 g_hash_table_insert (image_set->ptr_cache, el_class, result);
1386 mono_image_set_unlock (image_set);
1387 } else {
1388 mono_image_lock (image);
1389 if (image->ptr_cache) {
1390 MonoClass *result2;
1391 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1392 mono_image_unlock (image);
1393 MONO_PROFILER_RAISE (class_failed, (result));
1394 return result2;
1396 } else {
1397 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1399 g_hash_table_insert (image->ptr_cache, el_class, result);
1400 mono_image_unlock (image);
1403 MONO_PROFILER_RAISE (class_loaded, (result));
1405 return result;
1408 MonoClass *
1409 mono_class_create_fnptr (MonoMethodSignature *sig)
1411 MonoClass *result, *cached;
1412 static GHashTable *ptr_hash = NULL;
1414 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1416 mono_loader_lock ();
1417 if (!ptr_hash)
1418 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1419 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1420 mono_loader_unlock ();
1421 if (cached)
1422 return cached;
1424 result = g_new0 (MonoClass, 1);
1426 result->parent = NULL; /* no parent for PTR types */
1427 result->name_space = "System";
1428 result->name = "MonoFNPtrFakeClass";
1429 result->class_kind = MONO_CLASS_POINTER;
1431 result->image = mono_defaults.corlib; /* need to fix... */
1432 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1433 result->min_align = sizeof (gpointer);
1434 result->cast_class = result->element_class = result;
1435 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_FNPTR;
1436 result->this_arg.data.method = result->_byval_arg.data.method = sig;
1437 result->this_arg.byref = TRUE;
1438 result->blittable = TRUE;
1439 result->inited = TRUE;
1441 mono_class_setup_supertypes (result);
1443 mono_loader_lock ();
1445 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1446 if (cached) {
1447 g_free (result);
1448 mono_loader_unlock ();
1449 return cached;
1452 MONO_PROFILER_RAISE (class_loading, (result));
1454 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1455 ++class_pointer_count;
1457 g_hash_table_insert (ptr_hash, sig, result);
1459 mono_loader_unlock ();
1461 MONO_PROFILER_RAISE (class_loaded, (result));
1463 return result;
1467 static void
1468 print_implemented_interfaces (MonoClass *klass)
1470 char *name;
1471 ERROR_DECL (error);
1472 GPtrArray *ifaces = NULL;
1473 int i;
1474 int ancestor_level = 0;
1476 name = mono_type_get_full_name (klass);
1477 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
1478 g_free (name);
1480 for (i = 0; i < klass->interface_offsets_count; i++) {
1481 char *ic_name = mono_type_get_full_name (klass->interfaces_packed [i]);
1482 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i,
1483 klass->interfaces_packed [i]->interface_id,
1484 klass->interface_offsets_packed [i],
1485 mono_class_get_method_count (klass->interfaces_packed [i]),
1486 ic_name);
1487 g_free (ic_name);
1489 printf ("Interface flags: ");
1490 for (i = 0; i <= klass->max_interface_id; i++)
1491 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
1492 printf ("(%d,T)", i);
1493 else
1494 printf ("(%d,F)", i);
1495 printf ("\n");
1496 printf ("Dump interface flags:");
1497 #ifdef COMPRESSED_INTERFACE_BITMAP
1499 const uint8_t* p = klass->interface_bitmap;
1500 i = klass->max_interface_id;
1501 while (i > 0) {
1502 printf (" %d x 00 %02X", p [0], p [1]);
1503 i -= p [0] * 8;
1504 i -= 8;
1507 #else
1508 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
1509 printf (" %02X", klass->interface_bitmap [i]);
1510 #endif
1511 printf ("\n");
1512 while (klass != NULL) {
1513 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
1514 ifaces = mono_class_get_implemented_interfaces (klass, error);
1515 if (!mono_error_ok (error)) {
1516 printf (" Type failed due to %s\n", mono_error_get_message (error));
1517 mono_error_cleanup (error);
1518 } else if (ifaces) {
1519 for (i = 0; i < ifaces->len; i++) {
1520 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1521 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
1522 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
1523 ic->interface_id,
1524 mono_class_interface_offset (klass, ic),
1525 mono_class_get_method_count (ic),
1526 ic->name_space,
1527 ic->name );
1529 g_ptr_array_free (ifaces, TRUE);
1531 ancestor_level ++;
1532 klass = klass->parent;
1537 * Return the number of virtual methods.
1538 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1539 * Return -1 on failure.
1540 * FIXME It would be nice if this information could be cached somewhere.
1542 static int
1543 count_virtual_methods (MonoClass *klass)
1545 int i, mcount, vcount = 0;
1546 guint32 flags;
1547 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
1549 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
1550 mono_class_setup_methods (klass);
1551 if (mono_class_has_failure (klass))
1552 return -1;
1554 mcount = mono_class_get_method_count (klass);
1555 for (i = 0; i < mcount; ++i) {
1556 flags = klass->methods [i]->flags;
1557 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
1558 ++vcount;
1560 } else {
1561 int first_idx = mono_class_get_first_method_idx (klass);
1562 mcount = mono_class_get_method_count (klass);
1563 for (i = 0; i < mcount; ++i) {
1564 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
1566 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
1567 ++vcount;
1570 return vcount;
1573 static mono_bool
1574 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
1576 int i;
1577 for (i = 0; i < num_ifaces; ++i) {
1578 if (interfaces_full [i] && interfaces_full [i]->interface_id == ic->interface_id) {
1579 if (!force_set)
1580 return TRUE;
1581 interface_offsets_full [i] = offset;
1582 return FALSE;
1584 if (interfaces_full [i])
1585 continue;
1586 interfaces_full [i] = ic;
1587 interface_offsets_full [i] = offset;
1588 break;
1590 return FALSE;
1593 #ifdef COMPRESSED_INTERFACE_BITMAP
1596 * Compressed interface bitmap design.
1598 * Interface bitmaps take a large amount of memory, because their size is
1599 * linear with the maximum interface id assigned in the process (each interface
1600 * is assigned a unique id as it is loaded). The number of interface classes
1601 * is high because of the many implicit interfaces implemented by arrays (we'll
1602 * need to lazy-load them in the future).
1603 * Most classes implement a very small number of interfaces, so the bitmap is
1604 * sparse. This bitmap needs to be checked by interface casts, so access to the
1605 * needed bit must be fast and doable with few jit instructions.
1607 * The current compression format is as follows:
1608 * *) it is a sequence of one or more two-byte elements
1609 * *) the first byte in the element is the count of empty bitmap bytes
1610 * at the current bitmap position
1611 * *) the second byte in the element is an actual bitmap byte at the current
1612 * bitmap position
1614 * As an example, the following compressed bitmap bytes:
1615 * 0x07 0x01 0x00 0x7
1616 * correspond to the following bitmap:
1617 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1619 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1620 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1621 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1625 * mono_compress_bitmap:
1626 * \param dest destination buffer
1627 * \param bitmap bitmap buffer
1628 * \param size size of \p bitmap in bytes
1630 * This is a mono internal function.
1631 * The \p bitmap data is compressed into a format that is small but
1632 * still searchable in few instructions by the JIT and runtime.
1633 * The compressed data is stored in the buffer pointed to by the
1634 * \p dest array. Passing a NULL value for \p dest allows to just compute
1635 * the size of the buffer.
1636 * This compression algorithm assumes the bits set in the bitmap are
1637 * few and far between, like in interface bitmaps.
1638 * \returns The size of the compressed bitmap in bytes.
1641 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
1643 int numz = 0;
1644 int res = 0;
1645 const uint8_t *end = bitmap + size;
1646 while (bitmap < end) {
1647 if (*bitmap || numz == 255) {
1648 if (dest) {
1649 *dest++ = numz;
1650 *dest++ = *bitmap;
1652 res += 2;
1653 numz = 0;
1654 bitmap++;
1655 continue;
1657 bitmap++;
1658 numz++;
1660 if (numz) {
1661 res += 2;
1662 if (dest) {
1663 *dest++ = numz;
1664 *dest++ = 0;
1667 return res;
1671 * mono_class_interface_match:
1672 * \param bitmap a compressed bitmap buffer
1673 * \param id the index to check in the bitmap
1675 * This is a mono internal function.
1676 * Checks if a bit is set in a compressed interface bitmap. \p id must
1677 * be already checked for being smaller than the maximum id encoded in the
1678 * bitmap.
1680 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1681 * FALSE otherwise.
1684 mono_class_interface_match (const uint8_t *bitmap, int id)
1686 while (TRUE) {
1687 id -= bitmap [0] * 8;
1688 if (id < 8) {
1689 if (id < 0)
1690 return 0;
1691 return bitmap [1] & (1 << id);
1693 bitmap += 2;
1694 id -= 8;
1697 #endif
1699 typedef struct {
1700 MonoClass *ic;
1701 int offset;
1702 int insertion_order;
1703 } ClassAndOffset;
1705 static int
1706 compare_by_interface_id (const void *a, const void *b)
1708 const ClassAndOffset *ca = (const ClassAndOffset*)a;
1709 const ClassAndOffset *cb = (const ClassAndOffset*)b;
1711 /* Sort on interface_id, but keep equal elements in the same relative
1712 * order. */
1713 int primary_order = ca->ic->interface_id - cb->ic->interface_id;
1714 if (primary_order != 0)
1715 return primary_order;
1716 else
1717 return ca->insertion_order - cb->insertion_order;
1721 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1722 * LOCKING: Acquires the loader lock.
1724 static int
1725 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
1727 ERROR_DECL (error);
1728 MonoClass *k, *ic;
1729 int i, j, num_ifaces;
1730 guint32 max_iid;
1731 MonoClass **interfaces_full = NULL;
1732 int *interface_offsets_full = NULL;
1733 GPtrArray *ifaces;
1734 GPtrArray **ifaces_array = NULL;
1735 int interface_offsets_count;
1736 max_iid = 0;
1737 num_ifaces = interface_offsets_count = 0;
1739 mono_loader_lock ();
1741 mono_class_setup_supertypes (klass);
1743 if (mono_class_is_ginst (klass)) {
1744 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1746 interface_offsets_count = num_ifaces = gklass->interface_offsets_count;
1747 interfaces_full = (MonoClass **)g_malloc (sizeof (MonoClass*) * num_ifaces);
1748 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1750 cur_slot = 0;
1751 for (int i = 0; i < num_ifaces; ++i) {
1752 MonoClass *gklass_ic = gklass->interfaces_packed [i];
1753 MonoClass *inflated = mono_class_inflate_generic_class_checked (gklass_ic, mono_class_get_context(klass), error);
1754 if (!is_ok (error)) {
1755 char *name = mono_type_get_full_name (gklass_ic);
1756 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1757 g_free (name);
1758 cur_slot = -1;
1759 goto end;
1762 mono_class_setup_interface_id_internal (inflated);
1764 interfaces_full [i] = inflated;
1765 interface_offsets_full [i] = gklass->interface_offsets_packed [i];
1767 int count = count_virtual_methods (inflated);
1768 if (count == -1) {
1769 char *name = mono_type_get_full_name (inflated);
1770 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1771 g_free (name);
1772 cur_slot = -1;
1773 goto end;
1776 cur_slot = MAX (cur_slot, interface_offsets_full [i] + count);
1777 max_iid = MAX (max_iid, inflated->interface_id);
1780 goto publish;
1782 /* compute maximum number of slots and maximum interface id */
1783 max_iid = 0;
1784 num_ifaces = 0; /* this can include duplicated ones */
1785 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
1786 for (j = 0; j < klass->idepth; j++) {
1787 k = klass->supertypes [j];
1788 g_assert (k);
1789 num_ifaces += k->interface_count;
1790 for (i = 0; i < k->interface_count; i++) {
1791 ic = k->interfaces [i];
1793 /* A gparam does not have any interface_id set. */
1794 if (! mono_class_is_gparam (ic))
1795 mono_class_setup_interface_id_internal (ic);
1797 if (max_iid < ic->interface_id)
1798 max_iid = ic->interface_id;
1800 ifaces = mono_class_get_implemented_interfaces (k, error);
1801 if (!mono_error_ok (error)) {
1802 char *name = mono_type_get_full_name (k);
1803 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (error));
1804 g_free (name);
1805 mono_error_cleanup (error);
1806 cur_slot = -1;
1807 goto end;
1809 if (ifaces) {
1810 num_ifaces += ifaces->len;
1811 for (i = 0; i < ifaces->len; ++i) {
1812 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1813 if (max_iid < ic->interface_id)
1814 max_iid = ic->interface_id;
1816 ifaces_array [j] = ifaces;
1820 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
1821 num_ifaces++;
1822 if (max_iid < klass->interface_id)
1823 max_iid = klass->interface_id;
1826 /* compute vtable offset for interfaces */
1827 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
1828 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1830 for (i = 0; i < num_ifaces; i++)
1831 interface_offsets_full [i] = -1;
1833 /* skip the current class */
1834 for (j = 0; j < klass->idepth - 1; j++) {
1835 k = klass->supertypes [j];
1836 ifaces = ifaces_array [j];
1838 if (ifaces) {
1839 for (i = 0; i < ifaces->len; ++i) {
1840 int io;
1841 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1843 /*Force the sharing of interface offsets between parent and subtypes.*/
1844 io = mono_class_interface_offset (k, ic);
1845 g_assertf (io >= 0, "class %s parent %s has no offset for iface %s",
1846 mono_type_get_full_name (klass),
1847 mono_type_get_full_name (k),
1848 mono_type_get_full_name (ic));
1850 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
1855 g_assert (klass == klass->supertypes [klass->idepth - 1]);
1856 ifaces = ifaces_array [klass->idepth - 1];
1857 if (ifaces) {
1858 for (i = 0; i < ifaces->len; ++i) {
1859 int count;
1860 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1861 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
1862 continue;
1863 count = count_virtual_methods (ic);
1864 if (count == -1) {
1865 char *name = mono_type_get_full_name (ic);
1866 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1867 g_free (name);
1868 cur_slot = -1;
1869 goto end;
1871 cur_slot += count;
1875 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass))
1876 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
1878 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
1879 if (interface_offsets_full [i] != -1)
1880 interface_offsets_count ++;
1883 publish:
1884 /* Publish the data */
1885 klass->max_interface_id = max_iid;
1887 * We might get called multiple times:
1888 * - mono_class_init_internal ()
1889 * - mono_class_setup_vtable ().
1890 * - mono_class_setup_interface_offsets ().
1891 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1892 * means we have to overwrite those when called from other places (#4440).
1894 if (klass->interfaces_packed) {
1895 if (!overwrite)
1896 g_assert (klass->interface_offsets_count == interface_offsets_count);
1897 } else {
1898 uint8_t *bitmap;
1899 int bsize;
1900 klass->interface_offsets_count = interface_offsets_count;
1901 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
1902 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
1903 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
1904 #ifdef COMPRESSED_INTERFACE_BITMAP
1905 bitmap = g_malloc0 (bsize);
1906 #else
1907 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
1908 #endif
1909 for (i = 0; i < interface_offsets_count; i++) {
1910 guint32 id = interfaces_full [i]->interface_id;
1911 bitmap [id >> 3] |= (1 << (id & 7));
1912 klass->interfaces_packed [i] = interfaces_full [i];
1913 klass->interface_offsets_packed [i] = interface_offsets_full [i];
1915 #ifdef COMPRESSED_INTERFACE_BITMAP
1916 i = mono_compress_bitmap (NULL, bitmap, bsize);
1917 klass->interface_bitmap = mono_class_alloc0 (klass, i);
1918 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
1919 g_free (bitmap);
1920 #else
1921 klass->interface_bitmap = bitmap;
1922 #endif
1924 end:
1925 mono_loader_unlock ();
1927 g_free (interfaces_full);
1928 g_free (interface_offsets_full);
1929 if (ifaces_array) {
1930 for (i = 0; i < klass->idepth; i++) {
1931 ifaces = ifaces_array [i];
1932 if (ifaces)
1933 g_ptr_array_free (ifaces, TRUE);
1935 g_free (ifaces_array);
1938 //printf ("JUST DONE: ");
1939 //print_implemented_interfaces (klass);
1941 return cur_slot;
1945 * Setup interface offsets for interfaces.
1946 * Initializes:
1947 * - klass->max_interface_id
1948 * - klass->interface_offsets_count
1949 * - klass->interfaces_packed
1950 * - klass->interface_offsets_packed
1951 * - klass->interface_bitmap
1953 * This function can fail @class.
1956 void
1957 mono_class_setup_interface_offsets (MonoClass *klass)
1959 /* NOTE: This function is only correct for interfaces.
1961 * It assumes that klass's interfaces can be assigned offsets starting
1962 * from 0. That assumption is incorrect for classes and valuetypes.
1964 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && !mono_class_is_ginst (klass));
1965 setup_interface_offsets (klass, 0, FALSE);
1968 #define DEBUG_INTERFACE_VTABLE_CODE 0
1969 #define TRACE_INTERFACE_VTABLE_CODE 0
1970 #define VERIFY_INTERFACE_VTABLE_CODE 0
1971 #define VTABLE_SELECTOR (1)
1973 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
1974 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
1975 if (!(VTABLE_SELECTOR)) break; \
1976 stmt;\
1977 } while (0)
1978 #else
1979 #define DEBUG_INTERFACE_VTABLE(stmt)
1980 #endif
1982 #if TRACE_INTERFACE_VTABLE_CODE
1983 #define TRACE_INTERFACE_VTABLE(stmt) do {\
1984 if (!(VTABLE_SELECTOR)) break; \
1985 stmt;\
1986 } while (0)
1987 #else
1988 #define TRACE_INTERFACE_VTABLE(stmt)
1989 #endif
1991 #if VERIFY_INTERFACE_VTABLE_CODE
1992 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
1993 if (!(VTABLE_SELECTOR)) break; \
1994 stmt;\
1995 } while (0)
1996 #else
1997 #define VERIFY_INTERFACE_VTABLE(stmt)
1998 #endif
2001 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2002 static char*
2003 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
2005 int i;
2006 char *result;
2007 GString *res = g_string_new ("");
2009 g_string_append_c (res, '(');
2010 for (i = 0; i < sig->param_count; ++i) {
2011 if (i > 0)
2012 g_string_append_c (res, ',');
2013 mono_type_get_desc (res, sig->params [i], include_namespace);
2015 g_string_append (res, ")=>");
2016 if (sig->ret != NULL) {
2017 mono_type_get_desc (res, sig->ret, include_namespace);
2018 } else {
2019 g_string_append (res, "NULL");
2021 result = res->str;
2022 g_string_free (res, FALSE);
2023 return result;
2025 static void
2026 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
2027 char *im_sig = mono_signature_get_full_desc (mono_method_signature_internal (im), TRUE);
2028 char *cm_sig = mono_signature_get_full_desc (mono_method_signature_internal (cm), TRUE);
2029 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
2030 g_free (im_sig);
2031 g_free (cm_sig);
2035 #endif
2037 static gboolean
2038 is_wcf_hack_disabled (void)
2040 static char disabled;
2041 if (!disabled)
2042 disabled = g_hasenv ("MONO_DISABLE_WCF_HACK") ? 1 : 2;
2043 return disabled == 1;
2046 static gboolean
2047 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
2049 MonoMethodSignature *cmsig, *imsig;
2050 if (strcmp (im->name, cm->name) == 0) {
2051 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
2052 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2053 return FALSE;
2055 if (! slot_is_empty) {
2056 if (require_newslot) {
2057 if (! interface_is_explicitly_implemented_by_class) {
2058 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2059 return FALSE;
2061 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
2062 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2063 return FALSE;
2065 } else {
2066 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2069 cmsig = mono_method_signature_internal (cm);
2070 imsig = mono_method_signature_internal (im);
2071 if (!cmsig || !imsig) {
2072 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2073 return FALSE;
2076 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2077 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2078 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2079 TRACE_INTERFACE_VTABLE (printf ("]"));
2080 return FALSE;
2082 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2083 if (mono_security_core_clr_enabled ())
2084 mono_security_core_clr_check_override (klass, cm, im);
2086 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2087 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2088 char *body_name = mono_method_full_name (cm, TRUE);
2089 char *decl_name = mono_method_full_name (im, TRUE);
2090 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2091 g_free (body_name);
2092 g_free (decl_name);
2093 return FALSE;
2096 return TRUE;
2097 } else {
2098 MonoClass *ic = im->klass;
2099 const char *ic_name_space = ic->name_space;
2100 const char *ic_name = ic->name;
2101 char *subname;
2103 if (! require_newslot) {
2104 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2105 return FALSE;
2107 if (cm->klass->rank == 0) {
2108 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2109 return FALSE;
2111 cmsig = mono_method_signature_internal (cm);
2112 imsig = mono_method_signature_internal (im);
2113 if (!cmsig || !imsig) {
2114 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2115 return FALSE;
2118 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2119 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2120 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2121 TRACE_INTERFACE_VTABLE (printf ("]"));
2122 return FALSE;
2124 if (mono_class_get_image (ic) != mono_defaults.corlib) {
2125 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2126 return FALSE;
2128 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
2129 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2130 return FALSE;
2132 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))) {
2133 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2134 return FALSE;
2137 subname = (char*)strstr (cm->name, ic_name_space);
2138 if (subname != cm->name) {
2139 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2140 return FALSE;
2142 subname += strlen (ic_name_space);
2143 if (subname [0] != '.') {
2144 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2145 return FALSE;
2147 subname ++;
2148 if (strstr (subname, ic_name) != subname) {
2149 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2150 return FALSE;
2152 subname += strlen (ic_name);
2153 if (subname [0] != '.') {
2154 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2155 return FALSE;
2157 subname ++;
2158 if (strcmp (subname, im->name) != 0) {
2159 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2160 return FALSE;
2163 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2164 if (mono_security_core_clr_enabled ())
2165 mono_security_core_clr_check_override (klass, cm, im);
2167 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2168 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2169 char *body_name = mono_method_full_name (cm, TRUE);
2170 char *decl_name = mono_method_full_name (im, TRUE);
2171 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2172 g_free (body_name);
2173 g_free (decl_name);
2174 return FALSE;
2177 return TRUE;
2181 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2182 static void
2183 foreach_override (gpointer key, gpointer value, gpointer user_data)
2185 MonoMethod *method = key;
2186 MonoMethod *override = value;
2188 char *method_name = mono_method_get_full_name (method);
2189 char *override_name = mono_method_get_full_name (override);
2190 printf (" Method '%s' has override '%s'\n", method_name, override_name);
2191 g_free (method_name);
2192 g_free (override_name);
2195 static void
2196 print_overrides (GHashTable *override_map, const char *message)
2198 if (override_map) {
2199 printf ("Override map \"%s\" START:\n", message);
2200 g_hash_table_foreach (override_map, foreach_override, NULL);
2201 printf ("Override map \"%s\" END.\n", message);
2202 } else {
2203 printf ("Override map \"%s\" EMPTY.\n", message);
2207 static void
2208 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces)
2210 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2211 int i;
2212 int parent_size;
2214 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
2216 if (print_interfaces) {
2217 print_implemented_interfaces (klass);
2218 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
2221 if (klass->parent) {
2222 parent_size = klass->parent->vtable_size;
2223 } else {
2224 parent_size = 0;
2226 for (i = 0; i < size; ++i) {
2227 MonoMethod *cm = vtable [i];
2228 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
2229 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
2231 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
2232 g_free (cm_name);
2235 g_free (full_name);
2237 #endif
2239 #if VERIFY_INTERFACE_VTABLE_CODE
2240 static int
2241 mono_method_try_get_vtable_index (MonoMethod *method)
2243 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2244 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
2245 if (imethod->declaring->is_generic)
2246 return imethod->declaring->slot;
2248 return method->slot;
2251 static void
2252 mono_class_verify_vtable (MonoClass *klass)
2254 int i, count;
2255 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2257 printf ("*** Verifying VTable of class '%s' \n", full_name);
2258 g_free (full_name);
2259 full_name = NULL;
2261 if (!klass->methods)
2262 return;
2264 count = mono_class_get_method_count (klass);
2265 for (i = 0; i < count; ++i) {
2266 MonoMethod *cm = klass->methods [i];
2267 int slot;
2269 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2270 continue;
2272 g_free (full_name);
2273 full_name = mono_method_full_name (cm, TRUE);
2275 slot = mono_method_try_get_vtable_index (cm);
2276 if (slot >= 0) {
2277 if (slot >= klass->vtable_size) {
2278 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
2279 continue;
2282 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
2283 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
2284 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
2285 g_free (other_name);
2287 } else
2288 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
2290 g_free (full_name);
2292 #endif
2294 static MonoMethod*
2295 mono_method_get_method_definition (MonoMethod *method)
2297 while (method->is_inflated)
2298 method = ((MonoMethodInflated*)method)->declaring;
2299 return method;
2302 static gboolean
2303 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
2305 int i;
2307 for (i = 0; i < onum; ++i) {
2308 MonoMethod *decl = overrides [i * 2];
2309 MonoMethod *body = overrides [i * 2 + 1];
2311 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
2312 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
2313 return FALSE;
2316 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
2317 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2318 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
2319 else
2320 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
2321 return FALSE;
2324 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
2325 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2326 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
2327 else
2328 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
2329 return FALSE;
2332 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
2333 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
2334 return FALSE;
2337 body = mono_method_get_method_definition (body);
2338 decl = mono_method_get_method_definition (decl);
2340 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
2341 char *body_name = mono_method_full_name (body, TRUE);
2342 char *decl_name = mono_method_full_name (decl, TRUE);
2343 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2344 g_free (body_name);
2345 g_free (decl_name);
2346 return FALSE;
2349 return TRUE;
2352 /*Checks if @klass has @parent as one of it's parents type gtd
2354 * For example:
2355 * Foo<T>
2356 * Bar<T> : Foo<Bar<Bar<T>>>
2359 static gboolean
2360 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
2362 klass = mono_class_get_generic_type_definition (klass);
2363 parent = mono_class_get_generic_type_definition (parent);
2364 mono_class_setup_supertypes (klass);
2365 mono_class_setup_supertypes (parent);
2367 return klass->idepth >= parent->idepth &&
2368 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
2371 gboolean
2372 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
2374 MonoGenericInst *ginst;
2375 int i;
2377 if (!mono_class_is_ginst (klass)) {
2378 mono_class_setup_vtable_full (klass, in_setup);
2379 return !mono_class_has_failure (klass);
2382 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
2383 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
2384 return FALSE;
2386 ginst = mono_class_get_generic_class (klass)->context.class_inst;
2387 for (i = 0; i < ginst->type_argc; ++i) {
2388 MonoClass *arg;
2389 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
2390 continue;
2391 arg = mono_class_from_mono_type_internal (ginst->type_argv [i]);
2392 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2393 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
2394 continue;
2395 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
2396 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
2397 return FALSE;
2400 return TRUE;
2404 * mono_class_setup_vtable:
2406 * Creates the generic vtable of CLASS.
2407 * Initializes the following fields in MonoClass:
2408 * - vtable
2409 * - vtable_size
2410 * Plus all the fields initialized by setup_interface_offsets ().
2411 * If there is an error during vtable construction, klass->has_failure
2412 * is set and details are stored in a MonoErrorBoxed.
2414 * LOCKING: Acquires the loader lock.
2416 void
2417 mono_class_setup_vtable (MonoClass *klass)
2419 mono_class_setup_vtable_full (klass, NULL);
2422 static void
2423 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
2425 ERROR_DECL (error);
2426 MonoMethod **overrides = NULL;
2427 MonoGenericContext *context;
2428 guint32 type_token;
2429 int onum = 0;
2431 if (klass->vtable)
2432 return;
2434 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
2435 /* This sets method->slot for all methods if this is an interface */
2436 mono_class_setup_methods (klass);
2437 return;
2440 if (mono_class_has_failure (klass))
2441 return;
2443 if (g_list_find (in_setup, klass))
2444 return;
2446 mono_loader_lock ();
2448 if (klass->vtable) {
2449 mono_loader_unlock ();
2450 return;
2453 UnlockedIncrement (&mono_stats.generic_vtable_count);
2454 in_setup = g_list_prepend (in_setup, klass);
2456 if (mono_class_is_ginst (klass)) {
2457 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
2458 mono_loader_unlock ();
2459 g_list_remove (in_setup, klass);
2460 return;
2463 context = mono_class_get_context (klass);
2464 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
2465 } else {
2466 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
2467 type_token = klass->type_token;
2470 if (image_is_dynamic (klass->image)) {
2471 /* Generic instances can have zero method overrides without causing any harm.
2472 * This is true since we don't do layout all over again for them, we simply inflate
2473 * the layout of the parent.
2475 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, error);
2476 if (!is_ok (error)) {
2477 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2478 goto done;
2480 } else {
2481 /* The following call fails if there are missing methods in the type */
2482 /* FIXME it's probably a good idea to avoid this for generic instances. */
2483 mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context, error);
2484 if (!is_ok (error)) {
2485 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2486 goto done;
2490 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
2492 done:
2493 g_free (overrides);
2494 mono_error_cleanup (error);
2496 mono_loader_unlock ();
2497 g_list_remove (in_setup, klass);
2499 return;
2502 static gboolean
2503 mono_class_need_stelemref_method (MonoClass *klass)
2505 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass)));
2508 static int
2509 apply_override (MonoClass *klass, MonoClass *override_class, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override,
2510 GHashTable **override_map, GHashTable **override_class_map, GHashTable **conflict_map)
2512 int dslot;
2513 dslot = mono_method_get_vtable_slot (decl);
2514 if (dslot == -1) {
2515 mono_class_set_type_load_failure (klass, "");
2516 return FALSE;
2519 dslot += mono_class_interface_offset (klass, decl->klass);
2520 vtable [dslot] = override;
2521 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass)) {
2523 * If override from an interface, then it is an override of a default interface method,
2524 * don't override its slot.
2526 vtable [dslot]->slot = dslot;
2529 if (!*override_map) {
2530 *override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2531 *override_class_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2533 GHashTable *map = *override_map;
2534 GHashTable *class_map = *override_class_map;
2536 MonoMethod *prev_override = (MonoMethod*)g_hash_table_lookup (map, decl);
2537 MonoClass *prev_override_class = (MonoClass*)g_hash_table_lookup (class_map, decl);
2539 g_hash_table_insert (map, decl, override);
2540 g_hash_table_insert (class_map, decl, override_class);
2542 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2543 if (prev_override) {
2544 ERROR_DECL (error);
2547 * The override methods are part of the generic definition, need to inflate them so their
2548 * parent class becomes the actual interface/class containing the override, i.e.
2549 * IFace<T> in:
2550 * class Foo<T> : IFace<T>
2551 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2552 * conflict resolution work.
2554 if (mono_class_is_ginst (override_class)) {
2555 override = mono_class_inflate_generic_method_checked (override, &mono_class_get_generic_class (override_class)->context, error);
2556 mono_error_assert_ok (error);
2559 if (mono_class_is_ginst (prev_override_class)) {
2560 prev_override = mono_class_inflate_generic_method_checked (prev_override, &mono_class_get_generic_class (prev_override_class)->context, error);
2561 mono_error_assert_ok (error);
2564 if (!*conflict_map)
2565 *conflict_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2566 GHashTable *cmap = *conflict_map;
2567 GSList *entries = (GSList*)g_hash_table_lookup (cmap, decl);
2568 if (!(decl->flags & METHOD_ATTRIBUTE_ABSTRACT))
2569 entries = g_slist_prepend (entries, decl);
2570 entries = g_slist_prepend (entries, prev_override);
2571 entries = g_slist_prepend (entries, override);
2573 g_hash_table_insert (cmap, decl, entries);
2576 return TRUE;
2579 static void
2580 handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflict_map)
2582 GHashTableIter iter;
2583 MonoMethod *decl;
2584 GSList *entries, *l, *l2;
2585 GSList *dim_conflicts = NULL;
2587 g_hash_table_iter_init (&iter, conflict_map);
2588 while (g_hash_table_iter_next (&iter, (gpointer*)&decl, (gpointer*)&entries)) {
2590 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2591 * class of another one.
2593 /* This is O(n^2), but that shouldn't be a problem in practice */
2594 for (l = entries; l; l = l->next) {
2595 for (l2 = entries; l2; l2 = l2->next) {
2596 MonoMethod *m1 = (MonoMethod*)l->data;
2597 MonoMethod *m2 = (MonoMethod*)l2->data;
2598 if (!m1 || !m2 || m1 == m2)
2599 continue;
2600 if (mono_class_is_assignable_from_internal (m1->klass, m2->klass))
2601 l->data = NULL;
2602 else if (mono_class_is_assignable_from_internal (m2->klass, m1->klass))
2603 l2->data = NULL;
2606 int nentries = 0;
2607 MonoMethod *impl = NULL;
2608 for (l = entries; l; l = l->next) {
2609 if (l->data) {
2610 nentries ++;
2611 impl = (MonoMethod*)l->data;
2614 if (nentries > 1) {
2615 /* If more than one method is left, we have a conflict */
2616 if (decl->is_inflated)
2617 decl = ((MonoMethodInflated*)decl)->declaring;
2618 dim_conflicts = g_slist_prepend (dim_conflicts, decl);
2620 for (l = entries; l; l = l->next) {
2621 if (l->data)
2622 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2625 } else {
2627 * Use the implementing method computed above instead of the already
2628 * computed one, which depends on interface ordering.
2630 int ic_offset = mono_class_interface_offset (klass, decl->klass);
2631 int im_slot = ic_offset + decl->slot;
2632 vtable [im_slot] = impl;
2634 g_slist_free (entries);
2636 if (dim_conflicts) {
2637 mono_loader_lock ();
2638 klass->has_dim_conflicts = 1;
2639 mono_loader_unlock ();
2642 * Exceptions are thrown at method call time and only for the methods which have
2643 * conflicts, so just save them in the class.
2646 /* Make a copy of the list from the class mempool */
2647 GSList *conflicts = (GSList*)mono_class_alloc0 (klass, g_slist_length (dim_conflicts) * sizeof (GSList));
2648 int i = 0;
2649 for (l = dim_conflicts; l; l = l->next) {
2650 conflicts [i].data = l->data;
2651 conflicts [i].next = &conflicts [i + 1];
2652 i ++;
2654 conflicts [i - 1].next = NULL;
2656 mono_class_set_dim_conflicts (klass, conflicts);
2657 g_slist_free (dim_conflicts);
2661 static void
2662 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
2664 int index, mcount;
2665 char *method_signature;
2666 char *type_name;
2668 for (index = 0; index < onum; ++index) {
2669 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name,
2670 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
2672 method_signature = mono_signature_get_desc (mono_method_signature_internal (im), FALSE);
2673 type_name = mono_type_full_name (m_class_get_byval_arg (klass));
2674 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s",
2675 mono_type_get_name (m_class_get_byval_arg (ic)), im->name, method_signature, type_name);
2676 g_free (method_signature);
2677 g_free (type_name);
2678 mono_class_setup_methods (klass);
2679 if (mono_class_has_failure (klass)) {
2680 char *name = mono_type_get_full_name (klass);
2681 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name);
2682 g_free (name);
2683 return;
2685 mcount = mono_class_get_method_count (klass);
2686 for (index = 0; index < mcount; ++index) {
2687 MonoMethod *cm = klass->methods [index];
2688 method_signature = mono_signature_get_desc (mono_method_signature_internal (cm), TRUE);
2690 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature);
2691 g_free (method_signature);
2696 * mono_class_get_virtual_methods:
2698 * Iterate over the virtual methods of KLASS.
2700 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2702 static MonoMethod*
2703 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
2705 gboolean static_iter = FALSE;
2707 if (!iter)
2708 return NULL;
2711 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2712 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2713 * klass->methods.
2715 if ((gsize)(*iter) & 1)
2716 static_iter = TRUE;
2717 /* Use the static metadata only if klass->methods is not yet initialized */
2718 if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
2719 static_iter = TRUE;
2721 if (!static_iter) {
2722 MonoMethod** methodptr;
2724 if (!*iter) {
2725 mono_class_setup_methods (klass);
2727 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2728 * FIXME we should better report this error to the caller
2730 if (!klass->methods)
2731 return NULL;
2732 /* start from the first */
2733 methodptr = &klass->methods [0];
2734 } else {
2735 methodptr = (MonoMethod **)*iter;
2736 methodptr++;
2738 if (*iter)
2739 g_assert ((guint64)(*iter) > 0x100);
2740 int mcount = mono_class_get_method_count (klass);
2741 while (methodptr < &klass->methods [mcount]) {
2742 if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
2743 break;
2744 methodptr ++;
2746 if (methodptr < &klass->methods [mcount]) {
2747 *iter = methodptr;
2748 return *methodptr;
2749 } else {
2750 return NULL;
2752 } else {
2753 /* Search directly in metadata to avoid calling setup_methods () */
2754 MonoMethod *res = NULL;
2755 int i, start_index;
2757 if (!*iter) {
2758 start_index = 0;
2759 } else {
2760 start_index = GPOINTER_TO_UINT (*iter) >> 1;
2763 int first_idx = mono_class_get_first_method_idx (klass);
2764 int mcount = mono_class_get_method_count (klass);
2765 for (i = start_index; i < mcount; ++i) {
2766 guint32 flags;
2768 /* first_idx points into the methodptr table */
2769 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
2771 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2772 break;
2775 if (i < mcount) {
2776 ERROR_DECL (error);
2777 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
2778 mono_error_cleanup (error); /* FIXME don't swallow the error */
2780 /* Add 1 here so the if (*iter) check fails */
2781 *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1);
2782 return res;
2783 } else {
2784 return NULL;
2789 static void
2790 print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot)
2792 int i, icount = 0;
2794 print_implemented_interfaces (klass);
2796 for (i = 0; i <= klass->max_interface_id; i++)
2797 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2798 icount++;
2800 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass)),
2801 klass->vtable_size, icount);
2803 for (i = 0; i < cur_slot; ++i) {
2804 MonoMethod *cm;
2806 cm = vtable [i];
2807 if (cm) {
2808 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
2809 mono_method_get_full_name (cm));
2810 } else {
2811 printf (" slot assigned: %03d, <null>\n", i);
2816 if (icount) {
2817 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
2818 klass->name, klass->max_interface_id);
2820 for (i = 0; i < klass->interface_count; i++) {
2821 MonoClass *ic = klass->interfaces [i];
2822 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2823 mono_class_interface_offset (klass, ic),
2824 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2827 for (MonoClass *k = klass->parent; k ; k = k->parent) {
2828 for (i = 0; i < k->interface_count; i++) {
2829 MonoClass *ic = k->interfaces [i];
2830 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2831 mono_class_interface_offset (klass, ic),
2832 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2839 * LOCKING: this is supposed to be called with the loader lock held.
2841 void
2842 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
2844 ERROR_DECL (error);
2845 MonoClass *k, *ic;
2846 MonoMethod **vtable = NULL;
2847 int i, max_vtsize = 0, cur_slot = 0;
2848 GPtrArray *ifaces = NULL;
2849 GHashTable *override_map = NULL;
2850 GHashTable *override_class_map = NULL;
2851 GHashTable *conflict_map = NULL;
2852 MonoMethod *cm;
2853 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2854 int first_non_interface_slot;
2855 #endif
2856 GSList *virt_methods = NULL, *l;
2857 int stelemref_slot = 0;
2859 error_init (error);
2861 if (klass->vtable)
2862 return;
2864 if (overrides && !verify_class_overrides (klass, overrides, onum))
2865 return;
2867 ifaces = mono_class_get_implemented_interfaces (klass, error);
2868 if (!mono_error_ok (error)) {
2869 char *name = mono_type_get_full_name (klass);
2870 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (error));
2871 g_free (name);
2872 mono_error_cleanup (error);
2873 return;
2874 } else if (ifaces) {
2875 for (i = 0; i < ifaces->len; i++) {
2876 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2877 max_vtsize += mono_class_get_method_count (ic);
2879 g_ptr_array_free (ifaces, TRUE);
2880 ifaces = NULL;
2883 if (klass->parent) {
2884 mono_class_init_internal (klass->parent);
2885 mono_class_setup_vtable_full (klass->parent, in_setup);
2887 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
2888 return;
2890 max_vtsize += klass->parent->vtable_size;
2891 cur_slot = klass->parent->vtable_size;
2894 max_vtsize += mono_class_get_method_count (klass);
2896 /*Array have a slot for stelemref*/
2897 if (mono_class_need_stelemref_method (klass)) {
2898 stelemref_slot = cur_slot;
2899 ++max_vtsize;
2900 ++cur_slot;
2903 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
2905 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
2906 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
2907 return;
2909 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
2911 /* Optimized version for generic instances */
2912 if (mono_class_is_ginst (klass)) {
2913 ERROR_DECL (error);
2914 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2915 MonoMethod **tmp;
2917 mono_class_setup_vtable_full (gklass, in_setup);
2918 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
2919 return;
2921 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
2922 klass->vtable_size = gklass->vtable_size;
2923 for (i = 0; i < gklass->vtable_size; ++i)
2924 if (gklass->vtable [i]) {
2925 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), error);
2926 goto_if_nok (error, fail);
2927 tmp [i] = inflated;
2928 tmp [i]->slot = gklass->vtable [i]->slot;
2930 mono_memory_barrier ();
2931 klass->vtable = tmp;
2933 mono_loader_lock ();
2934 klass->has_dim_conflicts = gklass->has_dim_conflicts;
2935 mono_loader_unlock ();
2937 /* Have to set method->slot for abstract virtual methods */
2938 if (klass->methods && gklass->methods) {
2939 int mcount = mono_class_get_method_count (klass);
2940 for (i = 0; i < mcount; ++i)
2941 if (klass->methods [i]->slot == -1)
2942 klass->methods [i]->slot = gklass->methods [i]->slot;
2945 if (mono_print_vtable)
2946 print_vtable_layout_result (klass, klass->vtable, gklass->vtable_size);
2948 return;
2951 vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize);
2953 if (klass->parent && klass->parent->vtable_size) {
2954 MonoClass *parent = klass->parent;
2955 int i;
2957 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
2959 // Also inherit parent interface vtables, just as a starting point.
2960 // This is needed otherwise bug-77127.exe fails when the property methods
2961 // have different names in the iterface and the class, because for child
2962 // classes the ".override" information is not used anymore.
2963 for (i = 0; i < parent->interface_offsets_count; i++) {
2964 MonoClass *parent_interface = parent->interfaces_packed [i];
2965 int interface_offset = mono_class_interface_offset (klass, parent_interface);
2966 /*FIXME this is now dead code as this condition will never hold true.
2967 Since interface offsets are inherited then the offset of an interface implemented
2968 by a parent will never be the out of it's vtable boundary.
2970 if (interface_offset >= parent->vtable_size) {
2971 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
2972 int j;
2974 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
2975 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
2976 int mcount = mono_class_get_method_count (parent_interface);
2977 for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
2978 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
2979 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
2980 parent_interface_offset + j, parent_interface_offset, j,
2981 interface_offset + j, interface_offset, j));
2988 /*Array have a slot for stelemref*/
2989 if (mono_class_need_stelemref_method (klass)) {
2990 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
2991 if (!method->slot)
2992 method->slot = stelemref_slot;
2993 else
2994 g_assert (method->slot == stelemref_slot);
2996 vtable [stelemref_slot] = method;
2999 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
3001 /* Process overrides from interface default methods */
3002 // FIXME: Ordering between interfaces
3003 for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
3004 ic = klass->interfaces_packed [ifindex];
3006 mono_class_setup_methods (ic);
3007 if (mono_class_has_failure (ic))
3008 goto fail;
3010 MonoMethod **iface_overrides;
3011 int iface_onum;
3012 mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic), error);
3013 goto_if_nok (error, fail);
3014 for (int i = 0; i < iface_onum; i++) {
3015 MonoMethod *decl = iface_overrides [i*2];
3016 MonoMethod *override = iface_overrides [i*2 + 1];
3017 if (decl->is_inflated) {
3018 override = mono_class_inflate_generic_method_checked (override, mono_method_get_context (decl), error);
3019 mono_error_assert_ok (error);
3021 if (!apply_override (klass, ic, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3022 goto fail;
3024 g_free (iface_overrides);
3027 /* override interface methods */
3028 for (i = 0; i < onum; i++) {
3029 MonoMethod *decl = overrides [i*2];
3030 MonoMethod *override = overrides [i*2 + 1];
3031 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3032 if (!apply_override (klass, klass, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3033 goto fail;
3037 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
3038 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
3041 * Create a list of virtual methods to avoid calling
3042 * mono_class_get_virtual_methods () which is slow because of the metadata
3043 * optimization.
3046 gpointer iter = NULL;
3047 MonoMethod *cm;
3049 virt_methods = NULL;
3050 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
3051 virt_methods = g_slist_prepend (virt_methods, cm);
3053 if (mono_class_has_failure (klass))
3054 goto fail;
3057 // Loop on all implemented interfaces...
3058 for (i = 0; i < klass->interface_offsets_count; i++) {
3059 MonoClass *parent = klass->parent;
3060 int ic_offset;
3061 gboolean interface_is_explicitly_implemented_by_class;
3062 int im_index;
3064 ic = klass->interfaces_packed [i];
3065 ic_offset = mono_class_interface_offset (klass, ic);
3067 mono_class_setup_methods (ic);
3068 if (mono_class_has_failure (ic))
3069 goto fail;
3071 // Check if this interface is explicitly implemented (instead of just inherited)
3072 if (parent != NULL) {
3073 int implemented_interfaces_index;
3074 interface_is_explicitly_implemented_by_class = FALSE;
3075 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
3076 if (ic == klass->interfaces [implemented_interfaces_index]) {
3077 interface_is_explicitly_implemented_by_class = TRUE;
3078 break;
3081 } else {
3082 interface_is_explicitly_implemented_by_class = TRUE;
3085 // Loop on all interface methods...
3086 int mcount = mono_class_get_method_count (ic);
3087 for (im_index = 0; im_index < mcount; im_index++) {
3088 gboolean foundOverrideInClassOrParent = FALSE;
3089 MonoMethod *im = ic->methods [im_index];
3090 int im_slot = ic_offset + im->slot;
3091 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
3093 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3094 continue;
3096 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
3098 int cm_index;
3099 MonoMethod *cm;
3101 // First look for a suitable method among the class methods
3102 for (l = virt_methods; l; l = l->next) {
3103 cm = (MonoMethod *)l->data;
3104 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)));
3105 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
3106 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3107 vtable [im_slot] = cm;
3108 foundOverrideInClassOrParent = TRUE;
3109 /* Why do we need this? */
3110 if (cm->slot < 0) {
3111 cm->slot = im_slot;
3113 if (conflict_map)
3114 g_hash_table_remove(conflict_map, im);
3116 TRACE_INTERFACE_VTABLE (printf ("\n"));
3117 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3118 goto fail;
3121 // If the slot is still empty, look in all the inherited virtual methods...
3122 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
3123 MonoClass *parent = klass->parent;
3124 // Reverse order, so that last added methods are preferred
3125 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
3126 cm = parent->vtable [cm_index];
3128 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));
3129 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
3130 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3131 vtable [im_slot] = cm;
3132 foundOverrideInClassOrParent = TRUE;
3133 /* Why do we need this? */
3134 if (cm->slot < 0) {
3135 cm->slot = im_slot;
3137 if (conflict_map)
3138 g_hash_table_remove(conflict_map, im);
3139 break;
3141 TRACE_INTERFACE_VTABLE (printf ("\n"));
3142 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3143 goto fail;
3147 if (vtable [im_slot] == NULL) {
3148 if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
3149 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im, 1)));
3150 vtable [im_slot] = im;
3154 if (override_im != NULL && !foundOverrideInClassOrParent)
3155 g_assert (vtable [im_slot] == override_im);
3159 // If the class is not abstract, check that all its interface slots are full.
3160 // The check is done here and not directly at the end of the loop above because
3161 // it can happen (for injected generic array interfaces) that the same slot is
3162 // processed multiple times (those interfaces have overlapping slots), and it
3163 // will not always be the first pass the one that fills the slot.
3164 if (!mono_class_is_abstract (klass)) {
3165 for (i = 0; i < klass->interface_offsets_count; i++) {
3166 int ic_offset;
3167 int im_index;
3169 ic = klass->interfaces_packed [i];
3170 ic_offset = mono_class_interface_offset (klass, ic);
3172 int mcount = mono_class_get_method_count (ic);
3173 for (im_index = 0; im_index < mcount; im_index++) {
3174 MonoMethod *im = ic->methods [im_index];
3175 int im_slot = ic_offset + im->slot;
3177 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3178 continue;
3180 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3181 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
3182 if (vtable [im_slot] == NULL) {
3183 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
3184 goto fail;
3190 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
3191 for (l = virt_methods; l; l = l->next) {
3192 cm = (MonoMethod *)l->data;
3194 * If the method is REUSE_SLOT, we must check in the
3195 * base class for a method to override.
3197 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3198 int slot = -1;
3199 for (k = klass->parent; k ; k = k->parent) {
3200 gpointer k_iter;
3201 MonoMethod *m1;
3203 k_iter = NULL;
3204 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
3205 MonoMethodSignature *cmsig, *m1sig;
3207 cmsig = mono_method_signature_internal (cm);
3208 m1sig = mono_method_signature_internal (m1);
3210 if (!cmsig || !m1sig) /* FIXME proper error message, use signature_checked? */
3211 goto fail;
3213 if (!strcmp(cm->name, m1->name) &&
3214 mono_metadata_signature_equal (cmsig, m1sig)) {
3216 if (mono_security_core_clr_enabled ())
3217 mono_security_core_clr_check_override (klass, cm, m1);
3219 slot = mono_method_get_vtable_slot (m1);
3220 if (slot == -1)
3221 goto fail;
3223 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
3224 char *body_name = mono_method_full_name (cm, TRUE);
3225 char *decl_name = mono_method_full_name (m1, TRUE);
3226 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3227 g_free (body_name);
3228 g_free (decl_name);
3229 goto fail;
3232 g_assert (cm->slot < max_vtsize);
3233 if (!override_map)
3234 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3235 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3236 mono_method_full_name (m1, 1), m1,
3237 mono_method_full_name (cm, 1), cm));
3238 g_hash_table_insert (override_map, m1, cm);
3239 break;
3242 if (mono_class_has_failure (k))
3243 goto fail;
3245 if (slot >= 0)
3246 break;
3248 if (slot >= 0)
3249 cm->slot = slot;
3252 /*Non final newslot methods must be given a non-interface vtable slot*/
3253 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
3254 cm->slot = -1;
3256 if (cm->slot < 0)
3257 cm->slot = cur_slot++;
3259 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
3260 vtable [cm->slot] = cm;
3263 /* override non interface methods */
3264 for (i = 0; i < onum; i++) {
3265 MonoMethod *decl = overrides [i*2];
3266 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3267 g_assert (decl->slot != -1);
3268 vtable [decl->slot] = overrides [i*2 + 1];
3269 overrides [i * 2 + 1]->slot = decl->slot;
3270 if (!override_map)
3271 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3272 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3273 mono_method_full_name (decl, 1), decl,
3274 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
3275 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
3277 if (mono_security_core_clr_enabled ())
3278 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
3283 * If a method occupies more than one place in the vtable, and it is
3284 * overriden, then change the other occurances too.
3286 if (override_map) {
3287 MonoMethod *cm;
3289 for (i = 0; i < max_vtsize; ++i)
3290 if (vtable [i]) {
3291 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
3293 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
3294 if (cm)
3295 vtable [i] = cm;
3298 g_hash_table_destroy (override_map);
3299 override_map = NULL;
3302 if (override_class_map)
3303 g_hash_table_destroy (override_class_map);
3305 if (conflict_map) {
3306 handle_dim_conflicts (vtable, klass, conflict_map);
3307 g_hash_table_destroy (conflict_map);
3310 g_slist_free (virt_methods);
3311 virt_methods = NULL;
3313 g_assert (cur_slot <= max_vtsize);
3315 /* Ensure that all vtable slots are filled with concrete instance methods */
3316 if (!mono_class_is_abstract (klass)) {
3317 for (i = 0; i < cur_slot; ++i) {
3318 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
3319 char *type_name = mono_type_get_full_name (klass);
3320 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
3321 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
3322 g_free (type_name);
3323 g_free (method_name);
3325 if (mono_print_vtable)
3326 print_vtable_layout_result (klass, vtable, cur_slot);
3328 g_free (vtable);
3329 return;
3334 if (mono_class_is_ginst (klass)) {
3335 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3337 mono_class_init_internal (gklass);
3339 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
3340 } else {
3341 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
3342 if (klass->vtable_size)
3343 g_assert (cur_slot == klass->vtable_size);
3344 klass->vtable_size = cur_slot;
3347 /* Try to share the vtable with our parent. */
3348 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
3349 mono_memory_barrier ();
3350 klass->vtable = klass->parent->vtable;
3351 } else {
3352 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
3353 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
3354 mono_memory_barrier ();
3355 klass->vtable = tmp;
3358 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
3359 if (mono_print_vtable)
3360 print_vtable_layout_result (klass, vtable, cur_slot);
3362 g_free (vtable);
3364 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
3365 return;
3367 fail:
3369 char *name = mono_type_get_full_name (klass);
3370 if (!is_ok (error))
3371 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (error));
3372 else
3373 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
3374 mono_error_cleanup (error);
3375 g_free (name);
3376 if (mono_print_vtable)
3377 print_vtable_layout_result (klass, vtable, cur_slot);
3380 g_free (vtable);
3381 if (override_map)
3382 g_hash_table_destroy (override_map);
3383 if (virt_methods)
3384 g_slist_free (virt_methods);
3388 static char*
3389 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
3391 int null_length = strlen ("(null)");
3392 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
3393 char *s = (char *)mono_image_alloc (image, len);
3394 int result;
3396 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
3397 g_assert (result == len - 1);
3399 return s;
3403 static void
3404 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
3406 if (cached_info) {
3407 mono_loader_lock ();
3408 klass->instance_size = cached_info->instance_size;
3409 klass->sizes.class_size = cached_info->class_size;
3410 klass->packing_size = cached_info->packing_size;
3411 klass->min_align = cached_info->min_align;
3412 klass->blittable = cached_info->blittable;
3413 klass->has_references = cached_info->has_references;
3414 klass->has_static_refs = cached_info->has_static_refs;
3415 klass->no_special_static_fields = cached_info->no_special_static_fields;
3416 klass->has_weak_fields = cached_info->has_weak_fields;
3417 mono_loader_unlock ();
3419 else {
3420 if (!klass->size_inited)
3421 mono_class_setup_fields (klass);
3426 * mono_class_init_sizes:
3428 * Initializes the size related fields of @klass without loading all field data if possible.
3429 * Sets the following fields in @klass:
3430 * - instance_size
3431 * - sizes.class_size
3432 * - packing_size
3433 * - min_align
3434 * - blittable
3435 * - has_references
3436 * - has_static_refs
3437 * - size_inited
3438 * Can fail the class.
3440 * LOCKING: Acquires the loader lock.
3442 void
3443 mono_class_init_sizes (MonoClass *klass)
3445 MonoCachedClassInfo cached_info;
3446 gboolean has_cached_info;
3448 if (klass->size_inited)
3449 return;
3451 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
3453 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
3457 static gboolean
3458 class_has_references (MonoClass *klass)
3460 mono_class_init_sizes (klass);
3463 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3464 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3465 * embed themselves.
3467 return klass->has_references;
3470 static gboolean
3471 type_has_references (MonoClass *klass, MonoType *ftype)
3473 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)))))
3474 return TRUE;
3475 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
3476 MonoGenericParam *gparam = ftype->data.generic_param;
3478 if (gparam->gshared_constraint)
3479 return class_has_references (mono_class_from_mono_type_internal (gparam->gshared_constraint));
3481 return FALSE;
3485 * mono_class_layout_fields:
3486 * @class: a class
3487 * @base_instance_size: base instance size
3488 * @packing_size:
3490 * This contains the common code for computing the layout of classes and sizes.
3491 * This should only be called from mono_class_setup_fields () and
3492 * typebuilder_setup_fields ().
3494 * LOCKING: Acquires the loader lock
3496 void
3497 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int explicit_size, gboolean sre)
3499 int i;
3500 const int top = mono_class_get_field_count (klass);
3501 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
3502 guint32 pass, passes, real_size;
3503 gboolean gc_aware_layout = FALSE;
3504 gboolean has_static_fields = FALSE;
3505 gboolean has_references = FALSE;
3506 gboolean has_static_refs = FALSE;
3507 MonoClassField *field;
3508 gboolean blittable;
3509 int instance_size = base_instance_size;
3510 int element_size = -1;
3511 int class_size, min_align;
3512 int *field_offsets;
3513 gboolean *fields_has_references;
3516 * We want to avoid doing complicated work inside locks, so we compute all the required
3517 * information and write it to @klass inside a lock.
3519 if (klass->fields_inited)
3520 return;
3522 if ((packing_size & 0xffffff00) != 0) {
3523 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
3524 return;
3527 if (klass->parent) {
3528 min_align = klass->parent->min_align;
3529 /* we use | since it may have been set already */
3530 has_references = klass->has_references | klass->parent->has_references;
3531 } else {
3532 min_align = 1;
3534 /* We can't really enable 16 bytes alignment until the GC supports it.
3535 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3536 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3537 Bug #506144 is an example of this issue.
3539 if (klass->simd_type)
3540 min_align = 16;
3544 * When we do generic sharing we need to have layout
3545 * information for open generic classes (either with a generic
3546 * context containing type variables or with a generic
3547 * container), so we don't return in that case anymore.
3550 if (klass->enumtype) {
3551 for (i = 0; i < top; i++) {
3552 field = &klass->fields [i];
3553 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3554 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (field->type);
3555 break;
3559 if (!mono_class_enum_basetype_internal (klass)) {
3560 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
3561 return;
3566 * Enable GC aware auto layout: in this mode, reference
3567 * fields are grouped together inside objects, increasing collector
3568 * performance.
3569 * Requires that all classes whose layout is known to native code be annotated
3570 * with [StructLayout (LayoutKind.Sequential)]
3571 * Value types have gc_aware_layout disabled by default, as per
3572 * what the default is for other runtimes.
3574 /* corlib is missing [StructLayout] directives in many places */
3575 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
3576 if (!klass->valuetype)
3577 gc_aware_layout = TRUE;
3580 /* Compute klass->blittable */
3581 blittable = TRUE;
3582 if (klass->parent)
3583 blittable = klass->parent->blittable;
3584 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
3585 blittable = FALSE;
3586 for (i = 0; i < top; i++) {
3587 field = &klass->fields [i];
3589 if (mono_field_is_deleted (field))
3590 continue;
3591 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3592 continue;
3593 if (blittable) {
3594 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
3595 blittable = FALSE;
3596 } else {
3597 MonoClass *field_class = mono_class_from_mono_type_internal (field->type);
3598 if (field_class) {
3599 mono_class_setup_fields (field_class);
3600 if (mono_class_has_failure (field_class)) {
3601 ERROR_DECL (field_error);
3602 mono_error_set_for_class_failure (field_error, field_class);
3603 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (field_error));
3604 mono_error_cleanup (field_error);
3605 break;
3608 if (!field_class || !field_class->blittable)
3609 blittable = FALSE;
3612 if (klass->enumtype)
3613 blittable = klass->element_class->blittable;
3615 if (mono_class_has_failure (klass))
3616 return;
3617 if (klass == mono_defaults.string_class)
3618 blittable = FALSE;
3620 /* Compute klass->has_references */
3622 * Process non-static fields first, since static fields might recursively
3623 * refer to the class itself.
3625 for (i = 0; i < top; i++) {
3626 MonoType *ftype;
3628 field = &klass->fields [i];
3630 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3631 ftype = mono_type_get_underlying_type (field->type);
3632 ftype = mono_type_get_basic_type_from_generic (ftype);
3633 if (type_has_references (klass, ftype))
3634 has_references = TRUE;
3639 * Compute field layout and total size (not considering static fields)
3641 field_offsets = g_new0 (int, top);
3642 fields_has_references = g_new0 (gboolean, top);
3643 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
3644 switch (layout) {
3645 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
3646 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
3647 if (gc_aware_layout)
3648 passes = 2;
3649 else
3650 passes = 1;
3652 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
3653 passes = 1;
3655 if (klass->parent) {
3656 mono_class_setup_fields (klass->parent);
3657 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
3658 return;
3659 real_size = klass->parent->instance_size;
3660 } else {
3661 real_size = MONO_ABI_SIZEOF (MonoObject);
3664 for (pass = 0; pass < passes; ++pass) {
3665 for (i = 0; i < top; i++){
3666 gint32 align;
3667 guint32 size;
3668 MonoType *ftype;
3670 field = &klass->fields [i];
3672 if (mono_field_is_deleted (field))
3673 continue;
3674 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3675 continue;
3677 ftype = mono_type_get_underlying_type (field->type);
3678 ftype = mono_type_get_basic_type_from_generic (ftype);
3679 if (gc_aware_layout) {
3680 fields_has_references [i] = type_has_references (klass, ftype);
3681 if (fields_has_references [i]) {
3682 if (pass == 1)
3683 continue;
3684 } else {
3685 if (pass == 0)
3686 continue;
3690 if ((top == 1) && (instance_size == MONO_ABI_SIZEOF (MonoObject)) &&
3691 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
3692 /* This field is a hack inserted by MCS to empty structures */
3693 continue;
3696 size = mono_type_size (field->type, &align);
3698 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3699 align = packing_size ? MIN (packing_size, align): align;
3700 /* if the field has managed references, we need to force-align it
3701 * see bug #77788
3703 if (type_has_references (klass, ftype))
3704 align = MAX (align, TARGET_SIZEOF_VOID_P);
3706 min_align = MAX (align, min_align);
3707 field_offsets [i] = real_size;
3708 if (align) {
3709 field_offsets [i] += align - 1;
3710 field_offsets [i] &= ~(align - 1);
3712 /*TypeBuilders produce all sort of weird things*/
3713 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
3714 real_size = field_offsets [i] + size;
3717 instance_size = MAX (real_size, instance_size);
3719 if (instance_size & (min_align - 1)) {
3720 instance_size += min_align - 1;
3721 instance_size &= ~(min_align - 1);
3724 break;
3725 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
3726 guint8 *ref_bitmap;
3728 real_size = 0;
3729 for (i = 0; i < top; i++) {
3730 gint32 align;
3731 guint32 size;
3732 MonoType *ftype;
3734 field = &klass->fields [i];
3737 * There must be info about all the fields in a type if it
3738 * uses explicit layout.
3740 if (mono_field_is_deleted (field))
3741 continue;
3742 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3743 continue;
3745 size = mono_type_size (field->type, &align);
3746 align = packing_size ? MIN (packing_size, align): align;
3747 min_align = MAX (align, min_align);
3749 if (sre) {
3750 /* Already set by typebuilder_setup_fields () */
3751 field_offsets [i] = field->offset + MONO_ABI_SIZEOF (MonoObject);
3752 } else {
3753 int idx = first_field_idx + i;
3754 guint32 offset;
3755 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
3756 field_offsets [i] = offset + MONO_ABI_SIZEOF (MonoObject);
3758 ftype = mono_type_get_underlying_type (field->type);
3759 ftype = mono_type_get_basic_type_from_generic (ftype);
3760 if (type_has_references (klass, ftype)) {
3761 if (field_offsets [i] % TARGET_SIZEOF_VOID_P) {
3762 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
3767 * Calc max size.
3769 real_size = MAX (real_size, size + field_offsets [i]);
3772 if (klass->has_references) {
3773 ref_bitmap = g_new0 (guint8, real_size / TARGET_SIZEOF_VOID_P);
3775 /* Check for overlapping reference and non-reference fields */
3776 for (i = 0; i < top; i++) {
3777 MonoType *ftype;
3779 field = &klass->fields [i];
3781 if (mono_field_is_deleted (field))
3782 continue;
3783 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3784 continue;
3785 ftype = mono_type_get_underlying_type (field->type);
3786 if (MONO_TYPE_IS_REFERENCE (ftype))
3787 ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P] = 1;
3789 for (i = 0; i < top; i++) {
3790 field = &klass->fields [i];
3792 if (mono_field_is_deleted (field))
3793 continue;
3794 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3795 continue;
3797 // FIXME: Too much code does this
3798 #if 0
3799 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P]) {
3800 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]);
3802 #endif
3804 g_free (ref_bitmap);
3807 instance_size = MAX (real_size, instance_size);
3808 if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) {
3809 if (instance_size & (min_align - 1)) {
3810 instance_size += min_align - 1;
3811 instance_size &= ~(min_align - 1);
3814 break;
3818 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
3820 * This leads to all kinds of problems with nested structs, so only
3821 * enable it when a MONO_DEBUG property is set.
3823 * For small structs, set min_align to at least the struct size to improve
3824 * performance, and since the JIT memset/memcpy code assumes this and generates
3825 * unaligned accesses otherwise. See #78990 for a testcase.
3827 if (mono_align_small_structs && top) {
3828 if (instance_size <= MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer))
3829 min_align = MAX (min_align, instance_size - MONO_ABI_SIZEOF (MonoObject));
3833 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3834 if (klass_byval_arg->type == MONO_TYPE_VAR || klass_byval_arg->type == MONO_TYPE_MVAR)
3835 instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_stack_size_internal (klass_byval_arg, NULL, TRUE);
3836 else if (klass_byval_arg->type == MONO_TYPE_PTR)
3837 instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
3839 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3840 element_size = mono_class_array_element_size (klass->element_class);
3842 /* Publish the data */
3843 mono_loader_lock ();
3844 if (klass->instance_size && !klass->image->dynamic) {
3845 /* Might be already set using cached info */
3846 if (klass->instance_size != instance_size) {
3847 /* Emit info to help debugging */
3848 g_print ("%s\n", mono_class_full_name (klass));
3849 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
3850 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
3851 g_print ("%d %d\n", klass->min_align, min_align);
3852 for (i = 0; i < top; ++i) {
3853 field = &klass->fields [i];
3854 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3855 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
3858 g_assert (klass->instance_size == instance_size);
3859 } else {
3860 klass->instance_size = instance_size;
3862 klass->blittable = blittable;
3863 klass->has_references = has_references;
3864 klass->packing_size = packing_size;
3865 klass->min_align = min_align;
3866 for (i = 0; i < top; ++i) {
3867 field = &klass->fields [i];
3868 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3869 klass->fields [i].offset = field_offsets [i];
3872 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3873 klass->sizes.element_size = element_size;
3875 mono_memory_barrier ();
3876 klass->size_inited = 1;
3877 mono_loader_unlock ();
3880 * Compute static field layout and size
3881 * Static fields can reference the class itself, so this has to be
3882 * done after instance_size etc. are initialized.
3884 class_size = 0;
3885 for (i = 0; i < top; i++) {
3886 gint32 align;
3887 guint32 size;
3889 field = &klass->fields [i];
3891 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3892 continue;
3893 if (mono_field_is_deleted (field))
3894 continue;
3896 if (mono_type_has_exceptions (field->type)) {
3897 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
3898 break;
3901 has_static_fields = TRUE;
3903 size = mono_type_size (field->type, &align);
3904 field_offsets [i] = class_size;
3905 /*align is always non-zero here*/
3906 field_offsets [i] += align - 1;
3907 field_offsets [i] &= ~(align - 1);
3908 class_size = field_offsets [i] + size;
3911 if (has_static_fields && class_size == 0)
3912 /* Simplify code which depends on class_size != 0 if the class has static fields */
3913 class_size = 8;
3915 /* Compute klass->has_static_refs */
3916 has_static_refs = FALSE;
3917 for (i = 0; i < top; i++) {
3918 MonoType *ftype;
3920 field = &klass->fields [i];
3922 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3923 ftype = mono_type_get_underlying_type (field->type);
3924 ftype = mono_type_get_basic_type_from_generic (ftype);
3925 if (type_has_references (klass, ftype))
3926 has_static_refs = TRUE;
3930 /*valuetypes can't be neither bigger than 1Mb or empty. */
3931 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + MONO_ABI_SIZEOF (MonoObject)))) {
3932 /* Special case compiler generated types */
3933 /* Hard to check for [CompilerGenerated] here */
3934 if (!strstr (klass->name, "StaticArrayInitTypeSize") && !strstr (klass->name, "$ArrayType"))
3935 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
3938 // Weak field support
3940 // FIXME:
3941 // - generic instances
3942 // - Disallow on structs/static fields/nonref fields
3943 gboolean has_weak_fields = FALSE;
3945 if (mono_class_has_static_metadata (klass)) {
3946 for (MonoClass *p = klass; p != NULL; p = p->parent) {
3947 gpointer iter = NULL;
3948 guint32 first_field_idx = mono_class_get_first_field_idx (p);
3950 while ((field = mono_class_get_fields_internal (p, &iter))) {
3951 guint32 field_idx = first_field_idx + (field - p->fields);
3952 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
3953 has_weak_fields = TRUE;
3954 mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
3961 * Check that any fields of IsByRefLike type are instance
3962 * fields and only inside other IsByRefLike structs.
3964 * (Has to be done late because we call
3965 * mono_class_from_mono_type_internal which may recursively
3966 * refer to the current class)
3968 gboolean allow_isbyreflike_fields = m_class_is_byreflike (klass);
3969 for (i = 0; i < top; i++) {
3970 field = &klass->fields [i];
3972 if (mono_field_is_deleted (field))
3973 continue;
3974 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
3975 continue;
3976 MonoClass *field_class = NULL;
3977 /* have to be careful not to recursively invoke mono_class_init on a static field.
3978 * for example - if the field is an array of a subclass of klass, we can loop.
3980 switch (field->type->type) {
3981 case MONO_TYPE_TYPEDBYREF:
3982 case MONO_TYPE_VALUETYPE:
3983 case MONO_TYPE_GENERICINST:
3984 field_class = mono_class_from_mono_type_internal (field->type);
3985 break;
3986 default:
3987 break;
3989 if (!field_class || !m_class_is_byreflike (field_class))
3990 continue;
3991 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3992 mono_class_set_type_load_failure (klass, "Static ByRefLike field '%s' is not allowed", field->name);
3993 return;
3994 } else {
3995 /* instance field */
3996 if (allow_isbyreflike_fields)
3997 continue;
3998 mono_class_set_type_load_failure (klass, "Instance ByRefLike field '%s' not in a ref struct", field->name);
3999 return;
4003 /* Publish the data */
4004 mono_loader_lock ();
4005 if (!klass->rank)
4006 klass->sizes.class_size = class_size;
4007 klass->has_static_refs = has_static_refs;
4008 klass->has_weak_fields = has_weak_fields;
4009 for (i = 0; i < top; ++i) {
4010 field = &klass->fields [i];
4012 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
4013 field->offset = field_offsets [i];
4015 mono_memory_barrier ();
4016 klass->fields_inited = 1;
4017 mono_loader_unlock ();
4019 g_free (field_offsets);
4020 g_free (fields_has_references);
4023 static MonoMethod *default_ghc = NULL;
4024 static MonoMethod *default_finalize = NULL;
4025 static int finalize_slot = -1;
4026 static int ghc_slot = -1;
4028 static void
4029 initialize_object_slots (MonoClass *klass)
4031 int i;
4032 if (default_ghc)
4033 return;
4034 if (klass == mono_defaults.object_class) {
4035 mono_class_setup_vtable (klass);
4036 for (i = 0; i < klass->vtable_size; ++i) {
4037 MonoMethod *cm = klass->vtable [i];
4039 if (!strcmp (cm->name, "GetHashCode"))
4040 ghc_slot = i;
4041 else if (!strcmp (cm->name, "Finalize"))
4042 finalize_slot = i;
4045 g_assert (ghc_slot >= 0);
4046 default_ghc = klass->vtable [ghc_slot];
4048 g_assert (finalize_slot >= 0);
4049 default_finalize = klass->vtable [finalize_slot];
4054 mono_class_get_object_finalize_slot ()
4056 return finalize_slot;
4059 MonoMethod *
4060 mono_class_get_default_finalize_method ()
4062 return default_finalize;
4065 typedef struct {
4066 MonoMethod *array_method;
4067 char *name;
4068 } GenericArrayMethodInfo;
4070 static int generic_array_method_num = 0;
4071 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4073 static void
4074 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
4076 MonoGenericContext tmp_context;
4077 int i;
4079 tmp_context.class_inst = NULL;
4080 tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
4081 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4083 for (i = 0; i < generic_array_method_num; i++) {
4084 ERROR_DECL (error);
4085 MonoMethod *m = generic_array_method_info [i].array_method;
4086 MonoMethod *inflated, *helper;
4088 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, error);
4089 mono_error_assert_ok (error);
4090 helper = (MonoMethod*)g_hash_table_lookup (cache, inflated);
4091 if (!helper) {
4092 helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
4093 g_hash_table_insert (cache, inflated, helper);
4095 methods [pos ++] = helper;
4099 static int
4100 generic_array_methods (MonoClass *klass)
4102 int i, count_generic = 0, mcount;
4103 GList *list = NULL, *tmp;
4104 if (generic_array_method_num)
4105 return generic_array_method_num;
4106 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4107 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4108 mcount = mono_class_get_method_count (klass->parent);
4109 for (i = 0; i < mcount; i++) {
4110 MonoMethod *m = klass->parent->methods [i];
4111 if (!strncmp (m->name, "InternalArray__", 15)) {
4112 count_generic++;
4113 list = g_list_prepend (list, m);
4116 list = g_list_reverse (list);
4117 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4118 i = 0;
4119 for (tmp = list; tmp; tmp = tmp->next) {
4120 const char *mname, *iname;
4121 gchar *name;
4122 MonoMethod *m = (MonoMethod *)tmp->data;
4123 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4124 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4126 generic_array_method_info [i].array_method = m;
4127 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4128 iname = "System.Collections.Generic.ICollection`1.";
4129 mname = m->name + 27;
4130 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4131 iname = "System.Collections.Generic.IEnumerable`1.";
4132 mname = m->name + 27;
4133 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4134 iname = "System.Collections.Generic.IReadOnlyList`1.";
4135 mname = m->name + strlen (ireadonlylist_prefix);
4136 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4137 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4138 mname = m->name + strlen (ireadonlycollection_prefix);
4139 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4140 iname = "System.Collections.Generic.IList`1.";
4141 mname = m->name + 15;
4142 } else {
4143 g_assert_not_reached ();
4146 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4147 strcpy (name, iname);
4148 strcpy (name + strlen (iname), mname);
4149 generic_array_method_info [i].name = name;
4150 i++;
4152 /*g_print ("array generic methods: %d\n", count_generic);*/
4154 generic_array_method_num = count_generic;
4155 g_list_free (list);
4156 return generic_array_method_num;
4160 * Global pool of interface IDs, represented as a bitset.
4161 * LOCKING: Protected by the classes lock.
4163 static MonoBitSet *global_interface_bitset = NULL;
4166 * mono_unload_interface_ids:
4167 * @bitset: bit set of interface IDs
4169 * When an image is unloaded, the interface IDs associated with
4170 * the image are put back in the global pool of IDs so the numbers
4171 * can be reused.
4173 void
4174 mono_unload_interface_ids (MonoBitSet *bitset)
4176 classes_lock ();
4177 mono_bitset_sub (global_interface_bitset, bitset);
4178 classes_unlock ();
4181 void
4182 mono_unload_interface_id (MonoClass *klass)
4184 if (global_interface_bitset && klass->interface_id) {
4185 classes_lock ();
4186 mono_bitset_clear (global_interface_bitset, klass->interface_id);
4187 classes_unlock ();
4192 * mono_get_unique_iid:
4193 * \param klass interface
4195 * Assign a unique integer ID to the interface represented by \p klass.
4196 * The ID will positive and as small as possible.
4197 * LOCKING: Acquires the classes lock.
4198 * \returns The new ID.
4200 static guint32
4201 mono_get_unique_iid (MonoClass *klass)
4203 int iid;
4205 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
4207 classes_lock ();
4209 if (!global_interface_bitset) {
4210 global_interface_bitset = mono_bitset_new (128, 0);
4211 mono_bitset_set (global_interface_bitset, 0); //don't let 0 be a valid iid
4214 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
4215 if (iid < 0) {
4216 int old_size = mono_bitset_size (global_interface_bitset);
4217 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
4218 mono_bitset_free (global_interface_bitset);
4219 global_interface_bitset = new_set;
4220 iid = old_size;
4222 mono_bitset_set (global_interface_bitset, iid);
4223 /* set the bit also in the per-image set */
4224 if (!mono_class_is_ginst (klass)) {
4225 if (klass->image->interface_bitset) {
4226 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
4227 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
4228 mono_bitset_free (klass->image->interface_bitset);
4229 klass->image->interface_bitset = new_set;
4231 } else {
4232 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
4234 mono_bitset_set (klass->image->interface_bitset, iid);
4237 classes_unlock ();
4239 #ifndef MONO_SMALL_CONFIG
4240 if (mono_print_vtable) {
4241 int generic_id;
4242 char *type_name = mono_type_full_name (m_class_get_byval_arg (klass));
4243 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
4244 if (gklass && !gklass->context.class_inst->is_open) {
4245 generic_id = gklass->context.class_inst->id;
4246 g_assert (generic_id != 0);
4247 } else {
4248 generic_id = 0;
4250 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->assembly_name, type_name, generic_id);
4251 g_free (type_name);
4253 #endif
4255 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4256 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4257 g_assert (iid < INT_MAX);
4258 return iid;
4262 * mono_class_init_internal:
4263 * \param klass the class to initialize
4265 * Compute the \c instance_size, \c class_size and other infos that cannot be
4266 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4267 * Initializes the following fields in \p klass:
4268 * - all the fields initialized by \c mono_class_init_sizes
4269 * - has_cctor
4270 * - ghcimpl
4271 * - inited
4273 * LOCKING: Acquires the loader lock.
4275 * \returns TRUE on success or FALSE if there was a problem in loading
4276 * the type (incorrect assemblies, missing assemblies, methods, etc).
4278 gboolean
4279 mono_class_init_internal (MonoClass *klass)
4281 int i, vtable_size = 0, array_method_count = 0;
4282 MonoCachedClassInfo cached_info;
4283 gboolean has_cached_info;
4284 gboolean locked = FALSE;
4285 gboolean ghcimpl = FALSE;
4286 gboolean has_cctor = FALSE;
4287 int first_iface_slot = 0;
4289 g_assert (klass);
4291 /* Double-checking locking pattern */
4292 if (klass->inited || mono_class_has_failure (klass))
4293 return !mono_class_has_failure (klass);
4295 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4298 * This function can recursively call itself.
4300 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
4301 if (g_slist_find (init_list, klass)) {
4302 mono_class_set_type_load_failure (klass, "Recursive type definition detected %s.%s", klass->name_space, klass->name);
4303 goto leave_no_init_pending;
4305 init_list = g_slist_prepend (init_list, klass);
4306 mono_native_tls_set_value (init_pending_tls_id, init_list);
4309 * We want to avoid doing complicated work inside locks, so we compute all the required
4310 * information and write it to @klass inside a lock.
4313 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
4314 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
4315 goto leave;
4318 MonoType *klass_byval_arg;
4319 klass_byval_arg = m_class_get_byval_arg (klass);
4320 if (klass_byval_arg->type == MONO_TYPE_ARRAY || klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4321 MonoClass *element_class = klass->element_class;
4322 MonoClass *cast_class = klass->cast_class;
4324 if (!element_class->inited)
4325 mono_class_init_internal (element_class);
4326 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
4327 goto leave;
4328 if (!cast_class->inited)
4329 mono_class_init_internal (cast_class);
4330 if (mono_class_set_type_load_failure_causedby_class (klass, cast_class, "Could not load array cast class"))
4331 goto leave;
4334 UnlockedIncrement (&mono_stats.initialized_class_count);
4336 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
4337 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4339 mono_class_init_internal (gklass);
4340 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
4341 goto leave;
4343 mono_loader_lock ();
4344 mono_class_setup_interface_id_internal (klass);
4345 mono_loader_unlock ();
4348 if (klass->parent && !klass->parent->inited)
4349 mono_class_init_internal (klass->parent);
4351 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
4353 /* Compute instance size etc. */
4354 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
4355 if (mono_class_has_failure (klass))
4356 goto leave;
4358 mono_class_setup_supertypes (klass);
4360 if (!default_ghc)
4361 initialize_object_slots (klass);
4364 * Initialize the rest of the data without creating a generic vtable if possible.
4365 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4366 * also avoid computing a generic vtable.
4368 if (has_cached_info) {
4369 /* AOT case */
4370 vtable_size = cached_info.vtable_size;
4371 ghcimpl = cached_info.ghcimpl;
4372 has_cctor = cached_info.has_cctor;
4373 } else if (klass->rank == 1 && klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4374 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4375 * The first slot if for array with.
4377 static int szarray_vtable_size[3] = { 0 };
4379 int slot;
4381 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass))))
4382 slot = 0;
4383 else if (klass->element_class->enumtype)
4384 slot = 1;
4385 else
4386 slot = 2;
4388 /* SZARRAY case */
4389 if (!szarray_vtable_size [slot]) {
4390 mono_class_setup_vtable (klass);
4391 szarray_vtable_size [slot] = klass->vtable_size;
4392 vtable_size = klass->vtable_size;
4393 } else {
4394 vtable_size = szarray_vtable_size[slot];
4396 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4397 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4399 /* Generic instance case */
4400 ghcimpl = gklass->ghcimpl;
4401 has_cctor = gklass->has_cctor;
4403 mono_class_setup_vtable (gklass);
4404 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
4405 goto leave;
4407 vtable_size = gklass->vtable_size;
4408 } else {
4409 /* General case */
4411 /* ghcimpl is not currently used
4412 klass->ghcimpl = 1;
4413 if (klass->parent) {
4414 MonoMethod *cmethod = klass->vtable [ghc_slot];
4415 if (cmethod->is_inflated)
4416 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
4417 if (cmethod == default_ghc) {
4418 klass->ghcimpl = 0;
4423 /* C# doesn't allow interfaces to have cctors */
4424 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->image != mono_defaults.corlib) {
4425 MonoMethod *cmethod = NULL;
4427 if (mono_class_is_ginst (klass)) {
4428 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4430 /* Generic instance case */
4431 ghcimpl = gklass->ghcimpl;
4432 has_cctor = gklass->has_cctor;
4433 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
4434 cmethod = mono_find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
4435 /* The find_method function ignores the 'flags' argument */
4436 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
4437 has_cctor = 1;
4438 } else {
4439 mono_class_setup_methods (klass);
4440 if (mono_class_has_failure (klass))
4441 goto leave;
4443 int mcount = mono_class_get_method_count (klass);
4444 for (i = 0; i < mcount; ++i) {
4445 MonoMethod *method = klass->methods [i];
4446 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
4447 (strcmp (".cctor", method->name) == 0)) {
4448 has_cctor = 1;
4449 break;
4456 if (klass->rank) {
4457 array_method_count = 3 + (klass->rank > 1? 2: 1);
4459 if (klass->interface_count) {
4460 int count_generic = generic_array_methods (klass);
4461 array_method_count += klass->interface_count * count_generic;
4465 if (klass->parent) {
4466 if (!klass->parent->vtable_size)
4467 mono_class_setup_vtable (klass->parent);
4468 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
4469 goto leave;
4470 g_assert (klass->parent->vtable_size);
4471 first_iface_slot = klass->parent->vtable_size;
4472 if (mono_class_need_stelemref_method (klass))
4473 ++first_iface_slot;
4477 * Do the actual changes to @klass inside the loader lock
4479 mono_loader_lock ();
4480 locked = TRUE;
4482 if (klass->inited || mono_class_has_failure (klass)) {
4483 mono_loader_unlock ();
4484 /* Somebody might have gotten in before us */
4485 return !mono_class_has_failure (klass);
4488 UnlockedIncrement (&mono_stats.initialized_class_count);
4490 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
4491 UnlockedIncrement (&mono_stats.generic_class_count);
4493 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
4494 klass->nested_classes_inited = TRUE;
4495 klass->ghcimpl = ghcimpl;
4496 klass->has_cctor = has_cctor;
4497 if (vtable_size)
4498 klass->vtable_size = vtable_size;
4499 if (has_cached_info) {
4500 klass->has_finalize = cached_info.has_finalize;
4501 klass->has_finalize_inited = TRUE;
4503 if (klass->rank)
4504 mono_class_set_method_count (klass, array_method_count);
4506 mono_loader_unlock ();
4507 locked = FALSE;
4509 setup_interface_offsets (klass, first_iface_slot, TRUE);
4511 if (mono_security_core_clr_enabled ())
4512 mono_security_core_clr_check_inheritance (klass);
4514 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
4515 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
4517 goto leave;
4519 leave:
4520 init_list = (GSList*)mono_native_tls_get_value (init_pending_tls_id);
4521 init_list = g_slist_remove (init_list, klass);
4522 mono_native_tls_set_value (init_pending_tls_id, init_list);
4524 leave_no_init_pending:
4525 if (locked)
4526 mono_loader_unlock ();
4528 /* Leave this for last */
4529 mono_loader_lock ();
4530 klass->inited = 1;
4531 mono_loader_unlock ();
4533 return !mono_class_has_failure (klass);
4536 gboolean
4537 mono_class_init_checked (MonoClass *klass, MonoError *error)
4539 error_init (error);
4540 gboolean const success = mono_class_init_internal (klass);
4541 if (!success)
4542 mono_error_set_for_class_failure (error, klass);
4543 return success;
4546 #ifndef DISABLE_COM
4548 * COM initialization is delayed until needed.
4549 * However when a [ComImport] attribute is present on a type it will trigger
4550 * the initialization. This is not a problem unless the BCL being executed
4551 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4553 static void
4554 init_com_from_comimport (MonoClass *klass)
4556 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4557 if (mono_security_core_clr_enabled ()) {
4558 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4559 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
4560 /* but it can not be made available for application (i.e. user code) since all COM calls
4561 * are considered native calls. In this case we fail with a TypeLoadException (just like
4562 * Silverlight 2 does */
4563 mono_class_set_type_load_failure (klass, "");
4564 return;
4568 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4570 #endif /*DISABLE_COM*/
4573 * LOCKING: this assumes the loader lock is held
4575 void
4576 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
4578 gboolean system_namespace;
4579 gboolean is_corlib = mono_is_corlib_image (klass->image);
4581 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
4583 /* if root of the hierarchy */
4584 if (system_namespace && !strcmp (klass->name, "Object")) {
4585 klass->parent = NULL;
4586 klass->instance_size = MONO_ABI_SIZEOF (MonoObject);
4587 return;
4589 if (!strcmp (klass->name, "<Module>")) {
4590 klass->parent = NULL;
4591 klass->instance_size = 0;
4592 return;
4595 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4596 /* Imported COM Objects always derive from __ComObject. */
4597 #ifndef DISABLE_COM
4598 if (MONO_CLASS_IS_IMPORT (klass)) {
4599 init_com_from_comimport (klass);
4600 if (parent == mono_defaults.object_class)
4601 parent = mono_class_get_com_object_class ();
4603 #endif
4604 if (!parent) {
4605 /* set the parent to something useful and safe, but mark the type as broken */
4606 parent = mono_defaults.object_class;
4607 mono_class_set_type_load_failure (klass, "");
4608 g_assert (parent);
4611 klass->parent = parent;
4613 if (mono_class_is_ginst (parent) && !parent->name) {
4615 * If the parent is a generic instance, we may get
4616 * called before it is fully initialized, especially
4617 * before it has its name.
4619 return;
4622 #ifndef DISABLE_REMOTING
4623 klass->marshalbyref = parent->marshalbyref;
4624 klass->contextbound = parent->contextbound;
4625 #endif
4627 klass->delegate = parent->delegate;
4629 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
4630 mono_class_set_is_com_object (klass);
4632 if (system_namespace) {
4633 #ifndef DISABLE_REMOTING
4634 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
4635 klass->marshalbyref = 1;
4637 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
4638 klass->contextbound = 1;
4639 #endif
4640 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
4641 klass->delegate = 1;
4644 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
4645 (strcmp (klass->parent->name_space, "System") == 0)))
4646 klass->valuetype = 1;
4647 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
4648 klass->valuetype = klass->enumtype = 1;
4650 /*klass->enumtype = klass->parent->enumtype; */
4651 } else {
4652 /* initialize com types if COM interfaces are present */
4653 #ifndef DISABLE_COM
4654 if (MONO_CLASS_IS_IMPORT (klass))
4655 init_com_from_comimport (klass);
4656 #endif
4657 klass->parent = NULL;
4662 /* Locking: must be called with the loader lock held. */
4663 static void
4664 mono_class_setup_interface_id_internal (MonoClass *klass)
4666 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->interface_id)
4667 return;
4668 klass->interface_id = mono_get_unique_iid (klass);
4670 if (mono_is_corlib_image (klass->image) && !strcmp (m_class_get_name_space (klass), "System.Collections.Generic")) {
4671 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4672 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4673 * MS returns diferrent types based on which instance is called. For example:
4674 * object obj = new byte[10][];
4675 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4676 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4677 * a != b ==> true
4679 const char *name = m_class_get_name (klass);
4680 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
4681 klass->is_array_special_interface = 1;
4687 * LOCKING: this assumes the loader lock is held
4689 void
4690 mono_class_setup_mono_type (MonoClass *klass)
4692 const char *name = klass->name;
4693 const char *nspace = klass->name_space;
4694 gboolean is_corlib = mono_is_corlib_image (klass->image);
4696 klass->this_arg.byref = 1;
4697 klass->this_arg.data.klass = klass;
4698 klass->this_arg.type = MONO_TYPE_CLASS;
4699 klass->_byval_arg.data.klass = klass;
4700 klass->_byval_arg.type = MONO_TYPE_CLASS;
4702 if (is_corlib && !strcmp (nspace, "System")) {
4703 if (!strcmp (name, "ValueType")) {
4705 * do not set the valuetype bit for System.ValueType.
4706 * klass->valuetype = 1;
4708 klass->blittable = TRUE;
4709 } else if (!strcmp (name, "Enum")) {
4711 * do not set the valuetype bit for System.Enum.
4712 * klass->valuetype = 1;
4714 klass->valuetype = 0;
4715 klass->enumtype = 0;
4716 } else if (!strcmp (name, "Object")) {
4717 klass->_byval_arg.type = MONO_TYPE_OBJECT;
4718 klass->this_arg.type = MONO_TYPE_OBJECT;
4719 } else if (!strcmp (name, "String")) {
4720 klass->_byval_arg.type = MONO_TYPE_STRING;
4721 klass->this_arg.type = MONO_TYPE_STRING;
4722 } else if (!strcmp (name, "TypedReference")) {
4723 klass->_byval_arg.type = MONO_TYPE_TYPEDBYREF;
4724 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
4728 if (klass->valuetype) {
4729 int t = MONO_TYPE_VALUETYPE;
4731 if (is_corlib && !strcmp (nspace, "System")) {
4732 switch (*name) {
4733 case 'B':
4734 if (!strcmp (name, "Boolean")) {
4735 t = MONO_TYPE_BOOLEAN;
4736 } else if (!strcmp(name, "Byte")) {
4737 t = MONO_TYPE_U1;
4738 klass->blittable = TRUE;
4740 break;
4741 case 'C':
4742 if (!strcmp (name, "Char")) {
4743 t = MONO_TYPE_CHAR;
4745 break;
4746 case 'D':
4747 if (!strcmp (name, "Double")) {
4748 t = MONO_TYPE_R8;
4749 klass->blittable = TRUE;
4751 break;
4752 case 'I':
4753 if (!strcmp (name, "Int32")) {
4754 t = MONO_TYPE_I4;
4755 klass->blittable = TRUE;
4756 } else if (!strcmp(name, "Int16")) {
4757 t = MONO_TYPE_I2;
4758 klass->blittable = TRUE;
4759 } else if (!strcmp(name, "Int64")) {
4760 t = MONO_TYPE_I8;
4761 klass->blittable = TRUE;
4762 } else if (!strcmp(name, "IntPtr")) {
4763 t = MONO_TYPE_I;
4764 klass->blittable = TRUE;
4766 break;
4767 case 'S':
4768 if (!strcmp (name, "Single")) {
4769 t = MONO_TYPE_R4;
4770 klass->blittable = TRUE;
4771 } else if (!strcmp(name, "SByte")) {
4772 t = MONO_TYPE_I1;
4773 klass->blittable = TRUE;
4775 break;
4776 case 'U':
4777 if (!strcmp (name, "UInt32")) {
4778 t = MONO_TYPE_U4;
4779 klass->blittable = TRUE;
4780 } else if (!strcmp(name, "UInt16")) {
4781 t = MONO_TYPE_U2;
4782 klass->blittable = TRUE;
4783 } else if (!strcmp(name, "UInt64")) {
4784 t = MONO_TYPE_U8;
4785 klass->blittable = TRUE;
4786 } else if (!strcmp(name, "UIntPtr")) {
4787 t = MONO_TYPE_U;
4788 klass->blittable = TRUE;
4790 break;
4791 case 'T':
4792 if (!strcmp (name, "TypedReference")) {
4793 t = MONO_TYPE_TYPEDBYREF;
4794 klass->blittable = TRUE;
4796 break;
4797 case 'V':
4798 if (!strcmp (name, "Void")) {
4799 t = MONO_TYPE_VOID;
4801 break;
4802 default:
4803 break;
4806 klass->_byval_arg.type = (MonoTypeEnum)t;
4807 klass->this_arg.type = (MonoTypeEnum)t;
4810 mono_class_setup_interface_id_internal (klass);
4813 static MonoMethod*
4814 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
4816 MonoMethod *method;
4818 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
4819 method->klass = klass;
4820 method->flags = METHOD_ATTRIBUTE_PUBLIC;
4821 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
4822 method->signature = sig;
4823 method->name = name;
4824 method->slot = -1;
4825 /* .ctor */
4826 if (name [0] == '.') {
4827 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
4828 } else {
4829 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
4831 return method;
4835 * mono_class_setup_methods:
4836 * @class: a class
4838 * Initializes the 'methods' array in CLASS.
4839 * Calling this method should be avoided if possible since it allocates a lot
4840 * of long-living MonoMethod structures.
4841 * Methods belonging to an interface are assigned a sequential slot starting
4842 * from 0.
4844 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4846 void
4847 mono_class_setup_methods (MonoClass *klass)
4849 int i, count;
4850 MonoMethod **methods;
4852 if (klass->methods)
4853 return;
4855 if (mono_class_is_ginst (klass)) {
4856 ERROR_DECL (error);
4857 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4859 mono_class_init_internal (gklass);
4860 if (!mono_class_has_failure (gklass))
4861 mono_class_setup_methods (gklass);
4862 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
4863 return;
4865 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4866 count = mono_class_get_method_count (gklass);
4867 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
4869 for (i = 0; i < count; i++) {
4870 methods [i] = mono_class_inflate_generic_method_full_checked (
4871 gklass->methods [i], klass, mono_class_get_context (klass), error);
4872 if (!mono_error_ok (error)) {
4873 char *method = mono_method_full_name (gklass->methods [i], TRUE);
4874 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (error));
4876 g_free (method);
4877 mono_error_cleanup (error);
4878 return;
4881 } else if (klass->rank) {
4882 ERROR_DECL (error);
4883 MonoMethod *amethod;
4884 MonoMethodSignature *sig;
4885 int count_generic = 0, first_generic = 0;
4886 int method_num = 0;
4887 gboolean jagged_ctor = FALSE;
4889 count = 3 + (klass->rank > 1? 2: 1);
4891 mono_class_setup_interfaces (klass, error);
4892 g_assert (mono_error_ok (error)); /*FIXME can this fail for array types?*/
4894 if (klass->rank == 1 && klass->element_class->rank) {
4895 jagged_ctor = TRUE;
4896 count ++;
4899 if (klass->interface_count) {
4900 count_generic = generic_array_methods (klass);
4901 first_generic = count;
4902 count += klass->interface_count * count_generic;
4905 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
4907 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4908 sig->ret = mono_get_void_type ();
4909 sig->pinvoke = TRUE;
4910 sig->hasthis = TRUE;
4911 for (i = 0; i < klass->rank; ++i)
4912 sig->params [i] = mono_get_int32_type ();
4914 amethod = create_array_method (klass, ".ctor", sig);
4915 methods [method_num++] = amethod;
4916 if (klass->rank > 1) {
4917 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
4918 sig->ret = mono_get_void_type ();
4919 sig->pinvoke = TRUE;
4920 sig->hasthis = TRUE;
4921 for (i = 0; i < klass->rank * 2; ++i)
4922 sig->params [i] = mono_get_int32_type ();
4924 amethod = create_array_method (klass, ".ctor", sig);
4925 methods [method_num++] = amethod;
4928 if (jagged_ctor) {
4929 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4930 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4931 sig->ret = mono_get_void_type ();
4932 sig->pinvoke = TRUE;
4933 sig->hasthis = TRUE;
4934 for (i = 0; i < klass->rank + 1; ++i)
4935 sig->params [i] = mono_get_int32_type ();
4936 amethod = create_array_method (klass, ".ctor", sig);
4937 methods [method_num++] = amethod;
4940 /* element Get (idx11, [idx2, ...]) */
4941 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4942 sig->ret = m_class_get_byval_arg (m_class_get_element_class (klass));
4943 sig->pinvoke = TRUE;
4944 sig->hasthis = TRUE;
4945 for (i = 0; i < klass->rank; ++i)
4946 sig->params [i] = mono_get_int32_type ();
4947 amethod = create_array_method (klass, "Get", sig);
4948 methods [method_num++] = amethod;
4949 /* element& Address (idx11, [idx2, ...]) */
4950 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4951 sig->ret = &klass->element_class->this_arg;
4952 sig->pinvoke = TRUE;
4953 sig->hasthis = TRUE;
4954 for (i = 0; i < klass->rank; ++i)
4955 sig->params [i] = mono_get_int32_type ();
4956 amethod = create_array_method (klass, "Address", sig);
4957 methods [method_num++] = amethod;
4958 /* void Set (idx11, [idx2, ...], element) */
4959 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4960 sig->ret = mono_get_void_type ();
4961 sig->pinvoke = TRUE;
4962 sig->hasthis = TRUE;
4963 for (i = 0; i < klass->rank; ++i)
4964 sig->params [i] = mono_get_int32_type ();
4965 sig->params [i] = m_class_get_byval_arg (m_class_get_element_class (klass));
4966 amethod = create_array_method (klass, "Set", sig);
4967 methods [method_num++] = amethod;
4969 GHashTable *cache = g_hash_table_new (NULL, NULL);
4970 for (i = 0; i < klass->interface_count; i++)
4971 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
4972 g_hash_table_destroy (cache);
4973 } else if (mono_class_has_static_metadata (klass)) {
4974 ERROR_DECL (error);
4975 int first_idx = mono_class_get_first_method_idx (klass);
4977 count = mono_class_get_method_count (klass);
4978 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
4979 for (i = 0; i < count; ++i) {
4980 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
4981 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, error);
4982 if (!methods [i]) {
4983 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (error));
4984 mono_error_cleanup (error);
4987 } else {
4988 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
4989 count = 0;
4992 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4993 int slot = 0;
4994 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
4995 for (i = 0; i < count; ++i) {
4996 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
4997 methods [i]->slot = slot++;
5001 mono_image_lock (klass->image);
5003 if (!klass->methods) {
5004 mono_class_set_method_count (klass, count);
5006 /* Needed because of the double-checking locking pattern */
5007 mono_memory_barrier ();
5009 klass->methods = methods;
5012 mono_image_unlock (klass->image);
5016 * mono_class_setup_properties:
5018 * Initialize klass->ext.property and klass->ext.properties.
5020 * This method can fail the class.
5022 void
5023 mono_class_setup_properties (MonoClass *klass)
5025 guint startm, endm, i, j;
5026 guint32 cols [MONO_PROPERTY_SIZE];
5027 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5028 MonoProperty *properties;
5029 guint32 last;
5030 int first, count;
5031 MonoClassPropertyInfo *info;
5033 info = mono_class_get_property_info (klass);
5034 if (info)
5035 return;
5037 if (mono_class_is_ginst (klass)) {
5038 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5040 mono_class_init_internal (gklass);
5041 mono_class_setup_properties (gklass);
5042 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5043 return;
5045 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
5046 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
5048 for (i = 0; i < ginfo->count; i++) {
5049 ERROR_DECL (error);
5050 MonoProperty *prop = &properties [i];
5052 *prop = ginfo->properties [i];
5054 if (prop->get)
5055 prop->get = mono_class_inflate_generic_method_full_checked (
5056 prop->get, klass, mono_class_get_context (klass), error);
5057 if (prop->set)
5058 prop->set = mono_class_inflate_generic_method_full_checked (
5059 prop->set, klass, mono_class_get_context (klass), error);
5061 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5062 prop->parent = klass;
5065 first = ginfo->first;
5066 count = ginfo->count;
5067 } else {
5068 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5069 count = last - first;
5071 if (count) {
5072 mono_class_setup_methods (klass);
5073 if (mono_class_has_failure (klass))
5074 return;
5077 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
5078 for (i = first; i < last; ++i) {
5079 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
5080 properties [i - first].parent = klass;
5081 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
5082 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
5084 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
5085 int first_idx = mono_class_get_first_method_idx (klass);
5086 for (j = startm; j < endm; ++j) {
5087 MonoMethod *method;
5089 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5091 if (klass->image->uncompressed_metadata) {
5092 ERROR_DECL (error);
5093 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5094 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5095 mono_error_cleanup (error); /* FIXME don't swallow this error */
5096 } else {
5097 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5100 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5101 case METHOD_SEMANTIC_SETTER:
5102 properties [i - first].set = method;
5103 break;
5104 case METHOD_SEMANTIC_GETTER:
5105 properties [i - first].get = method;
5106 break;
5107 default:
5108 break;
5114 info = (MonoClassPropertyInfo*)mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
5115 info->first = first;
5116 info->count = count;
5117 info->properties = properties;
5118 mono_memory_barrier ();
5120 /* This might leak 'info' which was allocated from the image mempool */
5121 mono_class_set_property_info (klass, info);
5124 static MonoMethod**
5125 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
5127 MonoMethod **om, **retval;
5128 int count;
5130 for (om = methods, count = 0; *om; ++om, ++count)
5133 retval = g_new0 (MonoMethod*, count + 1);
5134 count = 0;
5135 for (om = methods, count = 0; *om; ++om, ++count) {
5136 ERROR_DECL (error);
5137 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, error);
5138 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5141 return retval;
5144 /*This method can fail the class.*/
5145 void
5146 mono_class_setup_events (MonoClass *klass)
5148 int first, count;
5149 guint startm, endm, i, j;
5150 guint32 cols [MONO_EVENT_SIZE];
5151 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5152 guint32 last;
5153 MonoEvent *events;
5155 MonoClassEventInfo *info = mono_class_get_event_info (klass);
5156 if (info)
5157 return;
5159 if (mono_class_is_ginst (klass)) {
5160 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5161 MonoGenericContext *context = NULL;
5163 mono_class_setup_events (gklass);
5164 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5165 return;
5167 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
5168 first = ginfo->first;
5169 count = ginfo->count;
5171 events = mono_class_new0 (klass, MonoEvent, count);
5173 if (count)
5174 context = mono_class_get_context (klass);
5176 for (i = 0; i < count; i++) {
5177 ERROR_DECL (error);
5178 MonoEvent *event = &events [i];
5179 MonoEvent *gevent = &ginfo->events [i];
5181 error_init (error); //since we do conditional calls, we must ensure the default value is ok
5183 event->parent = klass;
5184 event->name = gevent->name;
5185 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, error) : NULL;
5186 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5187 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, error) : NULL;
5188 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5189 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, error) : NULL;
5190 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5192 #ifndef MONO_SMALL_CONFIG
5193 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
5194 #endif
5195 event->attrs = gevent->attrs;
5197 } else {
5198 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5199 count = last - first;
5201 if (count) {
5202 mono_class_setup_methods (klass);
5203 if (mono_class_has_failure (klass)) {
5204 return;
5208 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
5209 for (i = first; i < last; ++i) {
5210 MonoEvent *event = &events [i - first];
5212 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
5213 event->parent = klass;
5214 event->attrs = cols [MONO_EVENT_FLAGS];
5215 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
5217 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
5218 int first_idx = mono_class_get_first_method_idx (klass);
5219 for (j = startm; j < endm; ++j) {
5220 MonoMethod *method;
5222 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5224 if (klass->image->uncompressed_metadata) {
5225 ERROR_DECL (error);
5226 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5227 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5228 mono_error_cleanup (error); /* FIXME don't swallow this error */
5229 } else {
5230 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5233 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5234 case METHOD_SEMANTIC_ADD_ON:
5235 event->add = method;
5236 break;
5237 case METHOD_SEMANTIC_REMOVE_ON:
5238 event->remove = method;
5239 break;
5240 case METHOD_SEMANTIC_FIRE:
5241 event->raise = method;
5242 break;
5243 case METHOD_SEMANTIC_OTHER: {
5244 #ifndef MONO_SMALL_CONFIG
5245 int n = 0;
5247 if (event->other == NULL) {
5248 event->other = g_new0 (MonoMethod*, 2);
5249 } else {
5250 while (event->other [n])
5251 n++;
5252 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
5254 event->other [n] = method;
5255 /* NULL terminated */
5256 event->other [n + 1] = NULL;
5257 #endif
5258 break;
5260 default:
5261 break;
5267 info = (MonoClassEventInfo*)mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
5268 info->events = events;
5269 info->first = first;
5270 info->count = count;
5272 mono_memory_barrier ();
5274 mono_class_set_event_info (klass, info);
5279 * mono_class_setup_interface_id:
5281 * Initializes MonoClass::interface_id if required.
5283 * LOCKING: Acquires the loader lock.
5285 void
5286 mono_class_setup_interface_id (MonoClass *klass)
5288 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
5289 mono_loader_lock ();
5290 mono_class_setup_interface_id_internal (klass);
5291 mono_loader_unlock ();
5295 * mono_class_setup_interfaces:
5297 * Initialize klass->interfaces/interfaces_count.
5298 * LOCKING: Acquires the loader lock.
5299 * This function can fail the type.
5301 void
5302 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
5304 int i, interface_count;
5305 MonoClass **interfaces;
5307 error_init (error);
5309 if (klass->interfaces_inited)
5310 return;
5312 if (klass->rank == 1 && m_class_get_byval_arg (klass)->type != MONO_TYPE_ARRAY) {
5313 MonoType *args [1];
5315 /* IList and IReadOnlyList -> 2x if enum*/
5316 interface_count = klass->element_class->enumtype ? 4 : 2;
5317 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
5319 args [0] = m_class_get_byval_arg (m_class_get_element_class (klass));
5320 interfaces [0] = mono_class_bind_generic_parameters (
5321 mono_defaults.generic_ilist_class, 1, args, FALSE);
5322 interfaces [1] = mono_class_bind_generic_parameters (
5323 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5324 if (klass->element_class->enumtype) {
5325 args [0] = mono_class_enum_basetype_internal (klass->element_class);
5326 interfaces [2] = mono_class_bind_generic_parameters (
5327 mono_defaults.generic_ilist_class, 1, args, FALSE);
5328 interfaces [3] = mono_class_bind_generic_parameters (
5329 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5331 } else if (mono_class_is_ginst (klass)) {
5332 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5334 mono_class_setup_interfaces (gklass, error);
5335 if (!mono_error_ok (error)) {
5336 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5337 return;
5340 interface_count = gklass->interface_count;
5341 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
5342 for (i = 0; i < interface_count; i++) {
5343 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
5344 if (!mono_error_ok (error)) {
5345 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5346 return;
5349 } else {
5350 interface_count = 0;
5351 interfaces = NULL;
5354 mono_loader_lock ();
5355 if (!klass->interfaces_inited) {
5356 klass->interface_count = interface_count;
5357 klass->interfaces = interfaces;
5359 mono_memory_barrier ();
5361 klass->interfaces_inited = TRUE;
5363 mono_loader_unlock ();
5368 * mono_class_setup_has_finalizer:
5370 * Initialize klass->has_finalizer if it isn't already initialized.
5372 * LOCKING: Acquires the loader lock.
5374 void
5375 mono_class_setup_has_finalizer (MonoClass *klass)
5377 gboolean has_finalize = FALSE;
5379 if (m_class_is_has_finalize_inited (klass))
5380 return;
5382 /* Interfaces and valuetypes are not supposed to have finalizers */
5383 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_is_valuetype (klass))) {
5384 MonoMethod *cmethod = NULL;
5386 if (m_class_get_rank (klass) == 1 && m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
5387 } else if (mono_class_is_ginst (klass)) {
5388 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5390 has_finalize = mono_class_has_finalizer (gklass);
5391 } else if (m_class_get_parent (klass) && m_class_has_finalize (m_class_get_parent (klass))) {
5392 has_finalize = TRUE;
5393 } else {
5394 if (m_class_get_parent (klass)) {
5396 * Can't search in metadata for a method named Finalize, because that
5397 * ignores overrides.
5399 mono_class_setup_vtable (klass);
5400 if (mono_class_has_failure (klass))
5401 cmethod = NULL;
5402 else
5403 cmethod = m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
5406 if (cmethod) {
5407 g_assert (m_class_get_vtable_size (klass) > mono_class_get_object_finalize_slot ());
5409 if (m_class_get_parent (klass)) {
5410 if (cmethod->is_inflated)
5411 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5412 if (cmethod != mono_class_get_default_finalize_method ())
5413 has_finalize = TRUE;
5419 mono_loader_lock ();
5420 if (!m_class_is_has_finalize_inited (klass)) {
5421 klass->has_finalize = has_finalize ? 1 : 0;
5423 mono_memory_barrier ();
5424 klass->has_finalize_inited = TRUE;
5426 mono_loader_unlock ();
5430 * mono_class_setup_supertypes:
5431 * @class: a class
5433 * Build the data structure needed to make fast type checks work.
5434 * This currently sets two fields in @class:
5435 * - idepth: distance between @class and System.Object in the type
5436 * hierarchy + 1
5437 * - supertypes: array of classes: each element has a class in the hierarchy
5438 * starting from @class up to System.Object
5440 * LOCKING: Acquires the loader lock.
5442 void
5443 mono_class_setup_supertypes (MonoClass *klass)
5445 int ms, idepth;
5446 MonoClass **supertypes;
5448 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5449 if (supertypes)
5450 return;
5452 if (klass->parent && !klass->parent->supertypes)
5453 mono_class_setup_supertypes (klass->parent);
5454 if (klass->parent)
5455 idepth = klass->parent->idepth + 1;
5456 else
5457 idepth = 1;
5459 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5460 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5462 if (klass->parent) {
5463 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5465 int supertype_idx;
5466 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5467 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5468 } else {
5469 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5472 mono_memory_barrier ();
5474 mono_loader_lock ();
5475 klass->idepth = idepth;
5476 /* Needed so idepth is visible before supertypes is set */
5477 mono_memory_barrier ();
5478 klass->supertypes = supertypes;
5479 mono_loader_unlock ();
5482 /* mono_class_setup_nested_types:
5484 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5486 * LOCKING: Acquires the loader lock.
5488 void
5489 mono_class_setup_nested_types (MonoClass *klass)
5491 ERROR_DECL (error);
5492 GList *classes, *nested_classes, *l;
5493 int i;
5495 if (klass->nested_classes_inited)
5496 return;
5498 if (!klass->type_token) {
5499 mono_loader_lock ();
5500 klass->nested_classes_inited = TRUE;
5501 mono_loader_unlock ();
5502 return;
5505 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
5506 classes = NULL;
5507 while (i) {
5508 MonoClass* nclass;
5509 guint32 cols [MONO_NESTED_CLASS_SIZE];
5510 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
5511 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], error);
5512 if (!mono_error_ok (error)) {
5513 /*FIXME don't swallow the error message*/
5514 mono_error_cleanup (error);
5516 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5517 continue;
5520 classes = g_list_prepend (classes, nclass);
5522 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5525 nested_classes = NULL;
5526 for (l = classes; l; l = l->next)
5527 nested_classes = mono_g_list_prepend_image (klass->image, nested_classes, l->data);
5528 g_list_free (classes);
5530 mono_loader_lock ();
5531 if (!klass->nested_classes_inited) {
5532 mono_class_set_nested_classes_property (klass, nested_classes);
5533 mono_memory_barrier ();
5534 klass->nested_classes_inited = TRUE;
5536 mono_loader_unlock ();
5540 * mono_class_setup_runtime_info:
5541 * \param klass the class to setup
5542 * \param domain the domain of the \p vtable
5543 * \param vtable
5545 * Store \p vtable in \c klass->runtime_info.
5547 * Sets the following field in MonoClass:
5548 * - runtime_info
5550 * LOCKING: domain lock and loaderlock must be held.
5552 void
5553 mono_class_setup_runtime_info (MonoClass *klass, MonoDomain *domain, MonoVTable *vtable)
5555 MonoClassRuntimeInfo *old_info = m_class_get_runtime_info (klass);
5556 if (old_info && old_info->max_domain >= domain->domain_id) {
5557 /* someone already created a large enough runtime info */
5558 old_info->domain_vtables [domain->domain_id] = vtable;
5559 } else {
5560 int new_size = domain->domain_id;
5561 if (old_info)
5562 new_size = MAX (new_size, old_info->max_domain);
5563 new_size++;
5564 /* make the new size a power of two */
5565 int i = 2;
5566 while (new_size > i)
5567 i <<= 1;
5568 new_size = i;
5569 /* this is a bounded memory retention issue: may want to
5570 * handle it differently when we'll have a rcu-like system.
5572 MonoClassRuntimeInfo *runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
5573 runtime_info->max_domain = new_size - 1;
5574 /* copy the stuff from the older info */
5575 if (old_info) {
5576 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
5578 runtime_info->domain_vtables [domain->domain_id] = vtable;
5579 /* keep this last*/
5580 mono_memory_barrier ();
5581 klass->runtime_info = runtime_info;
5586 * mono_class_create_array_fill_type:
5588 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5590 MonoClass *
5591 mono_class_create_array_fill_type (void)
5593 static MonoClass klass;
5595 klass.element_class = mono_defaults.int64_class;
5596 klass.rank = 1;
5597 klass.instance_size = MONO_SIZEOF_MONO_ARRAY;
5598 klass.sizes.element_size = 8;
5599 klass.size_inited = 1;
5600 klass.name = "array_filler_type";
5602 return &klass;
5606 * mono_classes_init:
5608 * Initialize the resources used by this module.
5609 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5611 MONO_NO_SANITIZE_THREAD
5612 void
5613 mono_classes_init (void)
5615 mono_os_mutex_init (&classes_mutex);
5617 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
5618 mono_native_tls_alloc (&init_pending_tls_id, NULL);
5620 mono_counters_register ("MonoClassDef count",
5621 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
5622 mono_counters_register ("MonoClassGtd count",
5623 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
5624 mono_counters_register ("MonoClassGenericInst count",
5625 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
5626 mono_counters_register ("MonoClassGenericParam count",
5627 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
5628 mono_counters_register ("MonoClassArray count",
5629 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
5630 mono_counters_register ("MonoClassPointer count",
5631 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
5632 mono_counters_register ("Inflated methods size",
5633 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mono_inflated_methods_size);
5634 mono_counters_register ("Inflated classes size",
5635 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
5636 mono_counters_register ("MonoClass size",
5637 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
5641 * mono_classes_cleanup:
5643 * Free the resources used by this module.
5645 void
5646 mono_classes_cleanup (void)
5648 mono_native_tls_free (setup_fields_tls_id);
5649 mono_native_tls_free (init_pending_tls_id);
5651 if (global_interface_bitset)
5652 mono_bitset_free (global_interface_bitset);
5653 global_interface_bitset = NULL;
5654 mono_os_mutex_destroy (&classes_mutex);