Pass the --clr-memory-model flag on the command line instead of MONO_DEBUG so its...
[mono-project.git] / mono / metadata / class-init.c
blob5932f0814faf3ff7a1402ae3a2e8547e3dc030b4
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;
1536 static gboolean
1537 method_is_reabstracted (guint16 flags)
1539 if ((flags & METHOD_ATTRIBUTE_ABSTRACT && flags & METHOD_ATTRIBUTE_FINAL))
1540 return TRUE;
1541 return FALSE;
1545 * Return the number of virtual methods.
1546 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1547 * Return -1 on failure.
1548 * FIXME It would be nice if this information could be cached somewhere.
1550 static int
1551 count_virtual_methods (MonoClass *klass)
1553 int i, mcount, vcount = 0;
1554 guint32 flags;
1555 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
1557 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
1558 mono_class_setup_methods (klass);
1559 if (mono_class_has_failure (klass))
1560 return -1;
1562 mcount = mono_class_get_method_count (klass);
1563 for (i = 0; i < mcount; ++i) {
1564 flags = klass->methods [i]->flags;
1565 if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1566 if (method_is_reabstracted (flags))
1567 continue;
1568 ++vcount;
1571 } else {
1572 int first_idx = mono_class_get_first_method_idx (klass);
1573 mcount = mono_class_get_method_count (klass);
1574 for (i = 0; i < mcount; ++i) {
1575 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
1577 if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1578 if (method_is_reabstracted (flags))
1579 continue;
1580 ++vcount;
1584 return vcount;
1587 static mono_bool
1588 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
1590 int i;
1591 for (i = 0; i < num_ifaces; ++i) {
1592 if (interfaces_full [i] && interfaces_full [i]->interface_id == ic->interface_id) {
1593 if (!force_set)
1594 return TRUE;
1595 interface_offsets_full [i] = offset;
1596 return FALSE;
1598 if (interfaces_full [i])
1599 continue;
1600 interfaces_full [i] = ic;
1601 interface_offsets_full [i] = offset;
1602 break;
1604 return FALSE;
1607 #ifdef COMPRESSED_INTERFACE_BITMAP
1610 * Compressed interface bitmap design.
1612 * Interface bitmaps take a large amount of memory, because their size is
1613 * linear with the maximum interface id assigned in the process (each interface
1614 * is assigned a unique id as it is loaded). The number of interface classes
1615 * is high because of the many implicit interfaces implemented by arrays (we'll
1616 * need to lazy-load them in the future).
1617 * Most classes implement a very small number of interfaces, so the bitmap is
1618 * sparse. This bitmap needs to be checked by interface casts, so access to the
1619 * needed bit must be fast and doable with few jit instructions.
1621 * The current compression format is as follows:
1622 * *) it is a sequence of one or more two-byte elements
1623 * *) the first byte in the element is the count of empty bitmap bytes
1624 * at the current bitmap position
1625 * *) the second byte in the element is an actual bitmap byte at the current
1626 * bitmap position
1628 * As an example, the following compressed bitmap bytes:
1629 * 0x07 0x01 0x00 0x7
1630 * correspond to the following bitmap:
1631 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1633 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1634 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1635 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1639 * mono_compress_bitmap:
1640 * \param dest destination buffer
1641 * \param bitmap bitmap buffer
1642 * \param size size of \p bitmap in bytes
1644 * This is a mono internal function.
1645 * The \p bitmap data is compressed into a format that is small but
1646 * still searchable in few instructions by the JIT and runtime.
1647 * The compressed data is stored in the buffer pointed to by the
1648 * \p dest array. Passing a NULL value for \p dest allows to just compute
1649 * the size of the buffer.
1650 * This compression algorithm assumes the bits set in the bitmap are
1651 * few and far between, like in interface bitmaps.
1652 * \returns The size of the compressed bitmap in bytes.
1655 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
1657 int numz = 0;
1658 int res = 0;
1659 const uint8_t *end = bitmap + size;
1660 while (bitmap < end) {
1661 if (*bitmap || numz == 255) {
1662 if (dest) {
1663 *dest++ = numz;
1664 *dest++ = *bitmap;
1666 res += 2;
1667 numz = 0;
1668 bitmap++;
1669 continue;
1671 bitmap++;
1672 numz++;
1674 if (numz) {
1675 res += 2;
1676 if (dest) {
1677 *dest++ = numz;
1678 *dest++ = 0;
1681 return res;
1685 * mono_class_interface_match:
1686 * \param bitmap a compressed bitmap buffer
1687 * \param id the index to check in the bitmap
1689 * This is a mono internal function.
1690 * Checks if a bit is set in a compressed interface bitmap. \p id must
1691 * be already checked for being smaller than the maximum id encoded in the
1692 * bitmap.
1694 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1695 * FALSE otherwise.
1698 mono_class_interface_match (const uint8_t *bitmap, int id)
1700 while (TRUE) {
1701 id -= bitmap [0] * 8;
1702 if (id < 8) {
1703 if (id < 0)
1704 return 0;
1705 return bitmap [1] & (1 << id);
1707 bitmap += 2;
1708 id -= 8;
1711 #endif
1713 typedef struct {
1714 MonoClass *ic;
1715 int offset;
1716 int insertion_order;
1717 } ClassAndOffset;
1719 static int
1720 compare_by_interface_id (const void *a, const void *b)
1722 const ClassAndOffset *ca = (const ClassAndOffset*)a;
1723 const ClassAndOffset *cb = (const ClassAndOffset*)b;
1725 /* Sort on interface_id, but keep equal elements in the same relative
1726 * order. */
1727 int primary_order = ca->ic->interface_id - cb->ic->interface_id;
1728 if (primary_order != 0)
1729 return primary_order;
1730 else
1731 return ca->insertion_order - cb->insertion_order;
1735 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1736 * LOCKING: Acquires the loader lock.
1738 static int
1739 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
1741 ERROR_DECL (error);
1742 MonoClass *k, *ic;
1743 int i, j, num_ifaces;
1744 guint32 max_iid;
1745 MonoClass **interfaces_full = NULL;
1746 int *interface_offsets_full = NULL;
1747 GPtrArray *ifaces;
1748 GPtrArray **ifaces_array = NULL;
1749 int interface_offsets_count;
1750 max_iid = 0;
1751 num_ifaces = interface_offsets_count = 0;
1753 mono_loader_lock ();
1755 mono_class_setup_supertypes (klass);
1757 if (mono_class_is_ginst (klass)) {
1758 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1760 interface_offsets_count = num_ifaces = gklass->interface_offsets_count;
1761 interfaces_full = (MonoClass **)g_malloc (sizeof (MonoClass*) * num_ifaces);
1762 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1764 cur_slot = 0;
1765 for (int i = 0; i < num_ifaces; ++i) {
1766 MonoClass *gklass_ic = gklass->interfaces_packed [i];
1767 MonoClass *inflated = mono_class_inflate_generic_class_checked (gklass_ic, mono_class_get_context(klass), error);
1768 if (!is_ok (error)) {
1769 char *name = mono_type_get_full_name (gklass_ic);
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 mono_class_setup_interface_id_internal (inflated);
1778 interfaces_full [i] = inflated;
1779 interface_offsets_full [i] = gklass->interface_offsets_packed [i];
1781 int count = count_virtual_methods (inflated);
1782 if (count == -1) {
1783 char *name = mono_type_get_full_name (inflated);
1784 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1785 g_free (name);
1786 cur_slot = -1;
1787 goto end;
1790 cur_slot = MAX (cur_slot, interface_offsets_full [i] + count);
1791 max_iid = MAX (max_iid, inflated->interface_id);
1794 goto publish;
1796 /* compute maximum number of slots and maximum interface id */
1797 max_iid = 0;
1798 num_ifaces = 0; /* this can include duplicated ones */
1799 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
1800 for (j = 0; j < klass->idepth; j++) {
1801 k = klass->supertypes [j];
1802 g_assert (k);
1803 num_ifaces += k->interface_count;
1804 for (i = 0; i < k->interface_count; i++) {
1805 ic = k->interfaces [i];
1807 /* A gparam does not have any interface_id set. */
1808 if (! mono_class_is_gparam (ic))
1809 mono_class_setup_interface_id_internal (ic);
1811 if (max_iid < ic->interface_id)
1812 max_iid = ic->interface_id;
1814 ifaces = mono_class_get_implemented_interfaces (k, error);
1815 if (!mono_error_ok (error)) {
1816 char *name = mono_type_get_full_name (k);
1817 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (error));
1818 g_free (name);
1819 mono_error_cleanup (error);
1820 cur_slot = -1;
1821 goto end;
1823 if (ifaces) {
1824 num_ifaces += ifaces->len;
1825 for (i = 0; i < ifaces->len; ++i) {
1826 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1827 if (max_iid < ic->interface_id)
1828 max_iid = ic->interface_id;
1830 ifaces_array [j] = ifaces;
1834 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
1835 num_ifaces++;
1836 if (max_iid < klass->interface_id)
1837 max_iid = klass->interface_id;
1840 /* compute vtable offset for interfaces */
1841 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
1842 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1844 for (i = 0; i < num_ifaces; i++)
1845 interface_offsets_full [i] = -1;
1847 /* skip the current class */
1848 for (j = 0; j < klass->idepth - 1; j++) {
1849 k = klass->supertypes [j];
1850 ifaces = ifaces_array [j];
1852 if (ifaces) {
1853 for (i = 0; i < ifaces->len; ++i) {
1854 int io;
1855 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1857 /*Force the sharing of interface offsets between parent and subtypes.*/
1858 io = mono_class_interface_offset (k, ic);
1859 g_assertf (io >= 0, "class %s parent %s has no offset for iface %s",
1860 mono_type_get_full_name (klass),
1861 mono_type_get_full_name (k),
1862 mono_type_get_full_name (ic));
1864 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
1869 g_assert (klass == klass->supertypes [klass->idepth - 1]);
1870 ifaces = ifaces_array [klass->idepth - 1];
1871 if (ifaces) {
1872 for (i = 0; i < ifaces->len; ++i) {
1873 int count;
1874 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1875 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
1876 continue;
1877 count = count_virtual_methods (ic);
1878 if (count == -1) {
1879 char *name = mono_type_get_full_name (ic);
1880 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1881 g_free (name);
1882 cur_slot = -1;
1883 goto end;
1885 cur_slot += count;
1889 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass))
1890 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
1892 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
1893 if (interface_offsets_full [i] != -1)
1894 interface_offsets_count ++;
1897 publish:
1898 /* Publish the data */
1899 klass->max_interface_id = max_iid;
1901 * We might get called multiple times:
1902 * - mono_class_init_internal ()
1903 * - mono_class_setup_vtable ().
1904 * - mono_class_setup_interface_offsets ().
1905 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1906 * means we have to overwrite those when called from other places (#4440).
1908 if (klass->interfaces_packed) {
1909 if (!overwrite)
1910 g_assert (klass->interface_offsets_count == interface_offsets_count);
1911 } else {
1912 uint8_t *bitmap;
1913 int bsize;
1914 klass->interface_offsets_count = interface_offsets_count;
1915 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
1916 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
1917 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
1918 #ifdef COMPRESSED_INTERFACE_BITMAP
1919 bitmap = g_malloc0 (bsize);
1920 #else
1921 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
1922 #endif
1923 for (i = 0; i < interface_offsets_count; i++) {
1924 guint32 id = interfaces_full [i]->interface_id;
1925 bitmap [id >> 3] |= (1 << (id & 7));
1926 klass->interfaces_packed [i] = interfaces_full [i];
1927 klass->interface_offsets_packed [i] = interface_offsets_full [i];
1929 #ifdef COMPRESSED_INTERFACE_BITMAP
1930 i = mono_compress_bitmap (NULL, bitmap, bsize);
1931 klass->interface_bitmap = mono_class_alloc0 (klass, i);
1932 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
1933 g_free (bitmap);
1934 #else
1935 klass->interface_bitmap = bitmap;
1936 #endif
1938 end:
1939 mono_loader_unlock ();
1941 g_free (interfaces_full);
1942 g_free (interface_offsets_full);
1943 if (ifaces_array) {
1944 for (i = 0; i < klass->idepth; i++) {
1945 ifaces = ifaces_array [i];
1946 if (ifaces)
1947 g_ptr_array_free (ifaces, TRUE);
1949 g_free (ifaces_array);
1952 //printf ("JUST DONE: ");
1953 //print_implemented_interfaces (klass);
1955 return cur_slot;
1959 * Setup interface offsets for interfaces.
1960 * Initializes:
1961 * - klass->max_interface_id
1962 * - klass->interface_offsets_count
1963 * - klass->interfaces_packed
1964 * - klass->interface_offsets_packed
1965 * - klass->interface_bitmap
1967 * This function can fail @class.
1970 void
1971 mono_class_setup_interface_offsets (MonoClass *klass)
1973 /* NOTE: This function is only correct for interfaces.
1975 * It assumes that klass's interfaces can be assigned offsets starting
1976 * from 0. That assumption is incorrect for classes and valuetypes.
1978 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && !mono_class_is_ginst (klass));
1979 setup_interface_offsets (klass, 0, FALSE);
1982 #define DEBUG_INTERFACE_VTABLE_CODE 0
1983 #define TRACE_INTERFACE_VTABLE_CODE 0
1984 #define VERIFY_INTERFACE_VTABLE_CODE 0
1985 #define VTABLE_SELECTOR (1)
1987 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
1988 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
1989 if (!(VTABLE_SELECTOR)) break; \
1990 stmt;\
1991 } while (0)
1992 #else
1993 #define DEBUG_INTERFACE_VTABLE(stmt)
1994 #endif
1996 #if TRACE_INTERFACE_VTABLE_CODE
1997 #define TRACE_INTERFACE_VTABLE(stmt) do {\
1998 if (!(VTABLE_SELECTOR)) break; \
1999 stmt;\
2000 } while (0)
2001 #else
2002 #define TRACE_INTERFACE_VTABLE(stmt)
2003 #endif
2005 #if VERIFY_INTERFACE_VTABLE_CODE
2006 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
2007 if (!(VTABLE_SELECTOR)) break; \
2008 stmt;\
2009 } while (0)
2010 #else
2011 #define VERIFY_INTERFACE_VTABLE(stmt)
2012 #endif
2015 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2016 static char*
2017 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
2019 int i;
2020 char *result;
2021 GString *res = g_string_new ("");
2023 g_string_append_c (res, '(');
2024 for (i = 0; i < sig->param_count; ++i) {
2025 if (i > 0)
2026 g_string_append_c (res, ',');
2027 mono_type_get_desc (res, sig->params [i], include_namespace);
2029 g_string_append (res, ")=>");
2030 if (sig->ret != NULL) {
2031 mono_type_get_desc (res, sig->ret, include_namespace);
2032 } else {
2033 g_string_append (res, "NULL");
2035 result = res->str;
2036 g_string_free (res, FALSE);
2037 return result;
2039 static void
2040 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
2041 char *im_sig = mono_signature_get_full_desc (mono_method_signature_internal (im), TRUE);
2042 char *cm_sig = mono_signature_get_full_desc (mono_method_signature_internal (cm), TRUE);
2043 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
2044 g_free (im_sig);
2045 g_free (cm_sig);
2049 #endif
2051 static gboolean
2052 is_wcf_hack_disabled (void)
2054 static char disabled;
2055 if (!disabled)
2056 disabled = g_hasenv ("MONO_DISABLE_WCF_HACK") ? 1 : 2;
2057 return disabled == 1;
2060 static gboolean
2061 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
2063 MonoMethodSignature *cmsig, *imsig;
2064 if (strcmp (im->name, cm->name) == 0) {
2065 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
2066 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2067 return FALSE;
2069 if (! slot_is_empty) {
2070 if (require_newslot) {
2071 if (! interface_is_explicitly_implemented_by_class) {
2072 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2073 return FALSE;
2075 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
2076 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2077 return FALSE;
2079 } else {
2080 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2083 cmsig = mono_method_signature_internal (cm);
2084 imsig = mono_method_signature_internal (im);
2085 if (!cmsig || !imsig) {
2086 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2087 return FALSE;
2090 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2091 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2092 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2093 TRACE_INTERFACE_VTABLE (printf ("]"));
2094 return FALSE;
2096 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2097 if (mono_security_core_clr_enabled ())
2098 mono_security_core_clr_check_override (klass, cm, im);
2100 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2101 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2102 char *body_name = mono_method_full_name (cm, TRUE);
2103 char *decl_name = mono_method_full_name (im, TRUE);
2104 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2105 g_free (body_name);
2106 g_free (decl_name);
2107 return FALSE;
2110 return TRUE;
2111 } else {
2112 MonoClass *ic = im->klass;
2113 const char *ic_name_space = ic->name_space;
2114 const char *ic_name = ic->name;
2115 char *subname;
2117 if (! require_newslot) {
2118 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2119 return FALSE;
2121 if (cm->klass->rank == 0) {
2122 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2123 return FALSE;
2125 cmsig = mono_method_signature_internal (cm);
2126 imsig = mono_method_signature_internal (im);
2127 if (!cmsig || !imsig) {
2128 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2129 return FALSE;
2132 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2133 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2134 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2135 TRACE_INTERFACE_VTABLE (printf ("]"));
2136 return FALSE;
2138 if (mono_class_get_image (ic) != mono_defaults.corlib) {
2139 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2140 return FALSE;
2142 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
2143 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2144 return FALSE;
2146 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))) {
2147 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2148 return FALSE;
2151 subname = (char*)strstr (cm->name, ic_name_space);
2152 if (subname != cm->name) {
2153 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2154 return FALSE;
2156 subname += strlen (ic_name_space);
2157 if (subname [0] != '.') {
2158 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2159 return FALSE;
2161 subname ++;
2162 if (strstr (subname, ic_name) != subname) {
2163 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2164 return FALSE;
2166 subname += strlen (ic_name);
2167 if (subname [0] != '.') {
2168 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2169 return FALSE;
2171 subname ++;
2172 if (strcmp (subname, im->name) != 0) {
2173 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2174 return FALSE;
2177 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2178 if (mono_security_core_clr_enabled ())
2179 mono_security_core_clr_check_override (klass, cm, im);
2181 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2182 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2183 char *body_name = mono_method_full_name (cm, TRUE);
2184 char *decl_name = mono_method_full_name (im, TRUE);
2185 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2186 g_free (body_name);
2187 g_free (decl_name);
2188 return FALSE;
2191 return TRUE;
2195 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2196 static void
2197 foreach_override (gpointer key, gpointer value, gpointer user_data)
2199 MonoMethod *method = key;
2200 MonoMethod *override = value;
2202 char *method_name = mono_method_get_full_name (method);
2203 char *override_name = mono_method_get_full_name (override);
2204 printf (" Method '%s' has override '%s'\n", method_name, override_name);
2205 g_free (method_name);
2206 g_free (override_name);
2209 static void
2210 print_overrides (GHashTable *override_map, const char *message)
2212 if (override_map) {
2213 printf ("Override map \"%s\" START:\n", message);
2214 g_hash_table_foreach (override_map, foreach_override, NULL);
2215 printf ("Override map \"%s\" END.\n", message);
2216 } else {
2217 printf ("Override map \"%s\" EMPTY.\n", message);
2221 static void
2222 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces)
2224 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2225 int i;
2226 int parent_size;
2228 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
2230 if (print_interfaces) {
2231 print_implemented_interfaces (klass);
2232 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
2235 if (klass->parent) {
2236 parent_size = klass->parent->vtable_size;
2237 } else {
2238 parent_size = 0;
2240 for (i = 0; i < size; ++i) {
2241 MonoMethod *cm = vtable [i];
2242 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
2243 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
2245 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
2246 g_free (cm_name);
2249 g_free (full_name);
2251 #endif
2253 #if VERIFY_INTERFACE_VTABLE_CODE
2254 static int
2255 mono_method_try_get_vtable_index (MonoMethod *method)
2257 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2258 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
2259 if (imethod->declaring->is_generic)
2260 return imethod->declaring->slot;
2262 return method->slot;
2265 static void
2266 mono_class_verify_vtable (MonoClass *klass)
2268 int i, count;
2269 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2271 printf ("*** Verifying VTable of class '%s' \n", full_name);
2272 g_free (full_name);
2273 full_name = NULL;
2275 if (!klass->methods)
2276 return;
2278 count = mono_class_get_method_count (klass);
2279 for (i = 0; i < count; ++i) {
2280 MonoMethod *cm = klass->methods [i];
2281 int slot;
2283 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2284 continue;
2286 g_free (full_name);
2287 full_name = mono_method_full_name (cm, TRUE);
2289 slot = mono_method_try_get_vtable_index (cm);
2290 if (slot >= 0) {
2291 if (slot >= klass->vtable_size) {
2292 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
2293 continue;
2296 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
2297 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
2298 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
2299 g_free (other_name);
2301 } else
2302 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
2304 g_free (full_name);
2306 #endif
2308 static MonoMethod*
2309 mono_method_get_method_definition (MonoMethod *method)
2311 while (method->is_inflated)
2312 method = ((MonoMethodInflated*)method)->declaring;
2313 return method;
2316 static gboolean
2317 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
2319 int i;
2321 for (i = 0; i < onum; ++i) {
2322 MonoMethod *decl = overrides [i * 2];
2323 MonoMethod *body = overrides [i * 2 + 1];
2325 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
2326 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
2327 return FALSE;
2330 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
2331 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2332 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
2333 else
2334 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
2335 return FALSE;
2338 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
2339 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2340 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
2341 else
2342 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
2343 return FALSE;
2346 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
2347 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
2348 return FALSE;
2351 body = mono_method_get_method_definition (body);
2352 decl = mono_method_get_method_definition (decl);
2354 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
2355 char *body_name = mono_method_full_name (body, TRUE);
2356 char *decl_name = mono_method_full_name (decl, TRUE);
2357 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2358 g_free (body_name);
2359 g_free (decl_name);
2360 return FALSE;
2363 return TRUE;
2366 /*Checks if @klass has @parent as one of it's parents type gtd
2368 * For example:
2369 * Foo<T>
2370 * Bar<T> : Foo<Bar<Bar<T>>>
2373 static gboolean
2374 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
2376 klass = mono_class_get_generic_type_definition (klass);
2377 parent = mono_class_get_generic_type_definition (parent);
2378 mono_class_setup_supertypes (klass);
2379 mono_class_setup_supertypes (parent);
2381 return klass->idepth >= parent->idepth &&
2382 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
2385 gboolean
2386 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
2388 MonoGenericInst *ginst;
2389 int i;
2391 if (!mono_class_is_ginst (klass)) {
2392 mono_class_setup_vtable_full (klass, in_setup);
2393 return !mono_class_has_failure (klass);
2396 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
2397 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
2398 return FALSE;
2400 ginst = mono_class_get_generic_class (klass)->context.class_inst;
2401 for (i = 0; i < ginst->type_argc; ++i) {
2402 MonoClass *arg;
2403 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
2404 continue;
2405 arg = mono_class_from_mono_type_internal (ginst->type_argv [i]);
2406 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2407 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
2408 continue;
2409 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
2410 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
2411 return FALSE;
2414 return TRUE;
2418 * mono_class_setup_vtable:
2420 * Creates the generic vtable of CLASS.
2421 * Initializes the following fields in MonoClass:
2422 * - vtable
2423 * - vtable_size
2424 * Plus all the fields initialized by setup_interface_offsets ().
2425 * If there is an error during vtable construction, klass->has_failure
2426 * is set and details are stored in a MonoErrorBoxed.
2428 * LOCKING: Acquires the loader lock.
2430 void
2431 mono_class_setup_vtable (MonoClass *klass)
2433 mono_class_setup_vtable_full (klass, NULL);
2436 static void
2437 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
2439 ERROR_DECL (error);
2440 MonoMethod **overrides = NULL;
2441 MonoGenericContext *context;
2442 guint32 type_token;
2443 int onum = 0;
2445 if (klass->vtable)
2446 return;
2448 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
2449 /* This sets method->slot for all methods if this is an interface */
2450 mono_class_setup_methods (klass);
2451 return;
2454 if (mono_class_has_failure (klass))
2455 return;
2457 if (g_list_find (in_setup, klass))
2458 return;
2460 mono_loader_lock ();
2462 if (klass->vtable) {
2463 mono_loader_unlock ();
2464 return;
2467 UnlockedIncrement (&mono_stats.generic_vtable_count);
2468 in_setup = g_list_prepend (in_setup, klass);
2470 if (mono_class_is_ginst (klass)) {
2471 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
2472 mono_loader_unlock ();
2473 g_list_remove (in_setup, klass);
2474 return;
2477 context = mono_class_get_context (klass);
2478 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
2479 } else {
2480 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
2481 type_token = klass->type_token;
2484 if (image_is_dynamic (klass->image)) {
2485 /* Generic instances can have zero method overrides without causing any harm.
2486 * This is true since we don't do layout all over again for them, we simply inflate
2487 * the layout of the parent.
2489 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, error);
2490 if (!is_ok (error)) {
2491 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2492 goto done;
2494 } else {
2495 /* The following call fails if there are missing methods in the type */
2496 /* FIXME it's probably a good idea to avoid this for generic instances. */
2497 mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context, error);
2498 if (!is_ok (error)) {
2499 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2500 goto done;
2504 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
2506 done:
2507 g_free (overrides);
2508 mono_error_cleanup (error);
2510 mono_loader_unlock ();
2511 g_list_remove (in_setup, klass);
2513 return;
2516 static gboolean
2517 mono_class_need_stelemref_method (MonoClass *klass)
2519 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass)));
2522 static int
2523 apply_override (MonoClass *klass, MonoClass *override_class, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override,
2524 GHashTable **override_map, GHashTable **override_class_map, GHashTable **conflict_map)
2526 int dslot;
2527 dslot = mono_method_get_vtable_slot (decl);
2528 if (dslot == -1) {
2529 mono_class_set_type_load_failure (klass, "");
2530 return FALSE;
2533 dslot += mono_class_interface_offset (klass, decl->klass);
2534 vtable [dslot] = override;
2535 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass)) {
2537 * If override from an interface, then it is an override of a default interface method,
2538 * don't override its slot.
2540 vtable [dslot]->slot = dslot;
2543 if (!*override_map) {
2544 *override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2545 *override_class_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2547 GHashTable *map = *override_map;
2548 GHashTable *class_map = *override_class_map;
2550 MonoMethod *prev_override = (MonoMethod*)g_hash_table_lookup (map, decl);
2551 MonoClass *prev_override_class = (MonoClass*)g_hash_table_lookup (class_map, decl);
2553 g_hash_table_insert (map, decl, override);
2554 g_hash_table_insert (class_map, decl, override_class);
2556 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2557 if (prev_override) {
2558 ERROR_DECL (error);
2561 * The override methods are part of the generic definition, need to inflate them so their
2562 * parent class becomes the actual interface/class containing the override, i.e.
2563 * IFace<T> in:
2564 * class Foo<T> : IFace<T>
2565 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2566 * conflict resolution work.
2568 if (mono_class_is_ginst (override_class)) {
2569 override = mono_class_inflate_generic_method_checked (override, &mono_class_get_generic_class (override_class)->context, error);
2570 mono_error_assert_ok (error);
2573 if (mono_class_is_ginst (prev_override_class)) {
2574 prev_override = mono_class_inflate_generic_method_checked (prev_override, &mono_class_get_generic_class (prev_override_class)->context, error);
2575 mono_error_assert_ok (error);
2578 if (!*conflict_map)
2579 *conflict_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2580 GHashTable *cmap = *conflict_map;
2581 GSList *entries = (GSList*)g_hash_table_lookup (cmap, decl);
2582 if (!(decl->flags & METHOD_ATTRIBUTE_ABSTRACT))
2583 entries = g_slist_prepend (entries, decl);
2584 entries = g_slist_prepend (entries, prev_override);
2585 entries = g_slist_prepend (entries, override);
2587 g_hash_table_insert (cmap, decl, entries);
2590 return TRUE;
2593 static void
2594 handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflict_map)
2596 GHashTableIter iter;
2597 MonoMethod *decl;
2598 GSList *entries, *l, *l2;
2599 GSList *dim_conflicts = NULL;
2601 g_hash_table_iter_init (&iter, conflict_map);
2602 while (g_hash_table_iter_next (&iter, (gpointer*)&decl, (gpointer*)&entries)) {
2604 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2605 * class of another one.
2607 /* This is O(n^2), but that shouldn't be a problem in practice */
2608 for (l = entries; l; l = l->next) {
2609 for (l2 = entries; l2; l2 = l2->next) {
2610 MonoMethod *m1 = (MonoMethod*)l->data;
2611 MonoMethod *m2 = (MonoMethod*)l2->data;
2612 if (!m1 || !m2 || m1 == m2)
2613 continue;
2614 if (mono_class_is_assignable_from_internal (m1->klass, m2->klass))
2615 l->data = NULL;
2616 else if (mono_class_is_assignable_from_internal (m2->klass, m1->klass))
2617 l2->data = NULL;
2620 int nentries = 0;
2621 MonoMethod *impl = NULL;
2622 for (l = entries; l; l = l->next) {
2623 if (l->data) {
2624 nentries ++;
2625 impl = (MonoMethod*)l->data;
2628 if (nentries > 1) {
2629 /* If more than one method is left, we have a conflict */
2630 if (decl->is_inflated)
2631 decl = ((MonoMethodInflated*)decl)->declaring;
2632 dim_conflicts = g_slist_prepend (dim_conflicts, decl);
2634 for (l = entries; l; l = l->next) {
2635 if (l->data)
2636 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2639 } else {
2641 * Use the implementing method computed above instead of the already
2642 * computed one, which depends on interface ordering.
2644 int ic_offset = mono_class_interface_offset (klass, decl->klass);
2645 int im_slot = ic_offset + decl->slot;
2646 vtable [im_slot] = impl;
2648 g_slist_free (entries);
2650 if (dim_conflicts) {
2651 mono_loader_lock ();
2652 klass->has_dim_conflicts = 1;
2653 mono_loader_unlock ();
2656 * Exceptions are thrown at method call time and only for the methods which have
2657 * conflicts, so just save them in the class.
2660 /* Make a copy of the list from the class mempool */
2661 GSList *conflicts = (GSList*)mono_class_alloc0 (klass, g_slist_length (dim_conflicts) * sizeof (GSList));
2662 int i = 0;
2663 for (l = dim_conflicts; l; l = l->next) {
2664 conflicts [i].data = l->data;
2665 conflicts [i].next = &conflicts [i + 1];
2666 i ++;
2668 conflicts [i - 1].next = NULL;
2670 mono_class_set_dim_conflicts (klass, conflicts);
2671 g_slist_free (dim_conflicts);
2675 static void
2676 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
2678 int index, mcount;
2679 char *method_signature;
2680 char *type_name;
2682 for (index = 0; index < onum; ++index) {
2683 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name,
2684 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
2686 method_signature = mono_signature_get_desc (mono_method_signature_internal (im), FALSE);
2687 type_name = mono_type_full_name (m_class_get_byval_arg (klass));
2688 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s",
2689 mono_type_get_name (m_class_get_byval_arg (ic)), im->name, method_signature, type_name);
2690 g_free (method_signature);
2691 g_free (type_name);
2692 mono_class_setup_methods (klass);
2693 if (mono_class_has_failure (klass)) {
2694 char *name = mono_type_get_full_name (klass);
2695 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name);
2696 g_free (name);
2697 return;
2699 mcount = mono_class_get_method_count (klass);
2700 for (index = 0; index < mcount; ++index) {
2701 MonoMethod *cm = klass->methods [index];
2702 method_signature = mono_signature_get_desc (mono_method_signature_internal (cm), TRUE);
2704 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature);
2705 g_free (method_signature);
2710 * mono_class_get_virtual_methods:
2712 * Iterate over the virtual methods of KLASS.
2714 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2716 static MonoMethod*
2717 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
2719 gboolean static_iter = FALSE;
2721 if (!iter)
2722 return NULL;
2725 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2726 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2727 * klass->methods.
2729 if ((gsize)(*iter) & 1)
2730 static_iter = TRUE;
2731 /* Use the static metadata only if klass->methods is not yet initialized */
2732 if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
2733 static_iter = TRUE;
2735 if (!static_iter) {
2736 MonoMethod** methodptr;
2738 if (!*iter) {
2739 mono_class_setup_methods (klass);
2741 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2742 * FIXME we should better report this error to the caller
2744 if (!klass->methods)
2745 return NULL;
2746 /* start from the first */
2747 methodptr = &klass->methods [0];
2748 } else {
2749 methodptr = (MonoMethod **)*iter;
2750 methodptr++;
2752 if (*iter)
2753 g_assert ((guint64)(*iter) > 0x100);
2754 int mcount = mono_class_get_method_count (klass);
2755 while (methodptr < &klass->methods [mcount]) {
2756 if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
2757 break;
2758 methodptr ++;
2760 if (methodptr < &klass->methods [mcount]) {
2761 *iter = methodptr;
2762 return *methodptr;
2763 } else {
2764 return NULL;
2766 } else {
2767 /* Search directly in metadata to avoid calling setup_methods () */
2768 MonoMethod *res = NULL;
2769 int i, start_index;
2771 if (!*iter) {
2772 start_index = 0;
2773 } else {
2774 start_index = GPOINTER_TO_UINT (*iter) >> 1;
2777 int first_idx = mono_class_get_first_method_idx (klass);
2778 int mcount = mono_class_get_method_count (klass);
2779 for (i = start_index; i < mcount; ++i) {
2780 guint32 flags;
2782 /* first_idx points into the methodptr table */
2783 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
2785 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2786 break;
2789 if (i < mcount) {
2790 ERROR_DECL (error);
2791 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
2792 mono_error_cleanup (error); /* FIXME don't swallow the error */
2794 /* Add 1 here so the if (*iter) check fails */
2795 *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1);
2796 return res;
2797 } else {
2798 return NULL;
2803 static void
2804 print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot)
2806 int i, icount = 0;
2808 print_implemented_interfaces (klass);
2810 for (i = 0; i <= klass->max_interface_id; i++)
2811 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2812 icount++;
2814 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass)),
2815 klass->vtable_size, icount);
2817 for (i = 0; i < cur_slot; ++i) {
2818 MonoMethod *cm;
2820 cm = vtable [i];
2821 if (cm) {
2822 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
2823 mono_method_get_full_name (cm));
2824 } else {
2825 printf (" slot assigned: %03d, <null>\n", i);
2830 if (icount) {
2831 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
2832 klass->name, klass->max_interface_id);
2834 for (i = 0; i < klass->interface_count; i++) {
2835 MonoClass *ic = klass->interfaces [i];
2836 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2837 mono_class_interface_offset (klass, ic),
2838 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2841 for (MonoClass *k = klass->parent; k ; k = k->parent) {
2842 for (i = 0; i < k->interface_count; i++) {
2843 MonoClass *ic = k->interfaces [i];
2844 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2845 mono_class_interface_offset (klass, ic),
2846 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2853 * LOCKING: this is supposed to be called with the loader lock held.
2855 void
2856 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
2858 ERROR_DECL (error);
2859 MonoClass *k, *ic;
2860 MonoMethod **vtable = NULL;
2861 int i, max_vtsize = 0, cur_slot = 0;
2862 GPtrArray *ifaces = NULL;
2863 GHashTable *override_map = NULL;
2864 GHashTable *override_class_map = NULL;
2865 GHashTable *conflict_map = NULL;
2866 MonoMethod *cm;
2867 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2868 int first_non_interface_slot;
2869 #endif
2870 GSList *virt_methods = NULL, *l;
2871 int stelemref_slot = 0;
2873 error_init (error);
2875 if (klass->vtable)
2876 return;
2878 if (overrides && !verify_class_overrides (klass, overrides, onum))
2879 return;
2881 ifaces = mono_class_get_implemented_interfaces (klass, error);
2882 if (!mono_error_ok (error)) {
2883 char *name = mono_type_get_full_name (klass);
2884 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (error));
2885 g_free (name);
2886 mono_error_cleanup (error);
2887 return;
2888 } else if (ifaces) {
2889 for (i = 0; i < ifaces->len; i++) {
2890 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2891 max_vtsize += mono_class_get_method_count (ic);
2893 g_ptr_array_free (ifaces, TRUE);
2894 ifaces = NULL;
2897 if (klass->parent) {
2898 mono_class_init_internal (klass->parent);
2899 mono_class_setup_vtable_full (klass->parent, in_setup);
2901 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
2902 return;
2904 max_vtsize += klass->parent->vtable_size;
2905 cur_slot = klass->parent->vtable_size;
2908 max_vtsize += mono_class_get_method_count (klass);
2910 /*Array have a slot for stelemref*/
2911 if (mono_class_need_stelemref_method (klass)) {
2912 stelemref_slot = cur_slot;
2913 ++max_vtsize;
2914 ++cur_slot;
2917 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
2919 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
2920 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
2921 return;
2923 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
2925 /* Optimized version for generic instances */
2926 if (mono_class_is_ginst (klass)) {
2927 ERROR_DECL (error);
2928 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2929 MonoMethod **tmp;
2931 mono_class_setup_vtable_full (gklass, in_setup);
2932 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
2933 return;
2935 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
2936 klass->vtable_size = gklass->vtable_size;
2937 for (i = 0; i < gklass->vtable_size; ++i)
2938 if (gklass->vtable [i]) {
2939 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), error);
2940 goto_if_nok (error, fail);
2941 tmp [i] = inflated;
2942 tmp [i]->slot = gklass->vtable [i]->slot;
2944 mono_memory_barrier ();
2945 klass->vtable = tmp;
2947 mono_loader_lock ();
2948 klass->has_dim_conflicts = gklass->has_dim_conflicts;
2949 mono_loader_unlock ();
2951 /* Have to set method->slot for abstract virtual methods */
2952 if (klass->methods && gklass->methods) {
2953 int mcount = mono_class_get_method_count (klass);
2954 for (i = 0; i < mcount; ++i)
2955 if (klass->methods [i]->slot == -1)
2956 klass->methods [i]->slot = gklass->methods [i]->slot;
2959 if (mono_print_vtable)
2960 print_vtable_layout_result (klass, klass->vtable, gklass->vtable_size);
2962 return;
2965 vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize);
2967 if (klass->parent && klass->parent->vtable_size) {
2968 MonoClass *parent = klass->parent;
2969 int i;
2971 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
2973 // Also inherit parent interface vtables, just as a starting point.
2974 // This is needed otherwise bug-77127.exe fails when the property methods
2975 // have different names in the iterface and the class, because for child
2976 // classes the ".override" information is not used anymore.
2977 for (i = 0; i < parent->interface_offsets_count; i++) {
2978 MonoClass *parent_interface = parent->interfaces_packed [i];
2979 int interface_offset = mono_class_interface_offset (klass, parent_interface);
2980 /*FIXME this is now dead code as this condition will never hold true.
2981 Since interface offsets are inherited then the offset of an interface implemented
2982 by a parent will never be the out of it's vtable boundary.
2984 if (interface_offset >= parent->vtable_size) {
2985 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
2986 int j;
2988 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
2989 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
2990 int mcount = mono_class_get_method_count (parent_interface);
2991 for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
2992 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
2993 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
2994 parent_interface_offset + j, parent_interface_offset, j,
2995 interface_offset + j, interface_offset, j));
3002 /*Array have a slot for stelemref*/
3003 if (mono_class_need_stelemref_method (klass)) {
3004 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
3005 if (!method->slot)
3006 method->slot = stelemref_slot;
3007 else
3008 g_assert (method->slot == stelemref_slot);
3010 vtable [stelemref_slot] = method;
3013 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
3015 /* Process overrides from interface default methods */
3016 // FIXME: Ordering between interfaces
3017 for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
3018 ic = klass->interfaces_packed [ifindex];
3020 mono_class_setup_methods (ic);
3021 if (mono_class_has_failure (ic))
3022 goto fail;
3024 MonoMethod **iface_overrides;
3025 int iface_onum;
3026 mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic), error);
3027 goto_if_nok (error, fail);
3028 for (int i = 0; i < iface_onum; i++) {
3029 MonoMethod *decl = iface_overrides [i*2];
3030 MonoMethod *override = iface_overrides [i*2 + 1];
3031 if (decl->is_inflated) {
3032 override = mono_class_inflate_generic_method_checked (override, mono_method_get_context (decl), error);
3033 mono_error_assert_ok (error);
3035 if (!apply_override (klass, ic, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3036 goto fail;
3038 g_free (iface_overrides);
3041 /* override interface methods */
3042 for (i = 0; i < onum; i++) {
3043 MonoMethod *decl = overrides [i*2];
3044 MonoMethod *override = overrides [i*2 + 1];
3045 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3046 if (!apply_override (klass, klass, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3047 goto fail;
3051 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
3052 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
3055 * Create a list of virtual methods to avoid calling
3056 * mono_class_get_virtual_methods () which is slow because of the metadata
3057 * optimization.
3060 gpointer iter = NULL;
3061 MonoMethod *cm;
3063 virt_methods = NULL;
3064 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
3065 virt_methods = g_slist_prepend (virt_methods, cm);
3067 if (mono_class_has_failure (klass))
3068 goto fail;
3071 // Loop on all implemented interfaces...
3072 for (i = 0; i < klass->interface_offsets_count; i++) {
3073 MonoClass *parent = klass->parent;
3074 int ic_offset;
3075 gboolean interface_is_explicitly_implemented_by_class;
3076 int im_index;
3078 ic = klass->interfaces_packed [i];
3079 ic_offset = mono_class_interface_offset (klass, ic);
3081 mono_class_setup_methods (ic);
3082 if (mono_class_has_failure (ic))
3083 goto fail;
3085 // Check if this interface is explicitly implemented (instead of just inherited)
3086 if (parent != NULL) {
3087 int implemented_interfaces_index;
3088 interface_is_explicitly_implemented_by_class = FALSE;
3089 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
3090 if (ic == klass->interfaces [implemented_interfaces_index]) {
3091 interface_is_explicitly_implemented_by_class = TRUE;
3092 break;
3095 } else {
3096 interface_is_explicitly_implemented_by_class = TRUE;
3099 // Loop on all interface methods...
3100 int mcount = mono_class_get_method_count (ic);
3101 for (im_index = 0; im_index < mcount; im_index++) {
3102 gboolean foundOverrideInClassOrParent = FALSE;
3103 MonoMethod *im = ic->methods [im_index];
3104 int im_slot = ic_offset + im->slot;
3105 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
3107 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3108 continue;
3110 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
3112 int cm_index;
3113 MonoMethod *cm;
3115 // First look for a suitable method among the class methods
3116 for (l = virt_methods; l; l = l->next) {
3117 cm = (MonoMethod *)l->data;
3118 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)));
3119 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
3120 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3121 vtable [im_slot] = cm;
3122 foundOverrideInClassOrParent = TRUE;
3123 /* Why do we need this? */
3124 if (cm->slot < 0) {
3125 cm->slot = im_slot;
3127 if (conflict_map)
3128 g_hash_table_remove(conflict_map, im);
3130 TRACE_INTERFACE_VTABLE (printf ("\n"));
3131 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3132 goto fail;
3135 // If the slot is still empty, look in all the inherited virtual methods...
3136 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
3137 MonoClass *parent = klass->parent;
3138 // Reverse order, so that last added methods are preferred
3139 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
3140 cm = parent->vtable [cm_index];
3142 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));
3143 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
3144 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3145 vtable [im_slot] = cm;
3146 foundOverrideInClassOrParent = TRUE;
3147 /* Why do we need this? */
3148 if (cm->slot < 0) {
3149 cm->slot = im_slot;
3151 if (conflict_map)
3152 g_hash_table_remove(conflict_map, im);
3153 break;
3155 TRACE_INTERFACE_VTABLE (printf ("\n"));
3156 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3157 goto fail;
3161 if (vtable [im_slot] == NULL) {
3162 if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
3163 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im, 1)));
3164 vtable [im_slot] = im;
3168 if (override_im != NULL && !foundOverrideInClassOrParent)
3169 g_assert (vtable [im_slot] == override_im);
3173 // If the class is not abstract, check that all its interface slots are full.
3174 // The check is done here and not directly at the end of the loop above because
3175 // it can happen (for injected generic array interfaces) that the same slot is
3176 // processed multiple times (those interfaces have overlapping slots), and it
3177 // will not always be the first pass the one that fills the slot.
3178 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
3179 if (!mono_class_is_abstract (klass)) {
3180 for (i = 0; i < klass->interface_offsets_count; i++) {
3181 int ic_offset;
3182 int im_index;
3184 ic = klass->interfaces_packed [i];
3185 ic_offset = mono_class_interface_offset (klass, ic);
3187 int mcount = mono_class_get_method_count (ic);
3188 for (im_index = 0; im_index < mcount; im_index++) {
3189 MonoMethod *im = ic->methods [im_index];
3190 int im_slot = ic_offset + im->slot;
3192 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3193 continue;
3194 if (im->is_reabstracted == 1)
3195 continue;
3197 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3198 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
3199 if (vtable [im_slot] == NULL) {
3200 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
3201 goto fail;
3207 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
3208 for (l = virt_methods; l; l = l->next) {
3209 cm = (MonoMethod *)l->data;
3211 * If the method is REUSE_SLOT, we must check in the
3212 * base class for a method to override.
3214 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3215 int slot = -1;
3216 for (k = klass->parent; k ; k = k->parent) {
3217 gpointer k_iter;
3218 MonoMethod *m1;
3220 k_iter = NULL;
3221 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
3222 MonoMethodSignature *cmsig, *m1sig;
3224 cmsig = mono_method_signature_internal (cm);
3225 m1sig = mono_method_signature_internal (m1);
3227 if (!cmsig || !m1sig) /* FIXME proper error message, use signature_checked? */
3228 goto fail;
3230 if (!strcmp(cm->name, m1->name) &&
3231 mono_metadata_signature_equal (cmsig, m1sig)) {
3233 if (mono_security_core_clr_enabled ())
3234 mono_security_core_clr_check_override (klass, cm, m1);
3236 slot = mono_method_get_vtable_slot (m1);
3237 if (slot == -1)
3238 goto fail;
3240 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
3241 char *body_name = mono_method_full_name (cm, TRUE);
3242 char *decl_name = mono_method_full_name (m1, TRUE);
3243 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3244 g_free (body_name);
3245 g_free (decl_name);
3246 goto fail;
3249 g_assert (cm->slot < max_vtsize);
3250 if (!override_map)
3251 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3252 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3253 mono_method_full_name (m1, 1), m1,
3254 mono_method_full_name (cm, 1), cm));
3255 g_hash_table_insert (override_map, m1, cm);
3256 break;
3259 if (mono_class_has_failure (k))
3260 goto fail;
3262 if (slot >= 0)
3263 break;
3265 if (slot >= 0)
3266 cm->slot = slot;
3269 /*Non final newslot methods must be given a non-interface vtable slot*/
3270 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
3271 cm->slot = -1;
3273 if (cm->slot < 0)
3274 cm->slot = cur_slot++;
3276 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
3277 vtable [cm->slot] = cm;
3280 /* override non interface methods */
3281 for (i = 0; i < onum; i++) {
3282 MonoMethod *decl = overrides [i*2];
3283 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3284 g_assert (decl->slot != -1);
3285 vtable [decl->slot] = overrides [i*2 + 1];
3286 overrides [i * 2 + 1]->slot = decl->slot;
3287 if (!override_map)
3288 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3289 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3290 mono_method_full_name (decl, 1), decl,
3291 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
3292 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
3294 if (mono_security_core_clr_enabled ())
3295 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
3300 * If a method occupies more than one place in the vtable, and it is
3301 * overriden, then change the other occurances too.
3303 if (override_map) {
3304 MonoMethod *cm;
3306 for (i = 0; i < max_vtsize; ++i)
3307 if (vtable [i]) {
3308 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
3310 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
3311 if (cm)
3312 vtable [i] = cm;
3315 g_hash_table_destroy (override_map);
3316 override_map = NULL;
3319 if (override_class_map)
3320 g_hash_table_destroy (override_class_map);
3322 if (conflict_map) {
3323 handle_dim_conflicts (vtable, klass, conflict_map);
3324 g_hash_table_destroy (conflict_map);
3327 g_slist_free (virt_methods);
3328 virt_methods = NULL;
3330 g_assert (cur_slot <= max_vtsize);
3332 /* Ensure that all vtable slots are filled with concrete instance methods */
3333 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
3334 if (!mono_class_is_abstract (klass)) {
3335 for (i = 0; i < cur_slot; ++i) {
3336 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
3337 if (vtable [i]->is_reabstracted == 1)
3338 continue;
3339 char *type_name = mono_type_get_full_name (klass);
3340 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
3341 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
3342 g_free (type_name);
3343 g_free (method_name);
3345 if (mono_print_vtable)
3346 print_vtable_layout_result (klass, vtable, cur_slot);
3348 g_free (vtable);
3349 return;
3354 if (mono_class_is_ginst (klass)) {
3355 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3357 mono_class_init_internal (gklass);
3359 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
3360 } else {
3361 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
3362 if (klass->vtable_size)
3363 g_assert (cur_slot == klass->vtable_size);
3364 klass->vtable_size = cur_slot;
3367 /* Try to share the vtable with our parent. */
3368 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
3369 mono_memory_barrier ();
3370 klass->vtable = klass->parent->vtable;
3371 } else {
3372 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
3373 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
3374 mono_memory_barrier ();
3375 klass->vtable = tmp;
3378 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
3379 if (mono_print_vtable)
3380 print_vtable_layout_result (klass, vtable, cur_slot);
3382 g_free (vtable);
3384 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
3385 return;
3387 fail:
3389 char *name = mono_type_get_full_name (klass);
3390 if (!is_ok (error))
3391 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (error));
3392 else
3393 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
3394 mono_error_cleanup (error);
3395 g_free (name);
3396 if (mono_print_vtable)
3397 print_vtable_layout_result (klass, vtable, cur_slot);
3400 g_free (vtable);
3401 if (override_map)
3402 g_hash_table_destroy (override_map);
3403 if (virt_methods)
3404 g_slist_free (virt_methods);
3408 static char*
3409 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
3411 int null_length = strlen ("(null)");
3412 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
3413 char *s = (char *)mono_image_alloc (image, len);
3414 int result;
3416 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
3417 g_assert (result == len - 1);
3419 return s;
3423 static void
3424 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
3426 if (cached_info) {
3427 mono_loader_lock ();
3428 klass->instance_size = cached_info->instance_size;
3429 klass->sizes.class_size = cached_info->class_size;
3430 klass->packing_size = cached_info->packing_size;
3431 klass->min_align = cached_info->min_align;
3432 klass->blittable = cached_info->blittable;
3433 klass->has_references = cached_info->has_references;
3434 klass->has_static_refs = cached_info->has_static_refs;
3435 klass->no_special_static_fields = cached_info->no_special_static_fields;
3436 klass->has_weak_fields = cached_info->has_weak_fields;
3437 mono_loader_unlock ();
3439 else {
3440 if (!klass->size_inited)
3441 mono_class_setup_fields (klass);
3446 * mono_class_init_sizes:
3448 * Initializes the size related fields of @klass without loading all field data if possible.
3449 * Sets the following fields in @klass:
3450 * - instance_size
3451 * - sizes.class_size
3452 * - packing_size
3453 * - min_align
3454 * - blittable
3455 * - has_references
3456 * - has_static_refs
3457 * - size_inited
3458 * Can fail the class.
3460 * LOCKING: Acquires the loader lock.
3462 void
3463 mono_class_init_sizes (MonoClass *klass)
3465 MonoCachedClassInfo cached_info;
3466 gboolean has_cached_info;
3468 if (klass->size_inited)
3469 return;
3471 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
3473 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
3477 static gboolean
3478 class_has_references (MonoClass *klass)
3480 mono_class_init_sizes (klass);
3483 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3484 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3485 * embed themselves.
3487 return klass->has_references;
3490 static gboolean
3491 type_has_references (MonoClass *klass, MonoType *ftype)
3493 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)))))
3494 return TRUE;
3495 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
3496 MonoGenericParam *gparam = ftype->data.generic_param;
3498 if (gparam->gshared_constraint)
3499 return class_has_references (mono_class_from_mono_type_internal (gparam->gshared_constraint));
3501 return FALSE;
3505 * mono_class_layout_fields:
3506 * @class: a class
3507 * @base_instance_size: base instance size
3508 * @packing_size:
3510 * This contains the common code for computing the layout of classes and sizes.
3511 * This should only be called from mono_class_setup_fields () and
3512 * typebuilder_setup_fields ().
3514 * LOCKING: Acquires the loader lock
3516 void
3517 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int explicit_size, gboolean sre)
3519 int i;
3520 const int top = mono_class_get_field_count (klass);
3521 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
3522 guint32 pass, passes, real_size;
3523 gboolean gc_aware_layout = FALSE;
3524 gboolean has_static_fields = FALSE;
3525 gboolean has_references = FALSE;
3526 gboolean has_static_refs = FALSE;
3527 MonoClassField *field;
3528 gboolean blittable;
3529 int instance_size = base_instance_size;
3530 int element_size = -1;
3531 int class_size, min_align;
3532 int *field_offsets;
3533 gboolean *fields_has_references;
3536 * We want to avoid doing complicated work inside locks, so we compute all the required
3537 * information and write it to @klass inside a lock.
3539 if (klass->fields_inited)
3540 return;
3542 if ((packing_size & 0xffffff00) != 0) {
3543 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
3544 return;
3547 if (klass->parent) {
3548 min_align = klass->parent->min_align;
3549 /* we use | since it may have been set already */
3550 has_references = klass->has_references | klass->parent->has_references;
3551 } else {
3552 min_align = 1;
3554 /* We can't really enable 16 bytes alignment until the GC supports it.
3555 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3556 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3557 Bug #506144 is an example of this issue.
3559 if (klass->simd_type)
3560 min_align = 16;
3564 * When we do generic sharing we need to have layout
3565 * information for open generic classes (either with a generic
3566 * context containing type variables or with a generic
3567 * container), so we don't return in that case anymore.
3570 if (klass->enumtype) {
3571 for (i = 0; i < top; i++) {
3572 field = &klass->fields [i];
3573 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3574 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (field->type);
3575 break;
3579 if (!mono_class_enum_basetype_internal (klass)) {
3580 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
3581 return;
3586 * Enable GC aware auto layout: in this mode, reference
3587 * fields are grouped together inside objects, increasing collector
3588 * performance.
3589 * Requires that all classes whose layout is known to native code be annotated
3590 * with [StructLayout (LayoutKind.Sequential)]
3591 * Value types have gc_aware_layout disabled by default, as per
3592 * what the default is for other runtimes.
3594 /* corlib is missing [StructLayout] directives in many places */
3595 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
3596 if (!klass->valuetype)
3597 gc_aware_layout = TRUE;
3600 /* Compute klass->blittable */
3601 blittable = TRUE;
3602 if (klass->parent)
3603 blittable = klass->parent->blittable;
3604 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
3605 blittable = FALSE;
3606 for (i = 0; i < top; i++) {
3607 field = &klass->fields [i];
3609 if (mono_field_is_deleted (field))
3610 continue;
3611 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3612 continue;
3613 if (blittable) {
3614 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
3615 blittable = FALSE;
3616 } else {
3617 MonoClass *field_class = mono_class_from_mono_type_internal (field->type);
3618 if (field_class) {
3619 mono_class_setup_fields (field_class);
3620 if (mono_class_has_failure (field_class)) {
3621 ERROR_DECL (field_error);
3622 mono_error_set_for_class_failure (field_error, field_class);
3623 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (field_error));
3624 mono_error_cleanup (field_error);
3625 break;
3628 if (!field_class || !field_class->blittable)
3629 blittable = FALSE;
3632 if (klass->enumtype)
3633 blittable = klass->element_class->blittable;
3635 if (mono_class_has_failure (klass))
3636 return;
3637 if (klass == mono_defaults.string_class)
3638 blittable = FALSE;
3640 /* Compute klass->has_references */
3642 * Process non-static fields first, since static fields might recursively
3643 * refer to the class itself.
3645 for (i = 0; i < top; i++) {
3646 MonoType *ftype;
3648 field = &klass->fields [i];
3650 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3651 ftype = mono_type_get_underlying_type (field->type);
3652 ftype = mono_type_get_basic_type_from_generic (ftype);
3653 if (type_has_references (klass, ftype))
3654 has_references = TRUE;
3659 * Compute field layout and total size (not considering static fields)
3661 field_offsets = g_new0 (int, top);
3662 fields_has_references = g_new0 (gboolean, top);
3663 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
3664 switch (layout) {
3665 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
3666 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
3667 if (gc_aware_layout)
3668 passes = 2;
3669 else
3670 passes = 1;
3672 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
3673 passes = 1;
3675 if (klass->parent) {
3676 mono_class_setup_fields (klass->parent);
3677 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
3678 return;
3679 real_size = klass->parent->instance_size;
3680 } else {
3681 real_size = MONO_ABI_SIZEOF (MonoObject);
3684 for (pass = 0; pass < passes; ++pass) {
3685 for (i = 0; i < top; i++){
3686 gint32 align;
3687 guint32 size;
3688 MonoType *ftype;
3690 field = &klass->fields [i];
3692 if (mono_field_is_deleted (field))
3693 continue;
3694 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3695 continue;
3697 ftype = mono_type_get_underlying_type (field->type);
3698 ftype = mono_type_get_basic_type_from_generic (ftype);
3699 if (gc_aware_layout) {
3700 fields_has_references [i] = type_has_references (klass, ftype);
3701 if (fields_has_references [i]) {
3702 if (pass == 1)
3703 continue;
3704 } else {
3705 if (pass == 0)
3706 continue;
3710 if ((top == 1) && (instance_size == MONO_ABI_SIZEOF (MonoObject)) &&
3711 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
3712 /* This field is a hack inserted by MCS to empty structures */
3713 continue;
3716 size = mono_type_size (field->type, &align);
3718 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3719 align = packing_size ? MIN (packing_size, align): align;
3720 /* if the field has managed references, we need to force-align it
3721 * see bug #77788
3723 if (type_has_references (klass, ftype))
3724 align = MAX (align, TARGET_SIZEOF_VOID_P);
3726 min_align = MAX (align, min_align);
3727 field_offsets [i] = real_size;
3728 if (align) {
3729 field_offsets [i] += align - 1;
3730 field_offsets [i] &= ~(align - 1);
3732 /*TypeBuilders produce all sort of weird things*/
3733 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
3734 real_size = field_offsets [i] + size;
3737 instance_size = MAX (real_size, instance_size);
3739 if (instance_size & (min_align - 1)) {
3740 instance_size += min_align - 1;
3741 instance_size &= ~(min_align - 1);
3744 break;
3745 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
3746 guint8 *ref_bitmap;
3748 real_size = 0;
3749 for (i = 0; i < top; i++) {
3750 gint32 align;
3751 guint32 size;
3752 MonoType *ftype;
3754 field = &klass->fields [i];
3757 * There must be info about all the fields in a type if it
3758 * uses explicit layout.
3760 if (mono_field_is_deleted (field))
3761 continue;
3762 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3763 continue;
3765 size = mono_type_size (field->type, &align);
3766 align = packing_size ? MIN (packing_size, align): align;
3767 min_align = MAX (align, min_align);
3769 if (sre) {
3770 /* Already set by typebuilder_setup_fields () */
3771 field_offsets [i] = field->offset + MONO_ABI_SIZEOF (MonoObject);
3772 } else {
3773 int idx = first_field_idx + i;
3774 guint32 offset;
3775 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
3776 field_offsets [i] = offset + MONO_ABI_SIZEOF (MonoObject);
3778 ftype = mono_type_get_underlying_type (field->type);
3779 ftype = mono_type_get_basic_type_from_generic (ftype);
3780 if (type_has_references (klass, ftype)) {
3781 if (field_offsets [i] % TARGET_SIZEOF_VOID_P) {
3782 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
3787 * Calc max size.
3789 real_size = MAX (real_size, size + field_offsets [i]);
3792 if (klass->has_references) {
3793 ref_bitmap = g_new0 (guint8, real_size / TARGET_SIZEOF_VOID_P);
3795 /* Check for overlapping reference and non-reference fields */
3796 for (i = 0; i < top; i++) {
3797 MonoType *ftype;
3799 field = &klass->fields [i];
3801 if (mono_field_is_deleted (field))
3802 continue;
3803 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3804 continue;
3805 ftype = mono_type_get_underlying_type (field->type);
3806 if (MONO_TYPE_IS_REFERENCE (ftype))
3807 ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P] = 1;
3809 for (i = 0; i < top; i++) {
3810 field = &klass->fields [i];
3812 if (mono_field_is_deleted (field))
3813 continue;
3814 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3815 continue;
3817 // FIXME: Too much code does this
3818 #if 0
3819 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P]) {
3820 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]);
3822 #endif
3824 g_free (ref_bitmap);
3827 instance_size = MAX (real_size, instance_size);
3828 if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) {
3829 if (instance_size & (min_align - 1)) {
3830 instance_size += min_align - 1;
3831 instance_size &= ~(min_align - 1);
3834 break;
3838 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
3840 * This leads to all kinds of problems with nested structs, so only
3841 * enable it when a MONO_DEBUG property is set.
3843 * For small structs, set min_align to at least the struct size to improve
3844 * performance, and since the JIT memset/memcpy code assumes this and generates
3845 * unaligned accesses otherwise. See #78990 for a testcase.
3847 if (mono_align_small_structs && top) {
3848 if (instance_size <= MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer))
3849 min_align = MAX (min_align, instance_size - MONO_ABI_SIZEOF (MonoObject));
3853 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3854 if (klass_byval_arg->type == MONO_TYPE_VAR || klass_byval_arg->type == MONO_TYPE_MVAR)
3855 instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_stack_size_internal (klass_byval_arg, NULL, TRUE);
3856 else if (klass_byval_arg->type == MONO_TYPE_PTR)
3857 instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
3859 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3860 element_size = mono_class_array_element_size (klass->element_class);
3862 /* Publish the data */
3863 mono_loader_lock ();
3864 if (klass->instance_size && !klass->image->dynamic) {
3865 /* Might be already set using cached info */
3866 if (klass->instance_size != instance_size) {
3867 /* Emit info to help debugging */
3868 g_print ("%s\n", mono_class_full_name (klass));
3869 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
3870 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
3871 g_print ("%d %d\n", klass->min_align, min_align);
3872 for (i = 0; i < top; ++i) {
3873 field = &klass->fields [i];
3874 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3875 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
3878 g_assert (klass->instance_size == instance_size);
3879 } else {
3880 klass->instance_size = instance_size;
3882 klass->blittable = blittable;
3883 klass->has_references = has_references;
3884 klass->packing_size = packing_size;
3885 klass->min_align = min_align;
3886 for (i = 0; i < top; ++i) {
3887 field = &klass->fields [i];
3888 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3889 klass->fields [i].offset = field_offsets [i];
3892 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3893 klass->sizes.element_size = element_size;
3895 mono_memory_barrier ();
3896 klass->size_inited = 1;
3897 mono_loader_unlock ();
3900 * Compute static field layout and size
3901 * Static fields can reference the class itself, so this has to be
3902 * done after instance_size etc. are initialized.
3904 class_size = 0;
3905 for (i = 0; i < top; i++) {
3906 gint32 align;
3907 guint32 size;
3909 field = &klass->fields [i];
3911 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3912 continue;
3913 if (mono_field_is_deleted (field))
3914 continue;
3916 if (mono_type_has_exceptions (field->type)) {
3917 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
3918 break;
3921 has_static_fields = TRUE;
3923 size = mono_type_size (field->type, &align);
3924 field_offsets [i] = class_size;
3925 /*align is always non-zero here*/
3926 field_offsets [i] += align - 1;
3927 field_offsets [i] &= ~(align - 1);
3928 class_size = field_offsets [i] + size;
3931 if (has_static_fields && class_size == 0)
3932 /* Simplify code which depends on class_size != 0 if the class has static fields */
3933 class_size = 8;
3935 /* Compute klass->has_static_refs */
3936 has_static_refs = FALSE;
3937 for (i = 0; i < top; i++) {
3938 MonoType *ftype;
3940 field = &klass->fields [i];
3942 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3943 ftype = mono_type_get_underlying_type (field->type);
3944 ftype = mono_type_get_basic_type_from_generic (ftype);
3945 if (type_has_references (klass, ftype))
3946 has_static_refs = TRUE;
3950 /*valuetypes can't be neither bigger than 1Mb or empty. */
3951 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + MONO_ABI_SIZEOF (MonoObject)))) {
3952 /* Special case compiler generated types */
3953 /* Hard to check for [CompilerGenerated] here */
3954 if (!strstr (klass->name, "StaticArrayInitTypeSize") && !strstr (klass->name, "$ArrayType"))
3955 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
3958 // Weak field support
3960 // FIXME:
3961 // - generic instances
3962 // - Disallow on structs/static fields/nonref fields
3963 gboolean has_weak_fields = FALSE;
3965 if (mono_class_has_static_metadata (klass)) {
3966 for (MonoClass *p = klass; p != NULL; p = p->parent) {
3967 gpointer iter = NULL;
3968 guint32 first_field_idx = mono_class_get_first_field_idx (p);
3970 while ((field = mono_class_get_fields_internal (p, &iter))) {
3971 guint32 field_idx = first_field_idx + (field - p->fields);
3972 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
3973 has_weak_fields = TRUE;
3974 mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
3981 * Check that any fields of IsByRefLike type are instance
3982 * fields and only inside other IsByRefLike structs.
3984 * (Has to be done late because we call
3985 * mono_class_from_mono_type_internal which may recursively
3986 * refer to the current class)
3988 gboolean allow_isbyreflike_fields = m_class_is_byreflike (klass);
3989 for (i = 0; i < top; i++) {
3990 field = &klass->fields [i];
3992 if (mono_field_is_deleted (field))
3993 continue;
3994 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
3995 continue;
3996 MonoClass *field_class = NULL;
3997 /* have to be careful not to recursively invoke mono_class_init on a static field.
3998 * for example - if the field is an array of a subclass of klass, we can loop.
4000 switch (field->type->type) {
4001 case MONO_TYPE_TYPEDBYREF:
4002 case MONO_TYPE_VALUETYPE:
4003 case MONO_TYPE_GENERICINST:
4004 field_class = mono_class_from_mono_type_internal (field->type);
4005 break;
4006 default:
4007 break;
4009 if (!field_class || !m_class_is_byreflike (field_class))
4010 continue;
4011 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
4012 mono_class_set_type_load_failure (klass, "Static ByRefLike field '%s' is not allowed", field->name);
4013 return;
4014 } else {
4015 /* instance field */
4016 if (allow_isbyreflike_fields)
4017 continue;
4018 mono_class_set_type_load_failure (klass, "Instance ByRefLike field '%s' not in a ref struct", field->name);
4019 return;
4023 /* Publish the data */
4024 mono_loader_lock ();
4025 if (!klass->rank)
4026 klass->sizes.class_size = class_size;
4027 klass->has_static_refs = has_static_refs;
4028 klass->has_weak_fields = has_weak_fields;
4029 for (i = 0; i < top; ++i) {
4030 field = &klass->fields [i];
4032 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
4033 field->offset = field_offsets [i];
4035 mono_memory_barrier ();
4036 klass->fields_inited = 1;
4037 mono_loader_unlock ();
4039 g_free (field_offsets);
4040 g_free (fields_has_references);
4043 static MonoMethod *default_ghc = NULL;
4044 static MonoMethod *default_finalize = NULL;
4045 static int finalize_slot = -1;
4046 static int ghc_slot = -1;
4048 static void
4049 initialize_object_slots (MonoClass *klass)
4051 int i;
4052 if (default_ghc)
4053 return;
4054 if (klass == mono_defaults.object_class) {
4055 mono_class_setup_vtable (klass);
4056 for (i = 0; i < klass->vtable_size; ++i) {
4057 MonoMethod *cm = klass->vtable [i];
4059 if (!strcmp (cm->name, "GetHashCode"))
4060 ghc_slot = i;
4061 else if (!strcmp (cm->name, "Finalize"))
4062 finalize_slot = i;
4065 g_assert (ghc_slot >= 0);
4066 default_ghc = klass->vtable [ghc_slot];
4068 g_assert (finalize_slot >= 0);
4069 default_finalize = klass->vtable [finalize_slot];
4074 mono_class_get_object_finalize_slot ()
4076 return finalize_slot;
4079 MonoMethod *
4080 mono_class_get_default_finalize_method ()
4082 return default_finalize;
4085 typedef struct {
4086 MonoMethod *array_method;
4087 char *name;
4088 } GenericArrayMethodInfo;
4090 static int generic_array_method_num = 0;
4091 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4093 static void
4094 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
4096 MonoGenericContext tmp_context;
4097 int i;
4099 tmp_context.class_inst = NULL;
4100 tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
4101 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4103 for (i = 0; i < generic_array_method_num; i++) {
4104 ERROR_DECL (error);
4105 MonoMethod *m = generic_array_method_info [i].array_method;
4106 MonoMethod *inflated, *helper;
4108 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, error);
4109 mono_error_assert_ok (error);
4110 helper = (MonoMethod*)g_hash_table_lookup (cache, inflated);
4111 if (!helper) {
4112 helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
4113 g_hash_table_insert (cache, inflated, helper);
4115 methods [pos ++] = helper;
4119 static int
4120 generic_array_methods (MonoClass *klass)
4122 int i, count_generic = 0, mcount;
4123 GList *list = NULL, *tmp;
4124 if (generic_array_method_num)
4125 return generic_array_method_num;
4126 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4127 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4128 mcount = mono_class_get_method_count (klass->parent);
4129 for (i = 0; i < mcount; i++) {
4130 MonoMethod *m = klass->parent->methods [i];
4131 if (!strncmp (m->name, "InternalArray__", 15)) {
4132 count_generic++;
4133 list = g_list_prepend (list, m);
4136 list = g_list_reverse (list);
4137 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4138 i = 0;
4139 for (tmp = list; tmp; tmp = tmp->next) {
4140 const char *mname, *iname;
4141 gchar *name;
4142 MonoMethod *m = (MonoMethod *)tmp->data;
4143 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4144 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4146 generic_array_method_info [i].array_method = m;
4147 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4148 iname = "System.Collections.Generic.ICollection`1.";
4149 mname = m->name + 27;
4150 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4151 iname = "System.Collections.Generic.IEnumerable`1.";
4152 mname = m->name + 27;
4153 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4154 iname = "System.Collections.Generic.IReadOnlyList`1.";
4155 mname = m->name + strlen (ireadonlylist_prefix);
4156 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4157 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4158 mname = m->name + strlen (ireadonlycollection_prefix);
4159 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4160 iname = "System.Collections.Generic.IList`1.";
4161 mname = m->name + 15;
4162 } else {
4163 g_assert_not_reached ();
4166 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4167 strcpy (name, iname);
4168 strcpy (name + strlen (iname), mname);
4169 generic_array_method_info [i].name = name;
4170 i++;
4172 /*g_print ("array generic methods: %d\n", count_generic);*/
4174 generic_array_method_num = count_generic;
4175 g_list_free (list);
4176 return generic_array_method_num;
4180 * Global pool of interface IDs, represented as a bitset.
4181 * LOCKING: Protected by the classes lock.
4183 static MonoBitSet *global_interface_bitset = NULL;
4186 * mono_unload_interface_ids:
4187 * @bitset: bit set of interface IDs
4189 * When an image is unloaded, the interface IDs associated with
4190 * the image are put back in the global pool of IDs so the numbers
4191 * can be reused.
4193 void
4194 mono_unload_interface_ids (MonoBitSet *bitset)
4196 classes_lock ();
4197 mono_bitset_sub (global_interface_bitset, bitset);
4198 classes_unlock ();
4201 void
4202 mono_unload_interface_id (MonoClass *klass)
4204 if (global_interface_bitset && klass->interface_id) {
4205 classes_lock ();
4206 mono_bitset_clear (global_interface_bitset, klass->interface_id);
4207 classes_unlock ();
4212 * mono_get_unique_iid:
4213 * \param klass interface
4215 * Assign a unique integer ID to the interface represented by \p klass.
4216 * The ID will positive and as small as possible.
4217 * LOCKING: Acquires the classes lock.
4218 * \returns The new ID.
4220 static guint32
4221 mono_get_unique_iid (MonoClass *klass)
4223 int iid;
4225 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
4227 classes_lock ();
4229 if (!global_interface_bitset) {
4230 global_interface_bitset = mono_bitset_new (128, 0);
4231 mono_bitset_set (global_interface_bitset, 0); //don't let 0 be a valid iid
4234 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
4235 if (iid < 0) {
4236 int old_size = mono_bitset_size (global_interface_bitset);
4237 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
4238 mono_bitset_free (global_interface_bitset);
4239 global_interface_bitset = new_set;
4240 iid = old_size;
4242 mono_bitset_set (global_interface_bitset, iid);
4243 /* set the bit also in the per-image set */
4244 if (!mono_class_is_ginst (klass)) {
4245 if (klass->image->interface_bitset) {
4246 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
4247 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
4248 mono_bitset_free (klass->image->interface_bitset);
4249 klass->image->interface_bitset = new_set;
4251 } else {
4252 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
4254 mono_bitset_set (klass->image->interface_bitset, iid);
4257 classes_unlock ();
4259 #ifndef MONO_SMALL_CONFIG
4260 if (mono_print_vtable) {
4261 int generic_id;
4262 char *type_name = mono_type_full_name (m_class_get_byval_arg (klass));
4263 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
4264 if (gklass && !gklass->context.class_inst->is_open) {
4265 generic_id = gklass->context.class_inst->id;
4266 g_assert (generic_id != 0);
4267 } else {
4268 generic_id = 0;
4270 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->assembly_name, type_name, generic_id);
4271 g_free (type_name);
4273 #endif
4275 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4276 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4277 g_assert (iid < INT_MAX);
4278 return iid;
4282 * mono_class_init_internal:
4283 * \param klass the class to initialize
4285 * Compute the \c instance_size, \c class_size and other infos that cannot be
4286 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4287 * Initializes the following fields in \p klass:
4288 * - all the fields initialized by \c mono_class_init_sizes
4289 * - has_cctor
4290 * - ghcimpl
4291 * - inited
4293 * LOCKING: Acquires the loader lock.
4295 * \returns TRUE on success or FALSE if there was a problem in loading
4296 * the type (incorrect assemblies, missing assemblies, methods, etc).
4298 gboolean
4299 mono_class_init_internal (MonoClass *klass)
4301 int i, vtable_size = 0, array_method_count = 0;
4302 MonoCachedClassInfo cached_info;
4303 gboolean has_cached_info;
4304 gboolean locked = FALSE;
4305 gboolean ghcimpl = FALSE;
4306 gboolean has_cctor = FALSE;
4307 int first_iface_slot = 0;
4309 g_assert (klass);
4311 /* Double-checking locking pattern */
4312 if (klass->inited || mono_class_has_failure (klass))
4313 return !mono_class_has_failure (klass);
4315 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4318 * This function can recursively call itself.
4320 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
4321 if (g_slist_find (init_list, klass)) {
4322 mono_class_set_type_load_failure (klass, "Recursive type definition detected %s.%s", klass->name_space, klass->name);
4323 goto leave_no_init_pending;
4325 init_list = g_slist_prepend (init_list, klass);
4326 mono_native_tls_set_value (init_pending_tls_id, init_list);
4329 * We want to avoid doing complicated work inside locks, so we compute all the required
4330 * information and write it to @klass inside a lock.
4333 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
4334 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
4335 goto leave;
4338 MonoType *klass_byval_arg;
4339 klass_byval_arg = m_class_get_byval_arg (klass);
4340 if (klass_byval_arg->type == MONO_TYPE_ARRAY || klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4341 MonoClass *element_class = klass->element_class;
4342 MonoClass *cast_class = klass->cast_class;
4344 if (!element_class->inited)
4345 mono_class_init_internal (element_class);
4346 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
4347 goto leave;
4348 if (!cast_class->inited)
4349 mono_class_init_internal (cast_class);
4350 if (mono_class_set_type_load_failure_causedby_class (klass, cast_class, "Could not load array cast class"))
4351 goto leave;
4354 UnlockedIncrement (&mono_stats.initialized_class_count);
4356 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
4357 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4359 mono_class_init_internal (gklass);
4360 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
4361 goto leave;
4363 mono_loader_lock ();
4364 mono_class_setup_interface_id_internal (klass);
4365 mono_loader_unlock ();
4368 if (klass->parent && !klass->parent->inited)
4369 mono_class_init_internal (klass->parent);
4371 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
4373 /* Compute instance size etc. */
4374 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
4375 if (mono_class_has_failure (klass))
4376 goto leave;
4378 mono_class_setup_supertypes (klass);
4380 if (!default_ghc)
4381 initialize_object_slots (klass);
4384 * Initialize the rest of the data without creating a generic vtable if possible.
4385 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4386 * also avoid computing a generic vtable.
4388 if (has_cached_info) {
4389 /* AOT case */
4390 vtable_size = cached_info.vtable_size;
4391 ghcimpl = cached_info.ghcimpl;
4392 has_cctor = cached_info.has_cctor;
4393 } else if (klass->rank == 1 && klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4394 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4395 * The first slot if for array with.
4397 static int szarray_vtable_size[3] = { 0 };
4399 int slot;
4401 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass))))
4402 slot = 0;
4403 else if (klass->element_class->enumtype)
4404 slot = 1;
4405 else
4406 slot = 2;
4408 /* SZARRAY case */
4409 if (!szarray_vtable_size [slot]) {
4410 mono_class_setup_vtable (klass);
4411 szarray_vtable_size [slot] = klass->vtable_size;
4412 vtable_size = klass->vtable_size;
4413 } else {
4414 vtable_size = szarray_vtable_size[slot];
4416 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4417 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4419 /* Generic instance case */
4420 ghcimpl = gklass->ghcimpl;
4421 has_cctor = gklass->has_cctor;
4423 mono_class_setup_vtable (gklass);
4424 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
4425 goto leave;
4427 vtable_size = gklass->vtable_size;
4428 } else {
4429 /* General case */
4431 /* ghcimpl is not currently used
4432 klass->ghcimpl = 1;
4433 if (klass->parent) {
4434 MonoMethod *cmethod = klass->vtable [ghc_slot];
4435 if (cmethod->is_inflated)
4436 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
4437 if (cmethod == default_ghc) {
4438 klass->ghcimpl = 0;
4443 /* C# doesn't allow interfaces to have cctors */
4444 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->image != mono_defaults.corlib) {
4445 MonoMethod *cmethod = NULL;
4447 if (mono_class_is_ginst (klass)) {
4448 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4450 /* Generic instance case */
4451 ghcimpl = gklass->ghcimpl;
4452 has_cctor = gklass->has_cctor;
4453 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
4454 cmethod = mono_find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
4455 /* The find_method function ignores the 'flags' argument */
4456 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
4457 has_cctor = 1;
4458 } else {
4459 mono_class_setup_methods (klass);
4460 if (mono_class_has_failure (klass))
4461 goto leave;
4463 int mcount = mono_class_get_method_count (klass);
4464 for (i = 0; i < mcount; ++i) {
4465 MonoMethod *method = klass->methods [i];
4466 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
4467 (strcmp (".cctor", method->name) == 0)) {
4468 has_cctor = 1;
4469 break;
4476 if (klass->rank) {
4477 array_method_count = 3 + (klass->rank > 1? 2: 1);
4479 if (klass->interface_count) {
4480 int count_generic = generic_array_methods (klass);
4481 array_method_count += klass->interface_count * count_generic;
4485 if (klass->parent) {
4486 if (!klass->parent->vtable_size)
4487 mono_class_setup_vtable (klass->parent);
4488 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
4489 goto leave;
4490 g_assert (klass->parent->vtable_size);
4491 first_iface_slot = klass->parent->vtable_size;
4492 if (mono_class_need_stelemref_method (klass))
4493 ++first_iface_slot;
4497 * Do the actual changes to @klass inside the loader lock
4499 mono_loader_lock ();
4500 locked = TRUE;
4502 if (klass->inited || mono_class_has_failure (klass)) {
4503 mono_loader_unlock ();
4504 /* Somebody might have gotten in before us */
4505 return !mono_class_has_failure (klass);
4508 UnlockedIncrement (&mono_stats.initialized_class_count);
4510 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
4511 UnlockedIncrement (&mono_stats.generic_class_count);
4513 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
4514 klass->nested_classes_inited = TRUE;
4515 klass->ghcimpl = ghcimpl;
4516 klass->has_cctor = has_cctor;
4517 if (vtable_size)
4518 klass->vtable_size = vtable_size;
4519 if (has_cached_info) {
4520 klass->has_finalize = cached_info.has_finalize;
4521 klass->has_finalize_inited = TRUE;
4523 if (klass->rank)
4524 mono_class_set_method_count (klass, array_method_count);
4526 mono_loader_unlock ();
4527 locked = FALSE;
4529 setup_interface_offsets (klass, first_iface_slot, TRUE);
4531 if (mono_security_core_clr_enabled ())
4532 mono_security_core_clr_check_inheritance (klass);
4534 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
4535 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
4537 goto leave;
4539 leave:
4540 init_list = (GSList*)mono_native_tls_get_value (init_pending_tls_id);
4541 init_list = g_slist_remove (init_list, klass);
4542 mono_native_tls_set_value (init_pending_tls_id, init_list);
4544 leave_no_init_pending:
4545 if (locked)
4546 mono_loader_unlock ();
4548 /* Leave this for last */
4549 mono_loader_lock ();
4550 klass->inited = 1;
4551 mono_loader_unlock ();
4553 return !mono_class_has_failure (klass);
4556 gboolean
4557 mono_class_init_checked (MonoClass *klass, MonoError *error)
4559 error_init (error);
4560 gboolean const success = mono_class_init_internal (klass);
4561 if (!success)
4562 mono_error_set_for_class_failure (error, klass);
4563 return success;
4566 #ifndef DISABLE_COM
4568 * COM initialization is delayed until needed.
4569 * However when a [ComImport] attribute is present on a type it will trigger
4570 * the initialization. This is not a problem unless the BCL being executed
4571 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4573 static void
4574 init_com_from_comimport (MonoClass *klass)
4576 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4577 if (mono_security_core_clr_enabled ()) {
4578 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4579 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
4580 /* but it can not be made available for application (i.e. user code) since all COM calls
4581 * are considered native calls. In this case we fail with a TypeLoadException (just like
4582 * Silverlight 2 does */
4583 mono_class_set_type_load_failure (klass, "");
4584 return;
4588 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4590 #endif /*DISABLE_COM*/
4593 * LOCKING: this assumes the loader lock is held
4595 void
4596 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
4598 gboolean system_namespace;
4599 gboolean is_corlib = mono_is_corlib_image (klass->image);
4601 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
4603 /* if root of the hierarchy */
4604 if (system_namespace && !strcmp (klass->name, "Object")) {
4605 klass->parent = NULL;
4606 klass->instance_size = MONO_ABI_SIZEOF (MonoObject);
4607 return;
4609 if (!strcmp (klass->name, "<Module>")) {
4610 klass->parent = NULL;
4611 klass->instance_size = 0;
4612 return;
4615 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4616 /* Imported COM Objects always derive from __ComObject. */
4617 #ifndef DISABLE_COM
4618 if (MONO_CLASS_IS_IMPORT (klass)) {
4619 init_com_from_comimport (klass);
4620 if (parent == mono_defaults.object_class)
4621 parent = mono_class_get_com_object_class ();
4623 #endif
4624 if (!parent) {
4625 /* set the parent to something useful and safe, but mark the type as broken */
4626 parent = mono_defaults.object_class;
4627 mono_class_set_type_load_failure (klass, "");
4628 g_assert (parent);
4631 klass->parent = parent;
4633 if (mono_class_is_ginst (parent) && !parent->name) {
4635 * If the parent is a generic instance, we may get
4636 * called before it is fully initialized, especially
4637 * before it has its name.
4639 return;
4642 #ifndef DISABLE_REMOTING
4643 klass->marshalbyref = parent->marshalbyref;
4644 klass->contextbound = parent->contextbound;
4645 #endif
4647 klass->delegate = parent->delegate;
4649 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
4650 mono_class_set_is_com_object (klass);
4652 if (system_namespace) {
4653 #ifndef DISABLE_REMOTING
4654 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
4655 klass->marshalbyref = 1;
4657 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
4658 klass->contextbound = 1;
4659 #endif
4660 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
4661 klass->delegate = 1;
4664 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
4665 (strcmp (klass->parent->name_space, "System") == 0)))
4666 klass->valuetype = 1;
4667 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
4668 klass->valuetype = klass->enumtype = 1;
4670 /*klass->enumtype = klass->parent->enumtype; */
4671 } else {
4672 /* initialize com types if COM interfaces are present */
4673 #ifndef DISABLE_COM
4674 if (MONO_CLASS_IS_IMPORT (klass))
4675 init_com_from_comimport (klass);
4676 #endif
4677 klass->parent = NULL;
4682 /* Locking: must be called with the loader lock held. */
4683 static void
4684 mono_class_setup_interface_id_internal (MonoClass *klass)
4686 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->interface_id)
4687 return;
4688 klass->interface_id = mono_get_unique_iid (klass);
4690 if (mono_is_corlib_image (klass->image) && !strcmp (m_class_get_name_space (klass), "System.Collections.Generic")) {
4691 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4692 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4693 * MS returns diferrent types based on which instance is called. For example:
4694 * object obj = new byte[10][];
4695 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4696 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4697 * a != b ==> true
4699 const char *name = m_class_get_name (klass);
4700 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
4701 klass->is_array_special_interface = 1;
4707 * LOCKING: this assumes the loader lock is held
4709 void
4710 mono_class_setup_mono_type (MonoClass *klass)
4712 const char *name = klass->name;
4713 const char *nspace = klass->name_space;
4714 gboolean is_corlib = mono_is_corlib_image (klass->image);
4716 klass->this_arg.byref = 1;
4717 klass->this_arg.data.klass = klass;
4718 klass->this_arg.type = MONO_TYPE_CLASS;
4719 klass->_byval_arg.data.klass = klass;
4720 klass->_byval_arg.type = MONO_TYPE_CLASS;
4722 if (is_corlib && !strcmp (nspace, "System")) {
4723 if (!strcmp (name, "ValueType")) {
4725 * do not set the valuetype bit for System.ValueType.
4726 * klass->valuetype = 1;
4728 klass->blittable = TRUE;
4729 } else if (!strcmp (name, "Enum")) {
4731 * do not set the valuetype bit for System.Enum.
4732 * klass->valuetype = 1;
4734 klass->valuetype = 0;
4735 klass->enumtype = 0;
4736 } else if (!strcmp (name, "Object")) {
4737 klass->_byval_arg.type = MONO_TYPE_OBJECT;
4738 klass->this_arg.type = MONO_TYPE_OBJECT;
4739 } else if (!strcmp (name, "String")) {
4740 klass->_byval_arg.type = MONO_TYPE_STRING;
4741 klass->this_arg.type = MONO_TYPE_STRING;
4742 } else if (!strcmp (name, "TypedReference")) {
4743 klass->_byval_arg.type = MONO_TYPE_TYPEDBYREF;
4744 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
4748 if (klass->valuetype) {
4749 int t = MONO_TYPE_VALUETYPE;
4751 if (is_corlib && !strcmp (nspace, "System")) {
4752 switch (*name) {
4753 case 'B':
4754 if (!strcmp (name, "Boolean")) {
4755 t = MONO_TYPE_BOOLEAN;
4756 } else if (!strcmp(name, "Byte")) {
4757 t = MONO_TYPE_U1;
4758 klass->blittable = TRUE;
4760 break;
4761 case 'C':
4762 if (!strcmp (name, "Char")) {
4763 t = MONO_TYPE_CHAR;
4765 break;
4766 case 'D':
4767 if (!strcmp (name, "Double")) {
4768 t = MONO_TYPE_R8;
4769 klass->blittable = TRUE;
4771 break;
4772 case 'I':
4773 if (!strcmp (name, "Int32")) {
4774 t = MONO_TYPE_I4;
4775 klass->blittable = TRUE;
4776 } else if (!strcmp(name, "Int16")) {
4777 t = MONO_TYPE_I2;
4778 klass->blittable = TRUE;
4779 } else if (!strcmp(name, "Int64")) {
4780 t = MONO_TYPE_I8;
4781 klass->blittable = TRUE;
4782 } else if (!strcmp(name, "IntPtr")) {
4783 t = MONO_TYPE_I;
4784 klass->blittable = TRUE;
4786 break;
4787 case 'S':
4788 if (!strcmp (name, "Single")) {
4789 t = MONO_TYPE_R4;
4790 klass->blittable = TRUE;
4791 } else if (!strcmp(name, "SByte")) {
4792 t = MONO_TYPE_I1;
4793 klass->blittable = TRUE;
4795 break;
4796 case 'U':
4797 if (!strcmp (name, "UInt32")) {
4798 t = MONO_TYPE_U4;
4799 klass->blittable = TRUE;
4800 } else if (!strcmp(name, "UInt16")) {
4801 t = MONO_TYPE_U2;
4802 klass->blittable = TRUE;
4803 } else if (!strcmp(name, "UInt64")) {
4804 t = MONO_TYPE_U8;
4805 klass->blittable = TRUE;
4806 } else if (!strcmp(name, "UIntPtr")) {
4807 t = MONO_TYPE_U;
4808 klass->blittable = TRUE;
4810 break;
4811 case 'T':
4812 if (!strcmp (name, "TypedReference")) {
4813 t = MONO_TYPE_TYPEDBYREF;
4814 klass->blittable = TRUE;
4816 break;
4817 case 'V':
4818 if (!strcmp (name, "Void")) {
4819 t = MONO_TYPE_VOID;
4821 break;
4822 default:
4823 break;
4826 klass->_byval_arg.type = (MonoTypeEnum)t;
4827 klass->this_arg.type = (MonoTypeEnum)t;
4830 mono_class_setup_interface_id_internal (klass);
4833 static MonoMethod*
4834 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
4836 MonoMethod *method;
4838 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
4839 method->klass = klass;
4840 method->flags = METHOD_ATTRIBUTE_PUBLIC;
4841 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
4842 method->signature = sig;
4843 method->name = name;
4844 method->slot = -1;
4845 /* .ctor */
4846 if (name [0] == '.') {
4847 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
4848 } else {
4849 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
4851 return method;
4855 * mono_class_setup_methods:
4856 * @class: a class
4858 * Initializes the 'methods' array in CLASS.
4859 * Calling this method should be avoided if possible since it allocates a lot
4860 * of long-living MonoMethod structures.
4861 * Methods belonging to an interface are assigned a sequential slot starting
4862 * from 0.
4864 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4866 void
4867 mono_class_setup_methods (MonoClass *klass)
4869 int i, count;
4870 MonoMethod **methods;
4872 if (klass->methods)
4873 return;
4875 if (mono_class_is_ginst (klass)) {
4876 ERROR_DECL (error);
4877 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4879 mono_class_init_internal (gklass);
4880 if (!mono_class_has_failure (gklass))
4881 mono_class_setup_methods (gklass);
4882 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
4883 return;
4885 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4886 count = mono_class_get_method_count (gklass);
4887 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
4889 for (i = 0; i < count; i++) {
4890 methods [i] = mono_class_inflate_generic_method_full_checked (
4891 gklass->methods [i], klass, mono_class_get_context (klass), error);
4892 if (!mono_error_ok (error)) {
4893 char *method = mono_method_full_name (gklass->methods [i], TRUE);
4894 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (error));
4896 g_free (method);
4897 mono_error_cleanup (error);
4898 return;
4901 } else if (klass->rank) {
4902 ERROR_DECL (error);
4903 MonoMethod *amethod;
4904 MonoMethodSignature *sig;
4905 int count_generic = 0, first_generic = 0;
4906 int method_num = 0;
4907 gboolean jagged_ctor = FALSE;
4909 count = 3 + (klass->rank > 1? 2: 1);
4911 mono_class_setup_interfaces (klass, error);
4912 g_assert (mono_error_ok (error)); /*FIXME can this fail for array types?*/
4914 if (klass->rank == 1 && klass->element_class->rank) {
4915 jagged_ctor = TRUE;
4916 count ++;
4919 if (klass->interface_count) {
4920 count_generic = generic_array_methods (klass);
4921 first_generic = count;
4922 count += klass->interface_count * count_generic;
4925 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
4927 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4928 sig->ret = mono_get_void_type ();
4929 sig->pinvoke = TRUE;
4930 sig->hasthis = TRUE;
4931 for (i = 0; i < klass->rank; ++i)
4932 sig->params [i] = mono_get_int32_type ();
4934 amethod = create_array_method (klass, ".ctor", sig);
4935 methods [method_num++] = amethod;
4936 if (klass->rank > 1) {
4937 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
4938 sig->ret = mono_get_void_type ();
4939 sig->pinvoke = TRUE;
4940 sig->hasthis = TRUE;
4941 for (i = 0; i < klass->rank * 2; ++i)
4942 sig->params [i] = mono_get_int32_type ();
4944 amethod = create_array_method (klass, ".ctor", sig);
4945 methods [method_num++] = amethod;
4948 if (jagged_ctor) {
4949 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4950 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4951 sig->ret = mono_get_void_type ();
4952 sig->pinvoke = TRUE;
4953 sig->hasthis = TRUE;
4954 for (i = 0; i < klass->rank + 1; ++i)
4955 sig->params [i] = mono_get_int32_type ();
4956 amethod = create_array_method (klass, ".ctor", sig);
4957 methods [method_num++] = amethod;
4960 /* element Get (idx11, [idx2, ...]) */
4961 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4962 sig->ret = m_class_get_byval_arg (m_class_get_element_class (klass));
4963 sig->pinvoke = TRUE;
4964 sig->hasthis = TRUE;
4965 for (i = 0; i < klass->rank; ++i)
4966 sig->params [i] = mono_get_int32_type ();
4967 amethod = create_array_method (klass, "Get", sig);
4968 methods [method_num++] = amethod;
4969 /* element& Address (idx11, [idx2, ...]) */
4970 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4971 sig->ret = &klass->element_class->this_arg;
4972 sig->pinvoke = TRUE;
4973 sig->hasthis = TRUE;
4974 for (i = 0; i < klass->rank; ++i)
4975 sig->params [i] = mono_get_int32_type ();
4976 amethod = create_array_method (klass, "Address", sig);
4977 methods [method_num++] = amethod;
4978 /* void Set (idx11, [idx2, ...], element) */
4979 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4980 sig->ret = mono_get_void_type ();
4981 sig->pinvoke = TRUE;
4982 sig->hasthis = TRUE;
4983 for (i = 0; i < klass->rank; ++i)
4984 sig->params [i] = mono_get_int32_type ();
4985 sig->params [i] = m_class_get_byval_arg (m_class_get_element_class (klass));
4986 amethod = create_array_method (klass, "Set", sig);
4987 methods [method_num++] = amethod;
4989 GHashTable *cache = g_hash_table_new (NULL, NULL);
4990 for (i = 0; i < klass->interface_count; i++)
4991 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
4992 g_hash_table_destroy (cache);
4993 } else if (mono_class_has_static_metadata (klass)) {
4994 ERROR_DECL (error);
4995 int first_idx = mono_class_get_first_method_idx (klass);
4997 count = mono_class_get_method_count (klass);
4998 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
4999 for (i = 0; i < count; ++i) {
5000 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
5001 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, error);
5002 if (!methods [i]) {
5003 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (error));
5004 mono_error_cleanup (error);
5007 } else {
5008 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
5009 count = 0;
5012 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
5013 int slot = 0;
5014 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
5015 for (i = 0; i < count; ++i) {
5016 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
5018 if (method_is_reabstracted (methods[i]->flags)) {
5019 methods [i]->is_reabstracted = 1;
5020 continue;
5022 methods [i]->slot = slot++;
5027 mono_image_lock (klass->image);
5029 if (!klass->methods) {
5030 mono_class_set_method_count (klass, count);
5032 /* Needed because of the double-checking locking pattern */
5033 mono_memory_barrier ();
5035 klass->methods = methods;
5038 mono_image_unlock (klass->image);
5042 * mono_class_setup_properties:
5044 * Initialize klass->ext.property and klass->ext.properties.
5046 * This method can fail the class.
5048 void
5049 mono_class_setup_properties (MonoClass *klass)
5051 guint startm, endm, i, j;
5052 guint32 cols [MONO_PROPERTY_SIZE];
5053 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5054 MonoProperty *properties;
5055 guint32 last;
5056 int first, count;
5057 MonoClassPropertyInfo *info;
5059 info = mono_class_get_property_info (klass);
5060 if (info)
5061 return;
5063 if (mono_class_is_ginst (klass)) {
5064 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5066 mono_class_init_internal (gklass);
5067 mono_class_setup_properties (gklass);
5068 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5069 return;
5071 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
5072 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
5074 for (i = 0; i < ginfo->count; i++) {
5075 ERROR_DECL (error);
5076 MonoProperty *prop = &properties [i];
5078 *prop = ginfo->properties [i];
5080 if (prop->get)
5081 prop->get = mono_class_inflate_generic_method_full_checked (
5082 prop->get, klass, mono_class_get_context (klass), error);
5083 if (prop->set)
5084 prop->set = mono_class_inflate_generic_method_full_checked (
5085 prop->set, klass, mono_class_get_context (klass), error);
5087 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5088 prop->parent = klass;
5091 first = ginfo->first;
5092 count = ginfo->count;
5093 } else {
5094 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5095 count = last - first;
5097 if (count) {
5098 mono_class_setup_methods (klass);
5099 if (mono_class_has_failure (klass))
5100 return;
5103 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
5104 for (i = first; i < last; ++i) {
5105 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
5106 properties [i - first].parent = klass;
5107 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
5108 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
5110 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
5111 int first_idx = mono_class_get_first_method_idx (klass);
5112 for (j = startm; j < endm; ++j) {
5113 MonoMethod *method;
5115 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5117 if (klass->image->uncompressed_metadata) {
5118 ERROR_DECL (error);
5119 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5120 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5121 mono_error_cleanup (error); /* FIXME don't swallow this error */
5122 } else {
5123 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5126 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5127 case METHOD_SEMANTIC_SETTER:
5128 properties [i - first].set = method;
5129 break;
5130 case METHOD_SEMANTIC_GETTER:
5131 properties [i - first].get = method;
5132 break;
5133 default:
5134 break;
5140 info = (MonoClassPropertyInfo*)mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
5141 info->first = first;
5142 info->count = count;
5143 info->properties = properties;
5144 mono_memory_barrier ();
5146 /* This might leak 'info' which was allocated from the image mempool */
5147 mono_class_set_property_info (klass, info);
5150 static MonoMethod**
5151 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
5153 MonoMethod **om, **retval;
5154 int count;
5156 for (om = methods, count = 0; *om; ++om, ++count)
5159 retval = g_new0 (MonoMethod*, count + 1);
5160 count = 0;
5161 for (om = methods, count = 0; *om; ++om, ++count) {
5162 ERROR_DECL (error);
5163 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, error);
5164 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5167 return retval;
5170 /*This method can fail the class.*/
5171 void
5172 mono_class_setup_events (MonoClass *klass)
5174 int first, count;
5175 guint startm, endm, i, j;
5176 guint32 cols [MONO_EVENT_SIZE];
5177 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5178 guint32 last;
5179 MonoEvent *events;
5181 MonoClassEventInfo *info = mono_class_get_event_info (klass);
5182 if (info)
5183 return;
5185 if (mono_class_is_ginst (klass)) {
5186 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5187 MonoGenericContext *context = NULL;
5189 mono_class_setup_events (gklass);
5190 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5191 return;
5193 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
5194 first = ginfo->first;
5195 count = ginfo->count;
5197 events = mono_class_new0 (klass, MonoEvent, count);
5199 if (count)
5200 context = mono_class_get_context (klass);
5202 for (i = 0; i < count; i++) {
5203 ERROR_DECL (error);
5204 MonoEvent *event = &events [i];
5205 MonoEvent *gevent = &ginfo->events [i];
5207 error_init (error); //since we do conditional calls, we must ensure the default value is ok
5209 event->parent = klass;
5210 event->name = gevent->name;
5211 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, error) : NULL;
5212 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5213 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, error) : NULL;
5214 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5215 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, error) : NULL;
5216 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5218 #ifndef MONO_SMALL_CONFIG
5219 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
5220 #endif
5221 event->attrs = gevent->attrs;
5223 } else {
5224 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5225 count = last - first;
5227 if (count) {
5228 mono_class_setup_methods (klass);
5229 if (mono_class_has_failure (klass)) {
5230 return;
5234 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
5235 for (i = first; i < last; ++i) {
5236 MonoEvent *event = &events [i - first];
5238 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
5239 event->parent = klass;
5240 event->attrs = cols [MONO_EVENT_FLAGS];
5241 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
5243 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
5244 int first_idx = mono_class_get_first_method_idx (klass);
5245 for (j = startm; j < endm; ++j) {
5246 MonoMethod *method;
5248 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5250 if (klass->image->uncompressed_metadata) {
5251 ERROR_DECL (error);
5252 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5253 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5254 mono_error_cleanup (error); /* FIXME don't swallow this error */
5255 } else {
5256 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5259 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5260 case METHOD_SEMANTIC_ADD_ON:
5261 event->add = method;
5262 break;
5263 case METHOD_SEMANTIC_REMOVE_ON:
5264 event->remove = method;
5265 break;
5266 case METHOD_SEMANTIC_FIRE:
5267 event->raise = method;
5268 break;
5269 case METHOD_SEMANTIC_OTHER: {
5270 #ifndef MONO_SMALL_CONFIG
5271 int n = 0;
5273 if (event->other == NULL) {
5274 event->other = g_new0 (MonoMethod*, 2);
5275 } else {
5276 while (event->other [n])
5277 n++;
5278 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
5280 event->other [n] = method;
5281 /* NULL terminated */
5282 event->other [n + 1] = NULL;
5283 #endif
5284 break;
5286 default:
5287 break;
5293 info = (MonoClassEventInfo*)mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
5294 info->events = events;
5295 info->first = first;
5296 info->count = count;
5298 mono_memory_barrier ();
5300 mono_class_set_event_info (klass, info);
5305 * mono_class_setup_interface_id:
5307 * Initializes MonoClass::interface_id if required.
5309 * LOCKING: Acquires the loader lock.
5311 void
5312 mono_class_setup_interface_id (MonoClass *klass)
5314 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
5315 mono_loader_lock ();
5316 mono_class_setup_interface_id_internal (klass);
5317 mono_loader_unlock ();
5321 * mono_class_setup_interfaces:
5323 * Initialize klass->interfaces/interfaces_count.
5324 * LOCKING: Acquires the loader lock.
5325 * This function can fail the type.
5327 void
5328 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
5330 int i, interface_count;
5331 MonoClass **interfaces;
5333 error_init (error);
5335 if (klass->interfaces_inited)
5336 return;
5338 if (klass->rank == 1 && m_class_get_byval_arg (klass)->type != MONO_TYPE_ARRAY) {
5339 MonoType *args [1];
5341 /* IList and IReadOnlyList -> 2x if enum*/
5342 interface_count = klass->element_class->enumtype ? 4 : 2;
5343 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
5345 args [0] = m_class_get_byval_arg (m_class_get_element_class (klass));
5346 interfaces [0] = mono_class_bind_generic_parameters (
5347 mono_defaults.generic_ilist_class, 1, args, FALSE);
5348 interfaces [1] = mono_class_bind_generic_parameters (
5349 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5350 if (klass->element_class->enumtype) {
5351 args [0] = mono_class_enum_basetype_internal (klass->element_class);
5352 interfaces [2] = mono_class_bind_generic_parameters (
5353 mono_defaults.generic_ilist_class, 1, args, FALSE);
5354 interfaces [3] = mono_class_bind_generic_parameters (
5355 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5357 } else if (mono_class_is_ginst (klass)) {
5358 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5360 mono_class_setup_interfaces (gklass, error);
5361 if (!mono_error_ok (error)) {
5362 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5363 return;
5366 interface_count = gklass->interface_count;
5367 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
5368 for (i = 0; i < interface_count; i++) {
5369 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
5370 if (!mono_error_ok (error)) {
5371 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5372 return;
5375 } else {
5376 interface_count = 0;
5377 interfaces = NULL;
5380 mono_loader_lock ();
5381 if (!klass->interfaces_inited) {
5382 klass->interface_count = interface_count;
5383 klass->interfaces = interfaces;
5385 mono_memory_barrier ();
5387 klass->interfaces_inited = TRUE;
5389 mono_loader_unlock ();
5394 * mono_class_setup_has_finalizer:
5396 * Initialize klass->has_finalizer if it isn't already initialized.
5398 * LOCKING: Acquires the loader lock.
5400 void
5401 mono_class_setup_has_finalizer (MonoClass *klass)
5403 gboolean has_finalize = FALSE;
5405 if (m_class_is_has_finalize_inited (klass))
5406 return;
5408 /* Interfaces and valuetypes are not supposed to have finalizers */
5409 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_is_valuetype (klass))) {
5410 MonoMethod *cmethod = NULL;
5412 if (m_class_get_rank (klass) == 1 && m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
5413 } else if (mono_class_is_ginst (klass)) {
5414 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5416 has_finalize = mono_class_has_finalizer (gklass);
5417 } else if (m_class_get_parent (klass) && m_class_has_finalize (m_class_get_parent (klass))) {
5418 has_finalize = TRUE;
5419 } else {
5420 if (m_class_get_parent (klass)) {
5422 * Can't search in metadata for a method named Finalize, because that
5423 * ignores overrides.
5425 mono_class_setup_vtable (klass);
5426 if (mono_class_has_failure (klass))
5427 cmethod = NULL;
5428 else
5429 cmethod = m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
5432 if (cmethod) {
5433 g_assert (m_class_get_vtable_size (klass) > mono_class_get_object_finalize_slot ());
5435 if (m_class_get_parent (klass)) {
5436 if (cmethod->is_inflated)
5437 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5438 if (cmethod != mono_class_get_default_finalize_method ())
5439 has_finalize = TRUE;
5445 mono_loader_lock ();
5446 if (!m_class_is_has_finalize_inited (klass)) {
5447 klass->has_finalize = has_finalize ? 1 : 0;
5449 mono_memory_barrier ();
5450 klass->has_finalize_inited = TRUE;
5452 mono_loader_unlock ();
5456 * mono_class_setup_supertypes:
5457 * @class: a class
5459 * Build the data structure needed to make fast type checks work.
5460 * This currently sets two fields in @class:
5461 * - idepth: distance between @class and System.Object in the type
5462 * hierarchy + 1
5463 * - supertypes: array of classes: each element has a class in the hierarchy
5464 * starting from @class up to System.Object
5466 * LOCKING: Acquires the loader lock.
5468 void
5469 mono_class_setup_supertypes (MonoClass *klass)
5471 int ms, idepth;
5472 MonoClass **supertypes;
5474 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5475 if (supertypes)
5476 return;
5478 if (klass->parent && !klass->parent->supertypes)
5479 mono_class_setup_supertypes (klass->parent);
5480 if (klass->parent)
5481 idepth = klass->parent->idepth + 1;
5482 else
5483 idepth = 1;
5485 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5486 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5488 if (klass->parent) {
5489 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5491 int supertype_idx;
5492 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5493 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5494 } else {
5495 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5498 mono_memory_barrier ();
5500 mono_loader_lock ();
5501 klass->idepth = idepth;
5502 /* Needed so idepth is visible before supertypes is set */
5503 mono_memory_barrier ();
5504 klass->supertypes = supertypes;
5505 mono_loader_unlock ();
5508 /* mono_class_setup_nested_types:
5510 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5512 * LOCKING: Acquires the loader lock.
5514 void
5515 mono_class_setup_nested_types (MonoClass *klass)
5517 ERROR_DECL (error);
5518 GList *classes, *nested_classes, *l;
5519 int i;
5521 if (klass->nested_classes_inited)
5522 return;
5524 if (!klass->type_token) {
5525 mono_loader_lock ();
5526 klass->nested_classes_inited = TRUE;
5527 mono_loader_unlock ();
5528 return;
5531 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
5532 classes = NULL;
5533 while (i) {
5534 MonoClass* nclass;
5535 guint32 cols [MONO_NESTED_CLASS_SIZE];
5536 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
5537 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], error);
5538 if (!mono_error_ok (error)) {
5539 /*FIXME don't swallow the error message*/
5540 mono_error_cleanup (error);
5542 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5543 continue;
5546 classes = g_list_prepend (classes, nclass);
5548 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5551 nested_classes = NULL;
5552 for (l = classes; l; l = l->next)
5553 nested_classes = mono_g_list_prepend_image (klass->image, nested_classes, l->data);
5554 g_list_free (classes);
5556 mono_loader_lock ();
5557 if (!klass->nested_classes_inited) {
5558 mono_class_set_nested_classes_property (klass, nested_classes);
5559 mono_memory_barrier ();
5560 klass->nested_classes_inited = TRUE;
5562 mono_loader_unlock ();
5566 * mono_class_setup_runtime_info:
5567 * \param klass the class to setup
5568 * \param domain the domain of the \p vtable
5569 * \param vtable
5571 * Store \p vtable in \c klass->runtime_info.
5573 * Sets the following field in MonoClass:
5574 * - runtime_info
5576 * LOCKING: domain lock and loaderlock must be held.
5578 void
5579 mono_class_setup_runtime_info (MonoClass *klass, MonoDomain *domain, MonoVTable *vtable)
5581 MonoClassRuntimeInfo *old_info = m_class_get_runtime_info (klass);
5582 if (old_info && old_info->max_domain >= domain->domain_id) {
5583 /* someone already created a large enough runtime info */
5584 old_info->domain_vtables [domain->domain_id] = vtable;
5585 } else {
5586 int new_size = domain->domain_id;
5587 if (old_info)
5588 new_size = MAX (new_size, old_info->max_domain);
5589 new_size++;
5590 /* make the new size a power of two */
5591 int i = 2;
5592 while (new_size > i)
5593 i <<= 1;
5594 new_size = i;
5595 /* this is a bounded memory retention issue: may want to
5596 * handle it differently when we'll have a rcu-like system.
5598 MonoClassRuntimeInfo *runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
5599 runtime_info->max_domain = new_size - 1;
5600 /* copy the stuff from the older info */
5601 if (old_info) {
5602 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
5604 runtime_info->domain_vtables [domain->domain_id] = vtable;
5605 /* keep this last*/
5606 mono_memory_barrier ();
5607 klass->runtime_info = runtime_info;
5612 * mono_class_create_array_fill_type:
5614 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5616 MonoClass *
5617 mono_class_create_array_fill_type (void)
5619 static MonoClass klass;
5621 klass.element_class = mono_defaults.int64_class;
5622 klass.rank = 1;
5623 klass.instance_size = MONO_SIZEOF_MONO_ARRAY;
5624 klass.sizes.element_size = 8;
5625 klass.size_inited = 1;
5626 klass.name = "array_filler_type";
5628 return &klass;
5632 * mono_classes_init:
5634 * Initialize the resources used by this module.
5635 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5637 MONO_NO_SANITIZE_THREAD
5638 void
5639 mono_classes_init (void)
5641 mono_os_mutex_init (&classes_mutex);
5643 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
5644 mono_native_tls_alloc (&init_pending_tls_id, NULL);
5646 mono_counters_register ("MonoClassDef count",
5647 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
5648 mono_counters_register ("MonoClassGtd count",
5649 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
5650 mono_counters_register ("MonoClassGenericInst count",
5651 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
5652 mono_counters_register ("MonoClassGenericParam count",
5653 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
5654 mono_counters_register ("MonoClassArray count",
5655 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
5656 mono_counters_register ("MonoClassPointer count",
5657 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
5658 mono_counters_register ("Inflated methods size",
5659 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mono_inflated_methods_size);
5660 mono_counters_register ("Inflated classes size",
5661 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
5662 mono_counters_register ("MonoClass size",
5663 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
5667 * mono_classes_cleanup:
5669 * Free the resources used by this module.
5671 void
5672 mono_classes_cleanup (void)
5674 mono_native_tls_free (setup_fields_tls_id);
5675 mono_native_tls_free (init_pending_tls_id);
5677 if (global_interface_bitset)
5678 mono_bitset_free (global_interface_bitset);
5679 global_interface_bitset = NULL;
5680 mono_os_mutex_destroy (&classes_mutex);