Apply changes from https://github.com/dotnet/runtime/commit/eb1756e97d23df13bc6fe798e...
[mono-project.git] / mono / metadata / class-init.c
blobf70cf849976bb9f6edac796f80ba5d37fcd63e79
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-init-internals.h>
13 #include <mono/metadata/class-internals.h>
14 #include <mono/metadata/custom-attrs-internals.h>
15 #include <mono/metadata/debug-helpers.h>
16 #include <mono/metadata/exception-internals.h>
17 #include <mono/metadata/gc-internals.h>
18 #include <mono/metadata/object-internals.h>
19 #include <mono/metadata/profiler-private.h>
20 #include <mono/metadata/security-core-clr.h>
21 #include <mono/metadata/security-manager.h>
22 #include <mono/metadata/verify-internals.h>
23 #include <mono/metadata/abi-details.h>
24 #include <mono/utils/checked-build.h>
25 #include <mono/utils/mono-counters.h>
26 #include <mono/utils/mono-error-internals.h>
27 #include <mono/utils/mono-logger-internals.h>
28 #include <mono/utils/mono-memory-model.h>
29 #include <mono/utils/unlocked.h>
30 #ifdef MONO_CLASS_DEF_PRIVATE
31 /* Class initialization gets to see the fields of MonoClass */
32 #define REALLY_INCLUDE_CLASS_DEF 1
33 #include <mono/metadata/class-private-definition.h>
34 #undef REALLY_INCLUDE_CLASS_DEF
35 #endif
37 #ifdef ENABLE_NETCORE
38 #define FEATURE_COVARIANT_RETURNS
39 #endif
41 gboolean mono_print_vtable = FALSE;
42 gboolean mono_align_small_structs = FALSE;
43 #ifdef ENABLE_NETCORE
44 /* Set by the EE */
45 gint32 mono_simd_register_size;
46 #endif
48 /* Statistics */
49 static gint32 classes_size;
50 static gint32 inflated_classes_size;
51 gint32 mono_inflated_methods_size;
52 static gint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
54 /* Low level lock which protects data structures in this module */
55 static mono_mutex_t classes_mutex;
57 static gboolean class_kind_may_contain_generic_instances (MonoTypeKind kind);
58 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd);
59 static int generic_array_methods (MonoClass *klass);
60 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
61 static gboolean class_has_isbyreflike_attribute (MonoClass *klass);
63 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
64 static MonoNativeTlsKey setup_fields_tls_id;
66 static MonoNativeTlsKey init_pending_tls_id;
68 static void
69 classes_lock (void)
71 mono_locks_os_acquire (&classes_mutex, ClassesLock);
74 static void
75 classes_unlock (void)
77 mono_locks_os_release (&classes_mutex, ClassesLock);
81 We use gclass recording to allow recursive system f types to be referenced by a parent.
83 Given the following type hierarchy:
85 class TextBox : TextBoxBase<TextBox> {}
86 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
87 class TextInput<T> : Input<T> where T: TextInput<T> {}
88 class Input<T> {}
90 The runtime tries to load TextBoxBase<>.
91 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
92 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
93 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
95 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
96 at this point, iow, both are registered in the type map and both and a NULL parent. This means
97 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
99 To fix that what we do is to record all generic instantes created while resolving the parent of
100 any generic type definition and, after resolved, correct the parent field if needed.
103 static int record_gclass_instantiation;
104 static GSList *gclass_recorded_list;
105 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
108 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
110 static void
111 enable_gclass_recording (void)
113 ++record_gclass_instantiation;
117 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
119 static void
120 disable_gclass_recording (gclass_record_func func, void *user_data)
122 GSList **head = &gclass_recorded_list;
124 g_assert (record_gclass_instantiation > 0);
125 --record_gclass_instantiation;
127 while (*head) {
128 GSList *node = *head;
129 if (func ((MonoClass*)node->data, user_data)) {
130 *head = node->next;
131 g_slist_free_1 (node);
132 } else {
133 head = &node->next;
137 /* We automatically discard all recorded gclasses when disabled. */
138 if (!record_gclass_instantiation && gclass_recorded_list) {
139 g_slist_free (gclass_recorded_list);
140 gclass_recorded_list = NULL;
144 #define mono_class_new0(klass,struct_type, n_structs) \
145 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
148 * mono_class_setup_basic_field_info:
149 * \param class The class to initialize
151 * Initializes the following fields in MonoClass:
152 * * klass->fields (only field->parent and field->name)
153 * * klass->field.count
154 * * klass->first_field_idx
155 * LOCKING: Acquires the loader lock
157 void
158 mono_class_setup_basic_field_info (MonoClass *klass)
160 MonoGenericClass *gklass;
161 MonoClassField *field;
162 MonoClassField *fields;
163 MonoClass *gtd;
164 MonoImage *image;
165 int i, top;
167 if (klass->fields)
168 return;
170 gklass = mono_class_try_get_generic_class (klass);
171 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
172 image = klass->image;
175 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
177 * This happens when a generic instance of an unfinished generic typebuilder
178 * is used as an element type for creating an array type. We can't initialize
179 * the fields of this class using the fields of gklass, since gklass is not
180 * finished yet, fields could be added to it later.
182 return;
185 if (gtd) {
186 mono_class_setup_basic_field_info (gtd);
188 mono_loader_lock ();
189 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
190 mono_loader_unlock ();
193 top = mono_class_get_field_count (klass);
195 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
198 * Fetch all the field information.
200 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
201 for (i = 0; i < top; i++) {
202 field = &fields [i];
203 field->parent = klass;
205 if (gtd) {
206 field->name = mono_field_get_name (&gtd->fields [i]);
207 } else {
208 int idx = first_field_idx + i;
209 /* first_field_idx and idx points into the fieldptr table */
210 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
211 /* The name is needed for fieldrefs */
212 field->name = mono_metadata_string_heap (image, name_idx);
216 mono_memory_barrier ();
218 mono_loader_lock ();
219 if (!klass->fields)
220 klass->fields = fields;
221 mono_loader_unlock ();
225 * mono_class_setup_fields:
226 * \p klass The class to initialize
228 * Initializes klass->fields, computes class layout and sizes.
229 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
230 * Sets the following fields in \p klass:
231 * - all the fields initialized by mono_class_init_sizes ()
232 * - element_class/cast_class (for enums)
233 * - sizes:element_size (for arrays)
234 * - field->type/offset for all fields
235 * - fields_inited
237 * LOCKING: Acquires the loader lock.
239 void
240 mono_class_setup_fields (MonoClass *klass)
242 ERROR_DECL (error);
243 MonoImage *m = klass->image;
244 int top;
245 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
246 int i;
247 guint32 real_size = 0;
248 guint32 packing_size = 0;
249 int instance_size;
250 gboolean explicit_size;
251 MonoClassField *field;
252 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
253 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
255 if (klass->fields_inited)
256 return;
258 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
260 * This happens when a generic instance of an unfinished generic typebuilder
261 * is used as an element type for creating an array type. We can't initialize
262 * the fields of this class using the fields of gklass, since gklass is not
263 * finished yet, fields could be added to it later.
265 return;
268 mono_class_setup_basic_field_info (klass);
269 top = mono_class_get_field_count (klass);
271 if (gtd) {
272 mono_class_setup_fields (gtd);
273 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
274 return;
277 instance_size = 0;
278 if (klass->parent) {
279 /* For generic instances, klass->parent might not have been initialized */
280 mono_class_init_internal (klass->parent);
281 mono_class_setup_fields (klass->parent);
282 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
283 return;
284 instance_size = klass->parent->instance_size;
285 } else {
286 instance_size = MONO_ABI_SIZEOF (MonoObject);
289 /* Get the real size */
290 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
291 if (explicit_size)
292 instance_size += real_size;
294 #ifdef ENABLE_NETCORE
295 if (mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System.Numerics") && !strcmp (klass->name, "Register")) {
296 if (mono_simd_register_size)
297 instance_size += mono_simd_register_size;
299 #endif
302 * This function can recursively call itself.
303 * Prevent infinite recursion by using a list in TLS.
305 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
306 if (g_slist_find (init_list, klass))
307 return;
308 init_list = g_slist_prepend (init_list, klass);
309 mono_native_tls_set_value (setup_fields_tls_id, init_list);
312 * Fetch all the field information.
314 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
315 for (i = 0; i < top; i++) {
316 int idx = first_field_idx + i;
317 field = &klass->fields [i];
319 if (!field->type) {
320 mono_field_resolve_type (field, error);
321 if (!is_ok (error)) {
322 /*mono_field_resolve_type already failed class*/
323 mono_error_cleanup (error);
324 break;
326 if (!field->type)
327 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
328 g_assert (field->type);
331 if (!mono_type_get_underlying_type (field->type)) {
332 mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
333 break;
336 if (mono_field_is_deleted (field))
337 continue;
338 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
339 guint32 uoffset;
340 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
341 int offset = uoffset;
343 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
344 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
345 break;
347 if (offset < -1) { /*-1 is used to encode special static fields */
348 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
349 break;
351 if (mono_class_is_gtd (klass)) {
352 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
353 break;
356 if (mono_type_has_exceptions (field->type)) {
357 char *class_name = mono_type_get_full_name (klass);
358 char *type_name = mono_type_full_name (field->type);
360 mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
361 g_free (class_name);
362 g_free (type_name);
363 break;
365 /* The def_value of fields is compute lazily during vtable creation */
368 if (!mono_class_has_failure (klass)) {
369 mono_loader_lock ();
370 mono_class_layout_fields (klass, instance_size, packing_size, real_size, FALSE);
371 mono_loader_unlock ();
374 init_list = g_slist_remove (init_list, klass);
375 mono_native_tls_set_value (setup_fields_tls_id, init_list);
378 static gboolean
379 discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
381 return mono_class_get_generic_class (gclass)->container_class == user_data;
384 static gboolean
385 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
387 MonoClass *gtd = (MonoClass*)user_data;
388 /* Only try to fix generic instances of @gtd */
389 if (mono_class_get_generic_class (gclass)->container_class != gtd)
390 return FALSE;
392 /* Check if the generic instance has no parent. */
393 if (gtd->parent && !gclass->parent)
394 mono_generic_class_setup_parent (gclass, gtd);
396 return TRUE;
399 static void
400 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
402 mono_class_set_type_load_failure (klass, "%s", msg);
403 mono_error_set_type_load_class (error, klass, "%s", msg);
407 * mono_class_create_from_typedef:
408 * \param image: image where the token is valid
409 * \param type_token: typedef token
410 * \param error: used to return any error found while creating the type
412 * Create the MonoClass* representing the specified type token.
413 * \p type_token must be a TypeDef token.
415 * FIXME: don't return NULL on failure, just let the caller figure it out.
417 MonoClass *
418 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
420 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
421 MonoClass *klass, *parent = NULL;
422 guint32 cols [MONO_TYPEDEF_SIZE];
423 guint32 cols_next [MONO_TYPEDEF_SIZE];
424 guint tidx = mono_metadata_token_index (type_token);
425 MonoGenericContext *context = NULL;
426 const char *name, *nspace;
427 guint icount = 0;
428 MonoClass **interfaces;
429 guint32 field_last, method_last;
430 guint32 nesting_tokeen;
432 error_init (error);
434 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
435 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
436 return NULL;
439 mono_loader_lock ();
441 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
442 mono_loader_unlock ();
443 return klass;
446 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
448 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
449 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
451 if (mono_metadata_has_generic_params (image, type_token)) {
452 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassGtd));
453 klass->class_kind = MONO_CLASS_GTD;
454 UnlockedAdd (&classes_size, sizeof (MonoClassGtd));
455 ++class_gtd_count;
456 } else {
457 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassDef));
458 klass->class_kind = MONO_CLASS_DEF;
459 UnlockedAdd (&classes_size, sizeof (MonoClassDef));
460 ++class_def_count;
463 klass->name = name;
464 klass->name_space = nspace;
466 MONO_PROFILER_RAISE (class_loading, (klass));
468 klass->image = image;
469 klass->type_token = type_token;
470 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
472 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
475 * Check whether we're a generic type definition.
477 if (mono_class_is_gtd (klass)) {
478 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL, klass);
479 context = &generic_container->context;
480 mono_class_set_generic_container (klass, generic_container);
481 MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
482 canonical_inst->type = MONO_TYPE_GENERICINST;
483 canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
484 enable_gclass_recording ();
487 if (cols [MONO_TYPEDEF_EXTENDS]) {
488 MonoClass *tmp;
489 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
491 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
492 /*WARNING: this must satisfy mono_metadata_type_hash*/
493 klass->this_arg.byref = 1;
494 klass->this_arg.data.klass = klass;
495 klass->this_arg.type = MONO_TYPE_CLASS;
496 klass->_byval_arg.data.klass = klass;
497 klass->_byval_arg.type = MONO_TYPE_CLASS;
499 parent = mono_class_get_checked (image, parent_token, error);
500 if (parent && context) /* Always inflate */
501 parent = mono_class_inflate_generic_class_checked (parent, context, error);
503 if (parent == NULL) {
504 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
505 goto parent_failure;
508 for (tmp = parent; tmp; tmp = tmp->parent) {
509 if (tmp == klass) {
510 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
511 goto parent_failure;
513 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
514 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
515 goto parent_failure;
520 mono_class_setup_parent (klass, parent);
522 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
523 mono_class_setup_mono_type (klass);
525 if (mono_class_is_gtd (klass))
526 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
529 * This might access klass->_byval_arg for recursion generated by generic constraints,
530 * so it has to come after setup_mono_type ().
532 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
533 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
534 if (!is_ok (error)) {
535 /*FIXME implement a mono_class_set_failure_from_mono_error */
536 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
537 mono_loader_unlock ();
538 MONO_PROFILER_RAISE (class_failed, (klass));
539 return NULL;
543 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
544 klass->unicode = 1;
546 #ifdef HOST_WIN32
547 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
548 klass->unicode = 1;
549 #endif
551 klass->cast_class = klass->element_class = klass;
552 if (mono_is_corlib_image (klass->image)) {
553 switch (m_class_get_byval_arg (klass)->type) {
554 case MONO_TYPE_I1:
555 if (mono_defaults.byte_class)
556 klass->cast_class = mono_defaults.byte_class;
557 break;
558 case MONO_TYPE_U1:
559 if (mono_defaults.sbyte_class)
560 mono_defaults.sbyte_class = klass;
561 break;
562 case MONO_TYPE_I2:
563 if (mono_defaults.uint16_class)
564 mono_defaults.uint16_class = klass;
565 break;
566 case MONO_TYPE_U2:
567 if (mono_defaults.int16_class)
568 klass->cast_class = mono_defaults.int16_class;
569 break;
570 case MONO_TYPE_I4:
571 if (mono_defaults.uint32_class)
572 mono_defaults.uint32_class = klass;
573 break;
574 case MONO_TYPE_U4:
575 if (mono_defaults.int32_class)
576 klass->cast_class = mono_defaults.int32_class;
577 break;
578 case MONO_TYPE_I8:
579 if (mono_defaults.uint64_class)
580 mono_defaults.uint64_class = klass;
581 break;
582 case MONO_TYPE_U8:
583 if (mono_defaults.int64_class)
584 klass->cast_class = mono_defaults.int64_class;
585 break;
586 default:
587 break;
591 if (!klass->enumtype) {
592 if (!mono_metadata_interfaces_from_typedef_full (
593 image, type_token, &interfaces, &icount, FALSE, context, error)){
595 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
596 mono_loader_unlock ();
597 MONO_PROFILER_RAISE (class_failed, (klass));
598 return NULL;
601 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
602 g_assert(icount <= 65535);
604 klass->interfaces = interfaces;
605 klass->interface_count = icount;
606 klass->interfaces_inited = 1;
609 /*g_print ("Load class %s\n", name);*/
612 * Compute the field and method lists
614 int first_field_idx;
615 first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
616 mono_class_set_first_field_idx (klass, first_field_idx);
617 int first_method_idx;
618 first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
619 mono_class_set_first_method_idx (klass, first_method_idx);
621 if (tt->rows > tidx){
622 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
623 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
624 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
625 } else {
626 field_last = image->tables [MONO_TABLE_FIELD].rows;
627 method_last = image->tables [MONO_TABLE_METHOD].rows;
630 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
631 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
632 mono_class_set_field_count (klass, field_last - first_field_idx);
633 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
634 mono_class_set_method_count (klass, method_last - first_method_idx);
636 /* reserve space to store vector pointer in arrays */
637 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
638 klass->instance_size += 2 * TARGET_SIZEOF_VOID_P;
639 #ifndef ENABLE_NETCORE
640 g_assert (mono_class_get_field_count (klass) == 0);
641 #else
642 /* TODO: check that array has 0 non-const fields */
643 #endif
646 if (klass->enumtype) {
647 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
648 if (!enum_basetype) {
649 /*set it to a default value as the whole runtime can't handle this to be null*/
650 klass->cast_class = klass->element_class = mono_defaults.int32_class;
651 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
652 mono_loader_unlock ();
653 MONO_PROFILER_RAISE (class_failed, (klass));
654 return NULL;
656 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (enum_basetype);
660 * If we're a generic type definition, load the constraints.
661 * We must do this after the class has been constructed to make certain recursive scenarios
662 * work.
664 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
665 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
666 mono_loader_unlock ();
667 MONO_PROFILER_RAISE (class_failed, (klass));
668 return NULL;
671 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
672 if (!strncmp (name, "Vector", 6))
673 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");
674 } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
675 /* The JIT can't handle SIMD types with != 16 size yet */
676 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
677 if (!strcmp (name, "Vector4"))
678 klass->simd_type = 1;
681 // compute is_byreflike
682 if (m_class_is_valuetype (klass))
683 if (class_has_isbyreflike_attribute (klass))
684 klass->is_byreflike = 1;
686 mono_loader_unlock ();
688 MONO_PROFILER_RAISE (class_loaded, (klass));
690 return klass;
692 parent_failure:
693 if (mono_class_is_gtd (klass))
694 disable_gclass_recording (discard_gclass_due_to_failure, klass);
696 mono_class_setup_mono_type (klass);
697 mono_loader_unlock ();
698 MONO_PROFILER_RAISE (class_failed, (klass));
699 return NULL;
703 static void
704 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
706 if (gtd->parent) {
707 ERROR_DECL (error);
708 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
710 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), error);
711 if (!is_ok (error)) {
712 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
713 klass->parent = mono_defaults.object_class;
714 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error));
715 mono_error_cleanup (error);
718 mono_loader_lock ();
719 if (klass->parent)
720 mono_class_setup_parent (klass, klass->parent);
722 if (klass->enumtype) {
723 klass->cast_class = gtd->cast_class;
724 klass->element_class = gtd->element_class;
726 mono_loader_unlock ();
729 struct FoundAttrUD {
730 /* inputs */
731 const char *nspace;
732 const char *name;
733 gboolean in_corlib;
734 /* output */
735 gboolean has_attr;
738 static gboolean
739 has_wellknown_attribute_func (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
741 struct FoundAttrUD *has_attr = (struct FoundAttrUD *)user_data;
742 if (!strcmp (name, has_attr->name) && !strcmp (nspace, has_attr->nspace)) {
743 has_attr->has_attr = TRUE;
744 return TRUE;
746 /* TODO: use typeref_scope_token to check that attribute comes from
747 * corlib if in_corlib is TRUE, without triggering an assembly load.
748 * If we're inside corlib, expect the scope to be
749 * MONO_RESOLUTION_SCOPE_MODULE I think, if we're outside it'll be an
750 * MONO_RESOLUTION_SCOPE_ASSEMBLYREF and we'll need to check the
751 * name.*/
752 return FALSE;
755 static gboolean
756 class_has_wellknown_attribute (MonoClass *klass, const char *nspace, const char *name, gboolean in_corlib)
758 struct FoundAttrUD has_attr;
759 has_attr.nspace = nspace;
760 has_attr.name = name;
761 has_attr.in_corlib = in_corlib;
762 has_attr.has_attr = FALSE;
764 mono_class_metadata_foreach_custom_attr (klass, has_wellknown_attribute_func, &has_attr);
766 return has_attr.has_attr;
769 static gboolean
770 method_has_wellknown_attribute (MonoMethod *method, const char *nspace, const char *name, gboolean in_corlib)
772 struct FoundAttrUD has_attr;
773 has_attr.nspace = nspace;
774 has_attr.name = name;
775 has_attr.in_corlib = in_corlib;
776 has_attr.has_attr = FALSE;
778 mono_method_metadata_foreach_custom_attr (method, has_wellknown_attribute_func, &has_attr);
780 return has_attr.has_attr;
784 static gboolean
785 class_has_isbyreflike_attribute (MonoClass *klass)
787 return class_has_wellknown_attribute (klass, "System.Runtime.CompilerServices", "IsByRefLikeAttribute", TRUE);
791 gboolean
792 mono_class_setup_method_has_preserve_base_overrides_attribute (MonoMethod *method)
794 MonoImage *image = m_class_get_image (method->klass);
795 /* FIXME: implement well known attribute check for dynamic images */
796 if (image_is_dynamic (image))
797 return FALSE;
798 return method_has_wellknown_attribute (method, "System.Runtime.CompilerServices", "PreserveBaseOverridesAttribute", TRUE);
801 static gboolean
802 check_valid_generic_inst_arguments (MonoGenericInst *inst, MonoError *error)
804 for (int i = 0; i < inst->type_argc; i++) {
805 if (!mono_type_is_valid_generic_argument (inst->type_argv [i])) {
806 char *type_name = mono_type_full_name (inst->type_argv [i]);
807 mono_error_set_invalid_program (error, "generic type cannot be instantiated with type '%s'", type_name);
808 g_free (type_name);
809 return FALSE;
812 return TRUE;
816 * Create the `MonoClass' for an instantiation of a generic type.
817 * We only do this if we actually need it.
818 * This will sometimes return a GTD due to checking the cached_class.
820 MonoClass*
821 mono_class_create_generic_inst (MonoGenericClass *gclass)
823 MonoClass *klass, *gklass;
825 if (gclass->cached_class)
826 return gclass->cached_class;
828 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
830 gklass = gclass->container_class;
832 if (gklass->nested_in) {
833 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
834 klass->nested_in = gklass->nested_in;
837 klass->name = gklass->name;
838 klass->name_space = gklass->name_space;
840 klass->image = gklass->image;
841 klass->type_token = gklass->type_token;
843 klass->class_kind = MONO_CLASS_GINST;
844 //FIXME add setter
845 ((MonoClassGenericInst*)klass)->generic_class = gclass;
847 klass->_byval_arg.type = MONO_TYPE_GENERICINST;
848 klass->this_arg.type = m_class_get_byval_arg (klass)->type;
849 klass->this_arg.data.generic_class = klass->_byval_arg.data.generic_class = gclass;
850 klass->this_arg.byref = TRUE;
851 klass->enumtype = gklass->enumtype;
852 klass->valuetype = gklass->valuetype;
855 if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
856 g_assert (gclass->context.class_inst);
857 g_assert (gclass->context.class_inst->type_argc > 0);
858 if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
859 klass->simd_type = 1;
861 #ifdef ENABLE_NETCORE
862 if (mono_is_corlib_image (gklass->image) &&
863 (!strcmp (gklass->name, "Vector`1") || !strcmp (gklass->name, "Vector128`1") || !strcmp (gklass->name, "Vector256`1"))) {
864 MonoType *etype = gclass->context.class_inst->type_argv [0];
865 if (mono_type_is_primitive (etype) && etype->type != MONO_TYPE_CHAR && etype->type != MONO_TYPE_BOOLEAN)
866 klass->simd_type = 1;
868 #endif
870 klass->is_array_special_interface = gklass->is_array_special_interface;
872 klass->cast_class = klass->element_class = klass;
874 if (m_class_is_valuetype (klass)) {
875 klass->is_byreflike = gklass->is_byreflike;
878 if (gclass->is_dynamic) {
880 * 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.
881 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
882 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
884 if (!gklass->wastypebuilder)
885 klass->inited = 1;
887 if (klass->enumtype) {
889 * For enums, gklass->fields might not been set, but instance_size etc. is
890 * already set in mono_reflection_create_internal_class (). For non-enums,
891 * these will be computed normally in mono_class_layout_fields ().
893 klass->instance_size = gklass->instance_size;
894 klass->sizes.class_size = gklass->sizes.class_size;
895 klass->size_inited = 1;
900 ERROR_DECL (error_inst);
901 if (!check_valid_generic_inst_arguments (gclass->context.class_inst, error_inst)) {
902 char *gklass_name = mono_type_get_full_name (gklass);
903 mono_class_set_type_load_failure (klass, "Could not instantiate %s due to %s", gklass_name, mono_error_get_message (error_inst));
904 g_free (gklass_name);
905 mono_error_cleanup (error_inst);
909 mono_loader_lock ();
911 if (gclass->cached_class) {
912 mono_loader_unlock ();
913 return gclass->cached_class;
916 if (record_gclass_instantiation > 0)
917 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
919 if (mono_class_is_nullable (klass))
920 klass->cast_class = klass->element_class = mono_class_get_nullable_param_internal (klass);
922 MONO_PROFILER_RAISE (class_loading, (klass));
924 mono_generic_class_setup_parent (klass, gklass);
926 if (gclass->is_dynamic)
927 mono_class_setup_supertypes (klass);
929 mono_memory_barrier ();
930 gclass->cached_class = klass;
932 MONO_PROFILER_RAISE (class_loaded, (klass));
934 ++class_ginst_count;
935 inflated_classes_size += sizeof (MonoClassGenericInst);
937 mono_loader_unlock ();
939 return klass;
943 * For a composite class like uint32[], uint32*, set MonoClass:cast_class to the corresponding "intermediate type" (for
944 * arrays) or "verification type" (for pointers) in the sense of ECMA I.8.7.3. This will be used by
945 * mono_class_is_assignable_from.
947 * Assumes MonoClass:cast_class is already set (for example if it's an array of
948 * some enum) and adjusts it.
950 static void
951 class_composite_fixup_cast_class (MonoClass *klass, gboolean for_ptr)
953 switch (m_class_get_byval_arg (m_class_get_cast_class (klass))->type) {
954 case MONO_TYPE_BOOLEAN:
955 if (!for_ptr)
956 break;
957 klass->cast_class = mono_defaults.byte_class;
958 break;
959 case MONO_TYPE_I1:
960 klass->cast_class = mono_defaults.byte_class;
961 break;
962 case MONO_TYPE_U2:
963 klass->cast_class = mono_defaults.int16_class;
964 break;
965 case MONO_TYPE_U4:
966 #if TARGET_SIZEOF_VOID_P == 4
967 case MONO_TYPE_I:
968 case MONO_TYPE_U:
969 #endif
970 klass->cast_class = mono_defaults.int32_class;
971 break;
972 case MONO_TYPE_U8:
973 #if TARGET_SIZEOF_VOID_P == 8
974 case MONO_TYPE_I:
975 case MONO_TYPE_U:
976 #endif
977 klass->cast_class = mono_defaults.int64_class;
978 break;
979 default:
980 break;
984 static gboolean
985 class_kind_may_contain_generic_instances (MonoTypeKind kind)
987 /* classes of type generic inst may contain generic arguments from other images,
988 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
989 return (kind == MONO_CLASS_GINST || kind == MONO_CLASS_ARRAY || kind == MONO_CLASS_POINTER);
993 * mono_class_create_bounded_array:
994 * \param element_class element class
995 * \param rank the dimension of the array class
996 * \param bounded whenever the array has non-zero bounds
997 * \returns A class object describing the array with element type \p element_type and
998 * dimension \p rank.
1000 MonoClass *
1001 mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bounded)
1003 MonoImage *image;
1004 MonoClass *klass, *cached, *k;
1005 MonoClass *parent = NULL;
1006 GSList *list, *rootlist = NULL;
1007 int nsize;
1008 char *name;
1009 MonoImageSet* image_set;
1011 if (rank > 1)
1012 /* bounded only matters for one-dimensional arrays */
1013 bounded = FALSE;
1015 image = eclass->image;
1016 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)eclass->class_kind) ? mono_metadata_get_image_set_for_class (eclass) : NULL;
1018 /* Check cache */
1019 cached = NULL;
1020 if (rank == 1 && !bounded) {
1021 if (image_set) {
1022 mono_image_set_lock (image_set);
1023 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
1024 mono_image_set_unlock (image_set);
1025 } else {
1027 * This case is very frequent not just during compilation because of calls
1028 * from mono_class_from_mono_type_internal (), mono_array_new (),
1029 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
1031 mono_os_mutex_lock (&image->szarray_cache_lock);
1032 if (!image->szarray_cache)
1033 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1034 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
1035 mono_os_mutex_unlock (&image->szarray_cache_lock);
1037 } else {
1038 if (image_set) {
1039 mono_image_set_lock (image_set);
1040 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
1041 for (list = rootlist; list; list = list->next) {
1042 k = (MonoClass *)list->data;
1043 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1044 cached = k;
1045 break;
1048 mono_image_set_unlock (image_set);
1049 } else {
1050 mono_loader_lock ();
1051 if (!image->array_cache)
1052 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1053 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
1054 for (list = rootlist; list; list = list->next) {
1055 k = (MonoClass *)list->data;
1056 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1057 cached = k;
1058 break;
1061 mono_loader_unlock ();
1064 if (cached)
1065 return cached;
1067 parent = mono_defaults.array_class;
1068 if (!parent->inited)
1069 mono_class_init_internal (parent);
1071 klass = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
1073 klass->image = image;
1074 klass->name_space = eclass->name_space;
1075 klass->class_kind = MONO_CLASS_ARRAY;
1077 nsize = strlen (eclass->name);
1078 int maxrank = MIN (rank, 32);
1079 name = (char *)g_malloc (nsize + 2 + maxrank + 1);
1080 memcpy (name, eclass->name, nsize);
1081 name [nsize] = '[';
1082 if (maxrank > 1)
1083 memset (name + nsize + 1, ',', maxrank - 1);
1084 if (bounded)
1085 name [nsize + maxrank] = '*';
1086 name [nsize + maxrank + bounded] = ']';
1087 name [nsize + maxrank + bounded + 1] = 0;
1088 klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
1089 g_free (name);
1091 klass->type_token = 0;
1092 klass->parent = parent;
1093 klass->instance_size = mono_class_instance_size (klass->parent);
1095 if (m_class_get_byval_arg (eclass)->type == MONO_TYPE_TYPEDBYREF) {
1096 /*Arrays of those two types are invalid.*/
1097 ERROR_DECL (prepared_error);
1098 mono_error_set_invalid_program (prepared_error, "Arrays of System.TypedReference types are invalid.");
1099 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
1100 mono_error_cleanup (prepared_error);
1101 } else if (m_class_is_byreflike (eclass)) {
1102 /* .NET Core throws a type load exception: "Could not create array type 'fullname[]'" */
1103 char *full_name = mono_type_get_full_name (eclass);
1104 mono_class_set_type_load_failure (klass, "Could not create array type '%s[]'", full_name);
1105 g_free (full_name);
1106 } else if (eclass->enumtype && !mono_class_enum_basetype_internal (eclass)) {
1107 MonoGCHandle ref_info_handle = mono_class_get_ref_info_handle (eclass);
1108 if (!ref_info_handle || eclass->wastypebuilder) {
1109 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
1110 g_assert (ref_info_handle && !eclass->wastypebuilder);
1112 /* element_size -1 is ok as this is not an instantitable type*/
1113 klass->sizes.element_size = -1;
1114 } else
1115 klass->sizes.element_size = -1;
1117 mono_class_setup_supertypes (klass);
1119 if (mono_class_is_ginst (eclass))
1120 mono_class_init_internal (eclass);
1121 if (!eclass->size_inited)
1122 mono_class_setup_fields (eclass);
1123 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
1124 /*FIXME we fail the array type, but we have to let other fields be set.*/
1126 klass->has_references = MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (eclass)) || m_class_has_references (eclass)? TRUE: FALSE;
1128 klass->rank = rank;
1130 if (eclass->enumtype)
1131 klass->cast_class = eclass->element_class;
1132 else
1133 klass->cast_class = eclass;
1135 class_composite_fixup_cast_class (klass, FALSE);
1137 klass->element_class = eclass;
1139 if ((rank > 1) || bounded) {
1140 MonoArrayType *at = image_set ? (MonoArrayType *)mono_image_set_alloc0 (image_set, sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
1141 klass->_byval_arg.type = MONO_TYPE_ARRAY;
1142 klass->_byval_arg.data.array = at;
1143 at->eklass = eclass;
1144 at->rank = rank;
1145 /* FIXME: complete.... */
1146 } else {
1147 klass->_byval_arg.type = MONO_TYPE_SZARRAY;
1148 klass->_byval_arg.data.klass = eclass;
1150 klass->this_arg = klass->_byval_arg;
1151 klass->this_arg.byref = 1;
1153 if (rank > 32) {
1154 ERROR_DECL (prepared_error);
1155 name = mono_type_get_full_name (klass);
1156 mono_error_set_type_load_class (prepared_error, klass, "%s has too many dimensions.", name);
1157 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
1158 mono_error_cleanup (prepared_error);
1159 g_free (name);
1162 mono_loader_lock ();
1164 /* Check cache again */
1165 cached = NULL;
1166 if (rank == 1 && !bounded) {
1167 if (image_set) {
1168 mono_image_set_lock (image_set);
1169 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
1170 mono_image_set_unlock (image_set);
1171 } else {
1172 mono_os_mutex_lock (&image->szarray_cache_lock);
1173 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
1174 mono_os_mutex_unlock (&image->szarray_cache_lock);
1176 } else {
1177 if (image_set) {
1178 mono_image_set_lock (image_set);
1179 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
1180 for (list = rootlist; list; list = list->next) {
1181 k = (MonoClass *)list->data;
1182 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1183 cached = k;
1184 break;
1187 mono_image_set_unlock (image_set);
1188 } else {
1189 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
1190 for (list = rootlist; list; list = list->next) {
1191 k = (MonoClass *)list->data;
1192 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1193 cached = k;
1194 break;
1199 if (cached) {
1200 mono_loader_unlock ();
1201 return cached;
1204 MONO_PROFILER_RAISE (class_loading, (klass));
1206 UnlockedAdd (&classes_size, sizeof (MonoClassArray));
1207 ++class_array_count;
1209 if (rank == 1 && !bounded) {
1210 if (image_set) {
1211 mono_image_set_lock (image_set);
1212 g_hash_table_insert (image_set->szarray_cache, eclass, klass);
1213 mono_image_set_unlock (image_set);
1214 } else {
1215 mono_os_mutex_lock (&image->szarray_cache_lock);
1216 g_hash_table_insert (image->szarray_cache, eclass, klass);
1217 mono_os_mutex_unlock (&image->szarray_cache_lock);
1219 } else {
1220 if (image_set) {
1221 mono_image_set_lock (image_set);
1222 list = g_slist_append (rootlist, klass);
1223 g_hash_table_insert (image_set->array_cache, eclass, list);
1224 mono_image_set_unlock (image_set);
1225 } else {
1226 list = g_slist_append (rootlist, klass);
1227 g_hash_table_insert (image->array_cache, eclass, list);
1231 mono_loader_unlock ();
1233 MONO_PROFILER_RAISE (class_loaded, (klass));
1235 return klass;
1239 * mono_class_create_array:
1240 * \param element_class element class
1241 * \param rank the dimension of the array class
1242 * \returns A class object describing the array with element type \p element_type and
1243 * dimension \p rank.
1245 MonoClass *
1246 mono_class_create_array (MonoClass *eclass, guint32 rank)
1248 return mono_class_create_bounded_array (eclass, rank, FALSE);
1251 // This is called by mono_class_create_generic_parameter when a new class must be created.
1252 static MonoClass*
1253 make_generic_param_class (MonoGenericParam *param)
1255 MonoClass *klass, **ptr;
1256 int count, pos, i, min_align;
1257 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1258 MonoGenericContainer *container = mono_generic_param_owner (param);
1259 g_assert_checked (container);
1261 MonoImage *image = mono_get_image_for_generic_param (param);
1262 gboolean is_mvar = container->is_method;
1263 gboolean is_anonymous = container->is_anonymous;
1265 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
1266 klass->class_kind = MONO_CLASS_GPARAM;
1267 UnlockedAdd (&classes_size, sizeof (MonoClassGenericParam));
1268 UnlockedIncrement (&class_gparam_count);
1270 if (!is_anonymous) {
1271 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
1272 } else {
1273 int n = mono_generic_param_num (param);
1274 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , mono_make_generic_name_string (image, n) );
1277 if (is_anonymous) {
1278 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
1279 } else if (is_mvar) {
1280 MonoMethod *omethod = container->owner.method;
1281 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
1282 } else {
1283 MonoClass *oklass = container->owner.klass;
1284 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
1287 MONO_PROFILER_RAISE (class_loading, (klass));
1289 // Count non-NULL items in pinfo->constraints
1290 count = 0;
1291 if (!is_anonymous)
1292 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
1295 pos = 0;
1296 if ((count > 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo->constraints [0])) {
1297 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
1298 pos++;
1299 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
1300 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
1301 } else {
1302 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
1305 if (count - pos > 0) {
1306 klass->interface_count = count - pos;
1307 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
1308 klass->interfaces_inited = TRUE;
1309 for (i = pos; i < count; i++)
1310 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
1313 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
1315 klass->inited = TRUE;
1316 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
1317 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
1319 MonoTypeEnum t = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
1320 klass->_byval_arg.type = t;
1321 klass->this_arg.type = t;
1322 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
1323 CHECKED_METADATA_WRITE_PTR ( klass->_byval_arg.data.generic_param , param );
1324 klass->this_arg.byref = TRUE;
1326 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1327 klass->sizes.generic_param_token = !is_anonymous ? pinfo->token : 0;
1329 if (param->gshared_constraint) {
1330 MonoClass *constraint_class = mono_class_from_mono_type_internal (param->gshared_constraint);
1331 mono_class_init_sizes (constraint_class);
1332 klass->has_references = m_class_has_references (constraint_class);
1335 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1336 * constrained to, the JIT depends on this.
1338 klass->instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_size (m_class_get_byval_arg (klass), &min_align);
1339 klass->min_align = min_align;
1340 mono_memory_barrier ();
1341 klass->size_inited = 1;
1343 mono_class_setup_supertypes (klass);
1345 if (count - pos > 0) {
1346 mono_class_setup_vtable (klass->parent);
1347 if (mono_class_has_failure (klass->parent))
1348 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
1349 else
1350 mono_class_setup_interface_offsets_internal (klass, klass->parent->vtable_size, TRUE);
1353 return klass;
1357 * LOCKING: Acquires the image lock (@image).
1359 MonoClass *
1360 mono_class_create_generic_parameter (MonoGenericParam *param)
1362 MonoImage *image = mono_get_image_for_generic_param (param);
1363 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1364 MonoClass *klass, *klass2;
1366 // If a klass already exists for this object and is cached, return it.
1367 klass = pinfo->pklass;
1369 if (klass)
1370 return klass;
1372 // Create a new klass
1373 klass = make_generic_param_class (param);
1375 // Now we need to cache the klass we created.
1376 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1377 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1378 // and allow our newly-created klass object to just leak.
1379 mono_memory_barrier ();
1381 mono_image_lock (image);
1383 // Here "klass2" refers to the klass potentially created by the other thread.
1384 klass2 = pinfo->pklass;
1386 if (klass2) {
1387 klass = klass2;
1388 } else {
1389 pinfo->pklass = klass;
1391 mono_image_unlock (image);
1393 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1394 if (klass2)
1395 MONO_PROFILER_RAISE (class_failed, (klass2));
1396 else
1397 MONO_PROFILER_RAISE (class_loaded, (klass));
1399 return klass;
1403 * mono_class_create_ptr:
1405 MonoClass *
1406 mono_class_create_ptr (MonoType *type)
1408 MonoClass *result;
1409 MonoClass *el_class;
1410 MonoImage *image;
1411 char *name;
1412 MonoImageSet* image_set;
1414 el_class = mono_class_from_mono_type_internal (type);
1415 image = el_class->image;
1416 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)el_class->class_kind) ? mono_metadata_get_image_set_for_class (el_class) : NULL;
1418 if (image_set) {
1419 mono_image_set_lock (image_set);
1420 if (image_set->ptr_cache) {
1421 if ((result = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1422 mono_image_set_unlock (image_set);
1423 return result;
1426 mono_image_set_unlock (image_set);
1427 } else {
1428 mono_image_lock (image);
1429 if (image->ptr_cache) {
1430 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1431 mono_image_unlock (image);
1432 return result;
1435 mono_image_unlock (image);
1438 result = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
1440 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1441 ++class_pointer_count;
1443 result->parent = NULL; /* no parent for PTR types */
1444 result->name_space = el_class->name_space;
1445 name = g_strdup_printf ("%s*", el_class->name);
1446 result->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
1447 result->class_kind = MONO_CLASS_POINTER;
1448 g_free (name);
1450 MONO_PROFILER_RAISE (class_loading, (result));
1452 result->image = el_class->image;
1453 result->inited = TRUE;
1454 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1455 result->min_align = sizeof (gpointer);
1456 result->element_class = el_class;
1457 result->blittable = TRUE;
1459 if (el_class->enumtype)
1460 result->cast_class = el_class->element_class;
1461 else
1462 result->cast_class = el_class;
1463 class_composite_fixup_cast_class (result, TRUE);
1465 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_PTR;
1466 result->this_arg.data.type = result->_byval_arg.data.type = m_class_get_byval_arg (el_class);
1467 result->this_arg.byref = TRUE;
1469 mono_class_setup_supertypes (result);
1471 if (image_set) {
1472 mono_image_set_lock (image_set);
1473 if (image_set->ptr_cache) {
1474 MonoClass *result2;
1475 if ((result2 = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1476 mono_image_set_unlock (image_set);
1477 MONO_PROFILER_RAISE (class_failed, (result));
1478 return result2;
1481 else {
1482 image_set->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1484 g_hash_table_insert (image_set->ptr_cache, el_class, result);
1485 mono_image_set_unlock (image_set);
1486 } else {
1487 mono_image_lock (image);
1488 if (image->ptr_cache) {
1489 MonoClass *result2;
1490 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1491 mono_image_unlock (image);
1492 MONO_PROFILER_RAISE (class_failed, (result));
1493 return result2;
1495 } else {
1496 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1498 g_hash_table_insert (image->ptr_cache, el_class, result);
1499 mono_image_unlock (image);
1502 MONO_PROFILER_RAISE (class_loaded, (result));
1504 return result;
1507 MonoClass *
1508 mono_class_create_fnptr (MonoMethodSignature *sig)
1510 MonoClass *result, *cached;
1511 static GHashTable *ptr_hash = NULL;
1513 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1515 mono_loader_lock ();
1516 if (!ptr_hash)
1517 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1518 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1519 mono_loader_unlock ();
1520 if (cached)
1521 return cached;
1523 result = g_new0 (MonoClass, 1);
1525 result->parent = NULL; /* no parent for PTR types */
1526 result->name_space = "System";
1527 result->name = "MonoFNPtrFakeClass";
1528 result->class_kind = MONO_CLASS_POINTER;
1530 result->image = mono_defaults.corlib; /* need to fix... */
1531 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1532 result->min_align = sizeof (gpointer);
1533 result->cast_class = result->element_class = result;
1534 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_FNPTR;
1535 result->this_arg.data.method = result->_byval_arg.data.method = sig;
1536 result->this_arg.byref = TRUE;
1537 result->blittable = TRUE;
1538 result->inited = TRUE;
1540 mono_class_setup_supertypes (result);
1542 mono_loader_lock ();
1544 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1545 if (cached) {
1546 g_free (result);
1547 mono_loader_unlock ();
1548 return cached;
1551 MONO_PROFILER_RAISE (class_loading, (result));
1553 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1554 ++class_pointer_count;
1556 g_hash_table_insert (ptr_hash, sig, result);
1558 mono_loader_unlock ();
1560 MONO_PROFILER_RAISE (class_loaded, (result));
1562 return result;
1566 static gboolean
1567 method_is_reabstracted (guint16 flags)
1569 if ((flags & METHOD_ATTRIBUTE_ABSTRACT && flags & METHOD_ATTRIBUTE_FINAL))
1570 return TRUE;
1571 return FALSE;
1575 * mono_class_setup_count_virtual_methods:
1577 * Return the number of virtual methods.
1578 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1579 * Return -1 on failure.
1580 * FIXME It would be nice if this information could be cached somewhere.
1583 mono_class_setup_count_virtual_methods (MonoClass *klass)
1585 int i, mcount, vcount = 0;
1586 guint32 flags;
1587 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
1589 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
1590 mono_class_setup_methods (klass);
1591 if (mono_class_has_failure (klass))
1592 return -1;
1594 mcount = mono_class_get_method_count (klass);
1595 for (i = 0; i < mcount; ++i) {
1596 flags = klass->methods [i]->flags;
1597 if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1598 if (method_is_reabstracted (flags))
1599 continue;
1600 ++vcount;
1603 } else {
1604 int first_idx = mono_class_get_first_method_idx (klass);
1605 mcount = mono_class_get_method_count (klass);
1606 for (i = 0; i < mcount; ++i) {
1607 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
1609 if ((flags & METHOD_ATTRIBUTE_VIRTUAL)) {
1610 if (method_is_reabstracted (flags))
1611 continue;
1612 ++vcount;
1616 return vcount;
1619 #ifdef COMPRESSED_INTERFACE_BITMAP
1622 * Compressed interface bitmap design.
1624 * Interface bitmaps take a large amount of memory, because their size is
1625 * linear with the maximum interface id assigned in the process (each interface
1626 * is assigned a unique id as it is loaded). The number of interface classes
1627 * is high because of the many implicit interfaces implemented by arrays (we'll
1628 * need to lazy-load them in the future).
1629 * Most classes implement a very small number of interfaces, so the bitmap is
1630 * sparse. This bitmap needs to be checked by interface casts, so access to the
1631 * needed bit must be fast and doable with few jit instructions.
1633 * The current compression format is as follows:
1634 * *) it is a sequence of one or more two-byte elements
1635 * *) the first byte in the element is the count of empty bitmap bytes
1636 * at the current bitmap position
1637 * *) the second byte in the element is an actual bitmap byte at the current
1638 * bitmap position
1640 * As an example, the following compressed bitmap bytes:
1641 * 0x07 0x01 0x00 0x7
1642 * correspond to the following bitmap:
1643 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1645 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1646 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1647 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1651 * mono_compress_bitmap:
1652 * \param dest destination buffer
1653 * \param bitmap bitmap buffer
1654 * \param size size of \p bitmap in bytes
1656 * This is a mono internal function.
1657 * The \p bitmap data is compressed into a format that is small but
1658 * still searchable in few instructions by the JIT and runtime.
1659 * The compressed data is stored in the buffer pointed to by the
1660 * \p dest array. Passing a NULL value for \p dest allows to just compute
1661 * the size of the buffer.
1662 * This compression algorithm assumes the bits set in the bitmap are
1663 * few and far between, like in interface bitmaps.
1664 * \returns The size of the compressed bitmap in bytes.
1667 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
1669 int numz = 0;
1670 int res = 0;
1671 const uint8_t *end = bitmap + size;
1672 while (bitmap < end) {
1673 if (*bitmap || numz == 255) {
1674 if (dest) {
1675 *dest++ = numz;
1676 *dest++ = *bitmap;
1678 res += 2;
1679 numz = 0;
1680 bitmap++;
1681 continue;
1683 bitmap++;
1684 numz++;
1686 if (numz) {
1687 res += 2;
1688 if (dest) {
1689 *dest++ = numz;
1690 *dest++ = 0;
1693 return res;
1697 * mono_class_interface_match:
1698 * \param bitmap a compressed bitmap buffer
1699 * \param id the index to check in the bitmap
1701 * This is a mono internal function.
1702 * Checks if a bit is set in a compressed interface bitmap. \p id must
1703 * be already checked for being smaller than the maximum id encoded in the
1704 * bitmap.
1706 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1707 * FALSE otherwise.
1710 mono_class_interface_match (const uint8_t *bitmap, int id)
1712 while (TRUE) {
1713 id -= bitmap [0] * 8;
1714 if (id < 8) {
1715 if (id < 0)
1716 return 0;
1717 return bitmap [1] & (1 << id);
1719 bitmap += 2;
1720 id -= 8;
1723 #endif
1725 static char*
1726 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
1728 int null_length = strlen ("(null)");
1729 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
1730 char *s = (char *)mono_image_alloc (image, len);
1731 int result;
1733 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
1734 g_assert (result == len - 1);
1736 return s;
1740 static void
1741 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
1743 if (cached_info) {
1744 mono_loader_lock ();
1745 klass->instance_size = cached_info->instance_size;
1746 klass->sizes.class_size = cached_info->class_size;
1747 klass->packing_size = cached_info->packing_size;
1748 klass->min_align = cached_info->min_align;
1749 klass->blittable = cached_info->blittable;
1750 klass->has_references = cached_info->has_references;
1751 klass->has_static_refs = cached_info->has_static_refs;
1752 klass->no_special_static_fields = cached_info->no_special_static_fields;
1753 klass->has_weak_fields = cached_info->has_weak_fields;
1754 mono_loader_unlock ();
1756 else {
1757 if (!klass->size_inited)
1758 mono_class_setup_fields (klass);
1763 * mono_class_init_sizes:
1765 * Initializes the size related fields of @klass without loading all field data if possible.
1766 * Sets the following fields in @klass:
1767 * - instance_size
1768 * - sizes.class_size
1769 * - packing_size
1770 * - min_align
1771 * - blittable
1772 * - has_references
1773 * - has_static_refs
1774 * - size_inited
1775 * Can fail the class.
1777 * LOCKING: Acquires the loader lock.
1779 void
1780 mono_class_init_sizes (MonoClass *klass)
1782 MonoCachedClassInfo cached_info;
1783 gboolean has_cached_info;
1785 if (klass->size_inited)
1786 return;
1788 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
1790 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
1794 static gboolean
1795 class_has_references (MonoClass *klass)
1797 mono_class_init_sizes (klass);
1800 * has_references is not set if this is called recursively, but this is not a problem since this is only used
1801 * during field layout, and instance fields are initialized before static fields, and instance fields can't
1802 * embed themselves.
1804 return klass->has_references;
1807 static gboolean
1808 type_has_references (MonoClass *klass, MonoType *ftype)
1810 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)))))
1811 return TRUE;
1812 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
1813 MonoGenericParam *gparam = ftype->data.generic_param;
1815 if (gparam->gshared_constraint)
1816 return class_has_references (mono_class_from_mono_type_internal (gparam->gshared_constraint));
1818 return FALSE;
1822 * mono_class_is_gparam_with_nonblittable_parent:
1823 * \param klass a generic parameter
1825 * \returns TRUE if \p klass is definitely not blittable.
1827 * A parameter is definitely not blittable if it has the IL 'reference'
1828 * constraint, or if it has a class specified as a parent. If it has an IL
1829 * 'valuetype' constraint or no constraint at all or only interfaces as
1830 * constraints, we return FALSE because the parameter may be instantiated both
1831 * with blittable and non-blittable types.
1833 * If the paramter is a generic sharing parameter, we look at its gshared_constraint->blittable bit.
1835 static gboolean
1836 mono_class_is_gparam_with_nonblittable_parent (MonoClass *klass)
1838 MonoType *type = m_class_get_byval_arg (klass);
1839 g_assert (mono_type_is_generic_parameter (type));
1840 MonoGenericParam *gparam = type->data.generic_param;
1841 if ((mono_generic_param_info (gparam)->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0)
1842 return TRUE;
1843 if ((mono_generic_param_info (gparam)->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0)
1844 return FALSE;
1846 if (gparam->gshared_constraint) {
1847 MonoClass *constraint_class = mono_class_from_mono_type_internal (gparam->gshared_constraint);
1848 return !m_class_is_blittable (constraint_class);
1851 if (mono_generic_param_owner (gparam)->is_anonymous)
1852 return FALSE;
1854 /* We could have: T : U, U : Base. So have to follow the constraints. */
1855 MonoClass *parent_class = mono_generic_param_get_base_type (klass);
1856 g_assert (!MONO_CLASS_IS_INTERFACE_INTERNAL (parent_class));
1857 /* Parent can only be: System.Object, System.ValueType or some specific base class.
1859 * If the parent_class is ValueType, the valuetype constraint would be set, above, so
1860 * we wouldn't get here.
1862 * If there was a reference constraint, the parent_class would be System.Object,
1863 * but we would have returned early above.
1865 * So if we get here, there is either no base class constraint at all,
1866 * in which case parent_class would be set to System.Object, or there is none at all.
1868 return parent_class != mono_defaults.object_class;
1872 * mono_class_layout_fields:
1873 * @class: a class
1874 * @base_instance_size: base instance size
1875 * @packing_size:
1877 * This contains the common code for computing the layout of classes and sizes.
1878 * This should only be called from mono_class_setup_fields () and
1879 * typebuilder_setup_fields ().
1881 * LOCKING: Acquires the loader lock
1883 void
1884 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int explicit_size, gboolean sre)
1886 int i;
1887 const int top = mono_class_get_field_count (klass);
1888 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
1889 guint32 pass, passes, real_size;
1890 gboolean gc_aware_layout = FALSE;
1891 gboolean has_static_fields = FALSE;
1892 gboolean has_references = FALSE;
1893 gboolean has_static_refs = FALSE;
1894 MonoClassField *field;
1895 gboolean blittable;
1896 int instance_size = base_instance_size;
1897 int element_size = -1;
1898 int class_size, min_align;
1899 int *field_offsets;
1900 gboolean *fields_has_references;
1903 * We want to avoid doing complicated work inside locks, so we compute all the required
1904 * information and write it to @klass inside a lock.
1906 if (klass->fields_inited)
1907 return;
1909 if ((packing_size & 0xffffff00) != 0) {
1910 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
1911 return;
1914 if (klass->parent) {
1915 min_align = klass->parent->min_align;
1916 /* we use | since it may have been set already */
1917 has_references = klass->has_references | klass->parent->has_references;
1918 } else {
1919 min_align = 1;
1921 /* We can't really enable 16 bytes alignment until the GC supports it.
1922 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1923 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1924 Bug #506144 is an example of this issue.
1926 if (klass->simd_type)
1927 min_align = 16;
1931 * When we do generic sharing we need to have layout
1932 * information for open generic classes (either with a generic
1933 * context containing type variables or with a generic
1934 * container), so we don't return in that case anymore.
1937 if (klass->enumtype) {
1938 for (i = 0; i < top; i++) {
1939 field = &klass->fields [i];
1940 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1941 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (field->type);
1942 break;
1946 if (!mono_class_enum_basetype_internal (klass)) {
1947 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
1948 return;
1953 * Enable GC aware auto layout: in this mode, reference
1954 * fields are grouped together inside objects, increasing collector
1955 * performance.
1956 * Requires that all classes whose layout is known to native code be annotated
1957 * with [StructLayout (LayoutKind.Sequential)]
1958 * Value types have gc_aware_layout disabled by default, as per
1959 * what the default is for other runtimes.
1961 /* corlib is missing [StructLayout] directives in many places */
1962 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1963 if (!klass->valuetype)
1964 gc_aware_layout = TRUE;
1967 /* Compute klass->blittable */
1968 blittable = TRUE;
1969 if (klass->parent)
1970 blittable = klass->parent->blittable;
1971 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
1972 blittable = FALSE;
1973 for (i = 0; i < top; i++) {
1974 field = &klass->fields [i];
1976 if (mono_field_is_deleted (field))
1977 continue;
1978 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1979 continue;
1980 if (blittable) {
1981 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1982 blittable = FALSE;
1983 } else if (mono_type_is_generic_parameter (field->type) &&
1984 mono_class_is_gparam_with_nonblittable_parent (mono_class_from_mono_type_internal (field->type))) {
1985 blittable = FALSE;
1986 } else {
1987 MonoClass *field_class = mono_class_from_mono_type_internal (field->type);
1988 if (field_class) {
1989 mono_class_setup_fields (field_class);
1990 if (mono_class_has_failure (field_class)) {
1991 ERROR_DECL (field_error);
1992 mono_error_set_for_class_failure (field_error, field_class);
1993 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (field_error));
1994 mono_error_cleanup (field_error);
1995 break;
1998 if (!field_class || !field_class->blittable)
1999 blittable = FALSE;
2002 if (klass->enumtype)
2003 blittable = klass->element_class->blittable;
2005 if (mono_class_has_failure (klass))
2006 return;
2007 if (klass == mono_defaults.string_class)
2008 blittable = FALSE;
2010 /* Compute klass->has_references */
2012 * Process non-static fields first, since static fields might recursively
2013 * refer to the class itself.
2015 for (i = 0; i < top; i++) {
2016 MonoType *ftype;
2018 field = &klass->fields [i];
2020 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
2021 ftype = mono_type_get_underlying_type (field->type);
2022 ftype = mono_type_get_basic_type_from_generic (ftype);
2023 if (type_has_references (klass, ftype))
2024 has_references = TRUE;
2029 * Compute field layout and total size (not considering static fields)
2031 field_offsets = g_new0 (int, top);
2032 fields_has_references = g_new0 (gboolean, top);
2033 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
2034 switch (layout) {
2035 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
2036 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
2037 if (gc_aware_layout)
2038 passes = 2;
2039 else
2040 passes = 1;
2042 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
2043 passes = 1;
2045 if (klass->parent) {
2046 mono_class_setup_fields (klass->parent);
2047 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
2048 return;
2049 real_size = klass->parent->instance_size;
2050 } else {
2051 real_size = MONO_ABI_SIZEOF (MonoObject);
2054 for (pass = 0; pass < passes; ++pass) {
2055 for (i = 0; i < top; i++){
2056 gint32 align;
2057 guint32 size;
2058 MonoType *ftype;
2060 field = &klass->fields [i];
2062 if (mono_field_is_deleted (field))
2063 continue;
2064 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2065 continue;
2067 ftype = mono_type_get_underlying_type (field->type);
2068 ftype = mono_type_get_basic_type_from_generic (ftype);
2069 if (gc_aware_layout) {
2070 fields_has_references [i] = type_has_references (klass, ftype);
2071 if (fields_has_references [i]) {
2072 if (pass == 1)
2073 continue;
2074 } else {
2075 if (pass == 0)
2076 continue;
2080 if ((top == 1) && (instance_size == MONO_ABI_SIZEOF (MonoObject)) &&
2081 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
2082 /* This field is a hack inserted by MCS to empty structures */
2083 continue;
2086 size = mono_type_size (field->type, &align);
2088 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
2089 align = packing_size ? MIN (packing_size, align): align;
2090 /* if the field has managed references, we need to force-align it
2091 * see bug #77788
2093 if (type_has_references (klass, ftype))
2094 align = MAX (align, TARGET_SIZEOF_VOID_P);
2096 min_align = MAX (align, min_align);
2097 field_offsets [i] = real_size;
2098 if (align) {
2099 field_offsets [i] += align - 1;
2100 field_offsets [i] &= ~(align - 1);
2102 /*TypeBuilders produce all sort of weird things*/
2103 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
2104 real_size = field_offsets [i] + size;
2107 instance_size = MAX (real_size, instance_size);
2109 if (instance_size & (min_align - 1)) {
2110 instance_size += min_align - 1;
2111 instance_size &= ~(min_align - 1);
2114 break;
2115 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
2116 real_size = 0;
2117 for (i = 0; i < top; i++) {
2118 gint32 align;
2119 guint32 size;
2120 MonoType *ftype;
2122 field = &klass->fields [i];
2125 * There must be info about all the fields in a type if it
2126 * uses explicit layout.
2128 if (mono_field_is_deleted (field))
2129 continue;
2130 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2131 continue;
2133 size = mono_type_size (field->type, &align);
2134 align = packing_size ? MIN (packing_size, align): align;
2135 min_align = MAX (align, min_align);
2137 if (sre) {
2138 /* Already set by typebuilder_setup_fields () */
2139 field_offsets [i] = field->offset + MONO_ABI_SIZEOF (MonoObject);
2140 } else {
2141 int idx = first_field_idx + i;
2142 guint32 offset;
2143 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
2144 field_offsets [i] = offset + MONO_ABI_SIZEOF (MonoObject);
2146 ftype = mono_type_get_underlying_type (field->type);
2147 ftype = mono_type_get_basic_type_from_generic (ftype);
2148 if (type_has_references (klass, ftype)) {
2149 if (field_offsets [i] % TARGET_SIZEOF_VOID_P) {
2150 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
2155 * Calc max size.
2157 real_size = MAX (real_size, size + field_offsets [i]);
2160 /* check for incorrectly aligned or overlapped by a non-object field */
2161 #ifdef ENABLE_NETCORE
2162 guint8 *layout_check;
2163 if (has_references) {
2164 layout_check = g_new0 (guint8, real_size);
2165 for (i = 0; i < top && !mono_class_has_failure (klass); i++) {
2166 field = &klass->fields [i];
2167 if (!field)
2168 continue;
2169 if (mono_field_is_deleted (field))
2170 continue;
2171 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2172 continue;
2173 int align = 0;
2174 int size = mono_type_size (field->type, &align);
2175 MonoType *ftype = mono_type_get_underlying_type (field->type);
2176 ftype = mono_type_get_basic_type_from_generic (ftype);
2177 guint8 type = type_has_references (klass, ftype) ? 1 : 2;
2178 for (int j = 0; j < size; j++) {
2179 if (layout_check [field_offsets [i] + j] != 0 && layout_check [field_offsets [i] + j] != type) {
2180 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->offset);
2181 break;
2183 layout_check [field_offsets [i] + j] = type;
2186 g_free (layout_check);
2188 #endif
2190 instance_size = MAX (real_size, instance_size);
2191 if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) {
2192 if (instance_size & (min_align - 1)) {
2193 instance_size += min_align - 1;
2194 instance_size &= ~(min_align - 1);
2197 break;
2201 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
2203 * This leads to all kinds of problems with nested structs, so only
2204 * enable it when a MONO_DEBUG property is set.
2206 * For small structs, set min_align to at least the struct size to improve
2207 * performance, and since the JIT memset/memcpy code assumes this and generates
2208 * unaligned accesses otherwise. See #78990 for a testcase.
2210 if (mono_align_small_structs && top) {
2211 if (instance_size <= MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer))
2212 min_align = MAX (min_align, instance_size - MONO_ABI_SIZEOF (MonoObject));
2216 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
2217 if (klass_byval_arg->type == MONO_TYPE_VAR || klass_byval_arg->type == MONO_TYPE_MVAR)
2218 instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_size (klass_byval_arg, &min_align);
2219 else if (klass_byval_arg->type == MONO_TYPE_PTR)
2220 instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
2222 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
2223 element_size = mono_class_array_element_size (klass->element_class);
2225 /* Publish the data */
2226 mono_loader_lock ();
2227 if (klass->instance_size && !klass->image->dynamic && klass_byval_arg->type != MONO_TYPE_FNPTR) {
2228 /* Might be already set using cached info */
2229 if (klass->instance_size != instance_size) {
2230 /* Emit info to help debugging */
2231 g_print ("%s\n", mono_class_full_name (klass));
2232 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
2233 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
2234 g_print ("%d %d\n", klass->min_align, min_align);
2235 for (i = 0; i < top; ++i) {
2236 field = &klass->fields [i];
2237 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2238 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
2241 g_assert (klass->instance_size == instance_size);
2242 } else {
2243 klass->instance_size = instance_size;
2245 klass->blittable = blittable;
2246 klass->has_references = has_references;
2247 klass->packing_size = packing_size;
2248 klass->min_align = min_align;
2249 for (i = 0; i < top; ++i) {
2250 field = &klass->fields [i];
2251 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2252 klass->fields [i].offset = field_offsets [i];
2255 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
2256 klass->sizes.element_size = element_size;
2258 mono_memory_barrier ();
2259 klass->size_inited = 1;
2260 mono_loader_unlock ();
2263 * Compute static field layout and size
2264 * Static fields can reference the class itself, so this has to be
2265 * done after instance_size etc. are initialized.
2267 class_size = 0;
2268 for (i = 0; i < top; i++) {
2269 gint32 align;
2270 guint32 size;
2272 field = &klass->fields [i];
2274 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
2275 continue;
2276 if (mono_field_is_deleted (field))
2277 continue;
2279 if (mono_type_has_exceptions (field->type)) {
2280 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
2281 break;
2284 has_static_fields = TRUE;
2286 size = mono_type_size (field->type, &align);
2287 field_offsets [i] = class_size;
2288 /*align is always non-zero here*/
2289 field_offsets [i] += align - 1;
2290 field_offsets [i] &= ~(align - 1);
2291 class_size = field_offsets [i] + size;
2294 if (has_static_fields && class_size == 0)
2295 /* Simplify code which depends on class_size != 0 if the class has static fields */
2296 class_size = 8;
2298 /* Compute klass->has_static_refs */
2299 has_static_refs = FALSE;
2300 for (i = 0; i < top; i++) {
2301 MonoType *ftype;
2303 field = &klass->fields [i];
2305 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2306 ftype = mono_type_get_underlying_type (field->type);
2307 ftype = mono_type_get_basic_type_from_generic (ftype);
2308 if (type_has_references (klass, ftype))
2309 has_static_refs = TRUE;
2313 /*valuetypes can't be neither bigger than 1Mb or empty. */
2314 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + MONO_ABI_SIZEOF (MonoObject)))) {
2315 /* Special case compiler generated types */
2316 /* Hard to check for [CompilerGenerated] here */
2317 if (!strstr (klass->name, "StaticArrayInitTypeSize") && !strstr (klass->name, "$ArrayType"))
2318 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
2321 // Weak field support
2323 // FIXME:
2324 // - generic instances
2325 // - Disallow on structs/static fields/nonref fields
2326 gboolean has_weak_fields = FALSE;
2328 if (mono_class_has_static_metadata (klass)) {
2329 for (MonoClass *p = klass; p != NULL; p = p->parent) {
2330 gpointer iter = NULL;
2331 guint32 first_field_idx = mono_class_get_first_field_idx (p);
2333 while ((field = mono_class_get_fields_internal (p, &iter))) {
2334 guint32 field_idx = first_field_idx + (field - p->fields);
2335 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
2336 has_weak_fields = TRUE;
2337 mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
2344 * Check that any fields of IsByRefLike type are instance
2345 * fields and only inside other IsByRefLike structs.
2347 * (Has to be done late because we call
2348 * mono_class_from_mono_type_internal which may recursively
2349 * refer to the current class)
2351 gboolean allow_isbyreflike_fields = m_class_is_byreflike (klass);
2352 for (i = 0; i < top; i++) {
2353 field = &klass->fields [i];
2355 if (mono_field_is_deleted (field))
2356 continue;
2357 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2358 continue;
2359 MonoClass *field_class = NULL;
2360 /* have to be careful not to recursively invoke mono_class_init on a static field.
2361 * for example - if the field is an array of a subclass of klass, we can loop.
2363 switch (field->type->type) {
2364 case MONO_TYPE_TYPEDBYREF:
2365 case MONO_TYPE_VALUETYPE:
2366 case MONO_TYPE_GENERICINST:
2367 field_class = mono_class_from_mono_type_internal (field->type);
2368 break;
2369 default:
2370 break;
2372 if (!field_class || !m_class_is_byreflike (field_class))
2373 continue;
2374 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
2375 mono_class_set_type_load_failure (klass, "Static ByRefLike field '%s' is not allowed", field->name);
2376 return;
2377 } else {
2378 /* instance field */
2379 if (allow_isbyreflike_fields)
2380 continue;
2381 mono_class_set_type_load_failure (klass, "Instance ByRefLike field '%s' not in a ref struct", field->name);
2382 return;
2386 /* Publish the data */
2387 mono_loader_lock ();
2388 if (!klass->rank)
2389 klass->sizes.class_size = class_size;
2390 klass->has_static_refs = has_static_refs;
2391 klass->has_weak_fields = has_weak_fields;
2392 for (i = 0; i < top; ++i) {
2393 field = &klass->fields [i];
2395 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2396 field->offset = field_offsets [i];
2398 mono_memory_barrier ();
2399 klass->fields_inited = 1;
2400 mono_loader_unlock ();
2402 g_free (field_offsets);
2403 g_free (fields_has_references);
2406 static int finalize_slot = -1;
2408 static void
2409 initialize_object_slots (MonoClass *klass)
2411 int i;
2413 if (klass != mono_defaults.object_class || finalize_slot >= 0)
2414 return;
2416 mono_class_setup_vtable (klass);
2418 for (i = 0; i < klass->vtable_size; ++i) {
2419 if (!strcmp (klass->vtable [i]->name, "Finalize")) {
2420 int const j = finalize_slot;
2421 g_assert (j == -1 || j == i);
2422 finalize_slot = i;
2426 g_assert (finalize_slot >= 0);
2430 mono_class_get_object_finalize_slot ()
2432 return finalize_slot;
2435 MonoMethod *
2436 mono_class_get_default_finalize_method ()
2438 int const i = finalize_slot;
2439 return (i < 0) ? NULL : mono_defaults.object_class->vtable [i];
2442 typedef struct {
2443 MonoMethod *array_method;
2444 char *name;
2445 } GenericArrayMethodInfo;
2447 static int generic_array_method_num = 0;
2448 static GenericArrayMethodInfo *generic_array_method_info = NULL;
2450 static void
2451 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
2453 MonoGenericContext tmp_context;
2454 MonoGenericClass *gclass;
2455 int i;
2457 // The interface can sometimes be a GTD in cases like IList
2458 // See: https://github.com/mono/mono/issues/7095#issuecomment-470465597
2459 if (mono_class_is_gtd (iface)) {
2460 MonoType *ty = mono_class_gtd_get_canonical_inst (iface);
2461 g_assert (ty->type == MONO_TYPE_GENERICINST);
2462 gclass = ty->data.generic_class;
2463 } else
2464 gclass = mono_class_get_generic_class (iface);
2466 tmp_context.class_inst = NULL;
2467 tmp_context.method_inst = gclass->context.class_inst;
2468 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
2470 for (i = 0; i < generic_array_method_num; i++) {
2471 ERROR_DECL (error);
2472 MonoMethod *m = generic_array_method_info [i].array_method;
2473 MonoMethod *inflated, *helper;
2475 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, error);
2476 mono_error_assert_ok (error);
2477 helper = (MonoMethod*)g_hash_table_lookup (cache, inflated);
2478 if (!helper) {
2479 helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
2480 g_hash_table_insert (cache, inflated, helper);
2482 methods [pos ++] = helper;
2486 static int
2487 generic_array_methods (MonoClass *klass)
2489 int i, count_generic = 0, mcount;
2490 GList *list = NULL, *tmp;
2491 if (generic_array_method_num)
2492 return generic_array_method_num;
2493 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
2494 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
2495 mcount = mono_class_get_method_count (klass->parent);
2496 for (i = 0; i < mcount; i++) {
2497 MonoMethod *m = klass->parent->methods [i];
2498 if (!strncmp (m->name, "InternalArray__", 15)) {
2499 count_generic++;
2500 list = g_list_prepend (list, m);
2503 list = g_list_reverse (list);
2504 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
2505 i = 0;
2506 for (tmp = list; tmp; tmp = tmp->next) {
2507 const char *mname, *iname;
2508 gchar *name;
2509 MonoMethod *m = (MonoMethod *)tmp->data;
2510 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
2511 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
2513 generic_array_method_info [i].array_method = m;
2514 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
2515 iname = "System.Collections.Generic.ICollection`1.";
2516 mname = m->name + 27;
2517 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
2518 iname = "System.Collections.Generic.IEnumerable`1.";
2519 mname = m->name + 27;
2520 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
2521 iname = "System.Collections.Generic.IReadOnlyList`1.";
2522 mname = m->name + strlen (ireadonlylist_prefix);
2523 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
2524 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
2525 mname = m->name + strlen (ireadonlycollection_prefix);
2526 } else if (!strncmp (m->name, "InternalArray__", 15)) {
2527 iname = "System.Collections.Generic.IList`1.";
2528 mname = m->name + 15;
2529 } else {
2530 g_assert_not_reached ();
2533 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
2534 strcpy (name, iname);
2535 strcpy (name + strlen (iname), mname);
2536 generic_array_method_info [i].name = name;
2537 i++;
2539 /*g_print ("array generic methods: %d\n", count_generic);*/
2541 generic_array_method_num = count_generic;
2542 g_list_free (list);
2543 return generic_array_method_num;
2546 static int array_get_method_count (MonoClass *klass)
2548 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
2549 if (klass_byval_arg->type == MONO_TYPE_ARRAY)
2550 /* Regular array */
2551 /* ctor([int32]*rank) */
2552 /* ctor([int32]*rank*2) */
2553 /* Get */
2554 /* Set */
2555 /* Address */
2556 return 5;
2557 else if (klass_byval_arg->type == MONO_TYPE_SZARRAY && klass->rank == 1 && klass->element_class->rank)
2558 /* Jagged arrays are typed as MONO_TYPE_SZARRAY but have an extra ctor in .net which creates an array of arrays */
2559 /* ctor([int32]) */
2560 /* ctor([int32], [int32]) */
2561 /* Get */
2562 /* Set */
2563 /* Address */
2564 return 5;
2565 else
2566 /* Vectors don't have additional constructor since a zero lower bound is assumed */
2567 /* ctor([int32]*rank) */
2568 /* Get */
2569 /* Set */
2570 /* Address */
2571 return 4;
2574 static gboolean array_supports_additional_ctor_method (MonoClass *klass)
2576 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
2577 if (klass_byval_arg->type == MONO_TYPE_ARRAY)
2578 /* Regular array */
2579 return TRUE;
2580 else if (klass_byval_arg->type == MONO_TYPE_SZARRAY && klass->rank == 1 && klass->element_class->rank)
2581 /* Jagged array */
2582 return TRUE;
2583 else
2584 /* Vector */
2585 return FALSE;
2589 * Global pool of interface IDs, represented as a bitset.
2590 * LOCKING: Protected by the classes lock.
2592 static MonoBitSet *global_interface_bitset = NULL;
2595 * mono_unload_interface_ids:
2596 * @bitset: bit set of interface IDs
2598 * When an image is unloaded, the interface IDs associated with
2599 * the image are put back in the global pool of IDs so the numbers
2600 * can be reused.
2602 void
2603 mono_unload_interface_ids (MonoBitSet *bitset)
2605 classes_lock ();
2606 mono_bitset_sub (global_interface_bitset, bitset);
2607 classes_unlock ();
2610 void
2611 mono_unload_interface_id (MonoClass *klass)
2613 if (global_interface_bitset && klass->interface_id) {
2614 classes_lock ();
2615 mono_bitset_clear (global_interface_bitset, klass->interface_id);
2616 classes_unlock ();
2621 * mono_get_unique_iid:
2622 * \param klass interface
2624 * Assign a unique integer ID to the interface represented by \p klass.
2625 * The ID will positive and as small as possible.
2626 * LOCKING: Acquires the classes lock.
2627 * \returns The new ID.
2629 static guint32
2630 mono_get_unique_iid (MonoClass *klass)
2632 int iid;
2634 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
2636 classes_lock ();
2638 if (!global_interface_bitset) {
2639 global_interface_bitset = mono_bitset_new (128, 0);
2640 mono_bitset_set (global_interface_bitset, 0); //don't let 0 be a valid iid
2643 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2644 if (iid < 0) {
2645 int old_size = mono_bitset_size (global_interface_bitset);
2646 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2647 mono_bitset_free (global_interface_bitset);
2648 global_interface_bitset = new_set;
2649 iid = old_size;
2651 mono_bitset_set (global_interface_bitset, iid);
2652 /* set the bit also in the per-image set */
2653 if (!mono_class_is_ginst (klass)) {
2654 if (klass->image->interface_bitset) {
2655 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
2656 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
2657 mono_bitset_free (klass->image->interface_bitset);
2658 klass->image->interface_bitset = new_set;
2660 } else {
2661 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2663 mono_bitset_set (klass->image->interface_bitset, iid);
2666 classes_unlock ();
2668 #ifndef MONO_SMALL_CONFIG
2669 if (mono_print_vtable) {
2670 int generic_id;
2671 char *type_name = mono_type_full_name (m_class_get_byval_arg (klass));
2672 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
2673 if (gklass && !gklass->context.class_inst->is_open) {
2674 generic_id = gklass->context.class_inst->id;
2675 g_assert (generic_id != 0);
2676 } else {
2677 generic_id = 0;
2679 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->assembly_name, type_name, generic_id);
2680 g_free (type_name);
2682 #endif
2684 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
2685 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
2686 g_assert (iid < INT_MAX);
2687 return iid;
2691 * mono_class_init_internal:
2692 * \param klass the class to initialize
2694 * Compute the \c instance_size, \c class_size and other infos that cannot be
2695 * computed at \c mono_class_get time. Also compute vtable_size if possible.
2696 * Initializes the following fields in \p klass:
2697 * - all the fields initialized by \c mono_class_init_sizes
2698 * - has_cctor
2699 * - ghcimpl
2700 * - inited
2702 * LOCKING: Acquires the loader lock.
2704 * \returns TRUE on success or FALSE if there was a problem in loading
2705 * the type (incorrect assemblies, missing assemblies, methods, etc).
2707 gboolean
2708 mono_class_init_internal (MonoClass *klass)
2710 int i, vtable_size = 0, array_method_count = 0;
2711 MonoCachedClassInfo cached_info;
2712 gboolean has_cached_info;
2713 gboolean locked = FALSE;
2714 gboolean ghcimpl = FALSE;
2715 gboolean has_cctor = FALSE;
2716 int first_iface_slot = 0;
2718 g_assert (klass);
2720 /* Double-checking locking pattern */
2721 if (klass->inited || mono_class_has_failure (klass))
2722 return !mono_class_has_failure (klass);
2724 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
2727 * This function can recursively call itself.
2729 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
2730 if (g_slist_find (init_list, klass)) {
2731 mono_class_set_type_load_failure (klass, "Recursive type definition detected %s.%s", klass->name_space, klass->name);
2732 goto leave_no_init_pending;
2734 init_list = g_slist_prepend (init_list, klass);
2735 mono_native_tls_set_value (init_pending_tls_id, init_list);
2738 * We want to avoid doing complicated work inside locks, so we compute all the required
2739 * information and write it to @klass inside a lock.
2742 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
2743 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
2744 goto leave;
2747 MonoType *klass_byval_arg;
2748 klass_byval_arg = m_class_get_byval_arg (klass);
2749 if (klass_byval_arg->type == MONO_TYPE_ARRAY || klass_byval_arg->type == MONO_TYPE_SZARRAY) {
2750 MonoClass *element_class = klass->element_class;
2751 MonoClass *cast_class = klass->cast_class;
2753 if (!element_class->inited)
2754 mono_class_init_internal (element_class);
2755 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
2756 goto leave;
2757 if (!cast_class->inited)
2758 mono_class_init_internal (cast_class);
2759 if (mono_class_set_type_load_failure_causedby_class (klass, cast_class, "Could not load array cast class"))
2760 goto leave;
2763 UnlockedIncrement (&mono_stats.initialized_class_count);
2765 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
2766 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2768 mono_class_init_internal (gklass);
2769 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
2770 goto leave;
2772 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass))
2773 mono_class_setup_interface_id (klass);
2776 if (klass->parent && !klass->parent->inited)
2777 mono_class_init_internal (klass->parent);
2779 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
2781 /* Compute instance size etc. */
2782 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
2783 if (mono_class_has_failure (klass))
2784 goto leave;
2786 mono_class_setup_supertypes (klass);
2788 initialize_object_slots (klass);
2791 * Initialize the rest of the data without creating a generic vtable if possible.
2792 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
2793 * also avoid computing a generic vtable.
2795 if (has_cached_info) {
2796 /* AOT case */
2797 vtable_size = cached_info.vtable_size;
2798 ghcimpl = cached_info.ghcimpl;
2799 has_cctor = cached_info.has_cctor;
2800 } else if (klass->rank == 1 && klass_byval_arg->type == MONO_TYPE_SZARRAY) {
2801 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
2802 * The first slot if for array with.
2804 static int szarray_vtable_size[3] = { 0 };
2806 int slot;
2808 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass))))
2809 slot = 0;
2810 else if (klass->element_class->enumtype)
2811 slot = 1;
2812 else
2813 slot = 2;
2815 /* SZARRAY case */
2816 if (!szarray_vtable_size [slot]) {
2817 mono_class_setup_vtable (klass);
2818 szarray_vtable_size [slot] = klass->vtable_size;
2819 vtable_size = klass->vtable_size;
2820 } else {
2821 vtable_size = szarray_vtable_size[slot];
2823 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
2824 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2826 /* Generic instance case */
2827 ghcimpl = gklass->ghcimpl;
2828 has_cctor = gklass->has_cctor;
2830 mono_class_setup_vtable (gklass);
2831 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
2832 goto leave;
2834 vtable_size = gklass->vtable_size;
2835 } else {
2836 /* General case */
2838 /* C# doesn't allow interfaces to have cctors */
2839 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->image != mono_defaults.corlib) {
2840 MonoMethod *cmethod = NULL;
2842 if (mono_class_is_ginst (klass)) {
2843 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2845 /* Generic instance case */
2846 ghcimpl = gklass->ghcimpl;
2847 has_cctor = gklass->has_cctor;
2848 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
2849 cmethod = mono_find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
2850 /* The find_method function ignores the 'flags' argument */
2851 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
2852 has_cctor = 1;
2853 } else {
2854 mono_class_setup_methods (klass);
2855 if (mono_class_has_failure (klass))
2856 goto leave;
2858 int mcount = mono_class_get_method_count (klass);
2859 for (i = 0; i < mcount; ++i) {
2860 MonoMethod *method = klass->methods [i];
2861 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
2862 (strcmp (".cctor", method->name) == 0)) {
2863 has_cctor = 1;
2864 break;
2871 if (klass->rank) {
2872 array_method_count = array_get_method_count (klass);
2874 if (klass->interface_count) {
2875 int count_generic = generic_array_methods (klass);
2876 array_method_count += klass->interface_count * count_generic;
2880 if (klass->parent) {
2881 if (!klass->parent->vtable_size)
2882 mono_class_setup_vtable (klass->parent);
2883 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
2884 goto leave;
2885 g_assert (klass->parent->vtable_size);
2886 first_iface_slot = klass->parent->vtable_size;
2887 if (mono_class_setup_need_stelemref_method (klass))
2888 ++first_iface_slot;
2892 * Do the actual changes to @klass inside the loader lock
2894 mono_loader_lock ();
2895 locked = TRUE;
2897 if (klass->inited || mono_class_has_failure (klass)) {
2898 /* Somebody might have gotten in before us */
2899 goto leave;
2902 UnlockedIncrement (&mono_stats.initialized_class_count);
2904 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
2905 UnlockedIncrement (&mono_stats.generic_class_count);
2907 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
2908 klass->nested_classes_inited = TRUE;
2909 klass->ghcimpl = ghcimpl;
2910 klass->has_cctor = has_cctor;
2911 if (vtable_size)
2912 klass->vtable_size = vtable_size;
2913 if (has_cached_info) {
2914 klass->has_finalize = cached_info.has_finalize;
2915 klass->has_finalize_inited = TRUE;
2917 if (klass->rank)
2918 mono_class_set_method_count (klass, array_method_count);
2920 mono_loader_unlock ();
2921 locked = FALSE;
2923 mono_class_setup_interface_offsets_internal (klass, first_iface_slot, TRUE);
2925 if (mono_security_core_clr_enabled ())
2926 mono_security_core_clr_check_inheritance (klass);
2928 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
2929 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
2931 goto leave;
2933 leave:
2934 init_list = (GSList*)mono_native_tls_get_value (init_pending_tls_id);
2935 init_list = g_slist_remove (init_list, klass);
2936 mono_native_tls_set_value (init_pending_tls_id, init_list);
2938 leave_no_init_pending:
2939 if (locked)
2940 mono_loader_unlock ();
2942 /* Leave this for last */
2943 mono_loader_lock ();
2944 klass->inited = 1;
2945 mono_loader_unlock ();
2947 return !mono_class_has_failure (klass);
2950 gboolean
2951 mono_class_init_checked (MonoClass *klass, MonoError *error)
2953 error_init (error);
2954 gboolean const success = mono_class_init_internal (klass);
2955 if (!success)
2956 mono_error_set_for_class_failure (error, klass);
2957 return success;
2960 #ifndef DISABLE_COM
2962 * COM initialization is delayed until needed.
2963 * However when a [ComImport] attribute is present on a type it will trigger
2964 * the initialization. This is not a problem unless the BCL being executed
2965 * lacks the types that COM depends on (e.g. Variant on Silverlight).
2967 static void
2968 init_com_from_comimport (MonoClass *klass)
2970 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
2971 if (mono_security_core_clr_enabled ()) {
2972 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
2973 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
2974 /* but it can not be made available for application (i.e. user code) since all COM calls
2975 * are considered native calls. In this case we fail with a TypeLoadException (just like
2976 * Silverlight 2 does */
2977 mono_class_set_type_load_failure (klass, "");
2978 return;
2982 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
2984 #endif /*DISABLE_COM*/
2987 * LOCKING: this assumes the loader lock is held
2989 void
2990 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
2992 gboolean system_namespace;
2993 gboolean is_corlib = mono_is_corlib_image (klass->image);
2995 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
2997 /* if root of the hierarchy */
2998 if (system_namespace && !strcmp (klass->name, "Object")) {
2999 klass->parent = NULL;
3000 klass->instance_size = MONO_ABI_SIZEOF (MonoObject);
3001 return;
3003 if (!strcmp (klass->name, "<Module>")) {
3004 klass->parent = NULL;
3005 klass->instance_size = 0;
3006 return;
3009 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3010 /* Imported COM Objects always derive from __ComObject. */
3011 #ifndef DISABLE_COM
3012 if (MONO_CLASS_IS_IMPORT (klass)) {
3013 init_com_from_comimport (klass);
3014 if (parent == mono_defaults.object_class)
3015 parent = mono_class_get_com_object_class ();
3017 #endif
3018 if (!parent) {
3019 /* set the parent to something useful and safe, but mark the type as broken */
3020 parent = mono_defaults.object_class;
3021 mono_class_set_type_load_failure (klass, "");
3022 g_assert (parent);
3025 klass->parent = parent;
3027 if (mono_class_is_ginst (parent) && !parent->name) {
3029 * If the parent is a generic instance, we may get
3030 * called before it is fully initialized, especially
3031 * before it has its name.
3033 return;
3036 #ifndef DISABLE_REMOTING
3037 klass->marshalbyref = parent->marshalbyref;
3038 klass->contextbound = parent->contextbound;
3039 #endif
3041 klass->delegate = parent->delegate;
3043 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
3044 mono_class_set_is_com_object (klass);
3046 if (system_namespace) {
3047 #ifndef DISABLE_REMOTING
3048 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
3049 klass->marshalbyref = 1;
3051 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
3052 klass->contextbound = 1;
3053 #endif
3054 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
3055 klass->delegate = 1;
3058 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
3059 (strcmp (klass->parent->name_space, "System") == 0)))
3060 klass->valuetype = 1;
3061 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
3062 klass->valuetype = klass->enumtype = 1;
3064 /*klass->enumtype = klass->parent->enumtype; */
3065 } else {
3066 /* initialize com types if COM interfaces are present */
3067 #ifndef DISABLE_COM
3068 if (MONO_CLASS_IS_IMPORT (klass))
3069 init_com_from_comimport (klass);
3070 #endif
3071 klass->parent = NULL;
3076 /* Locking: must be called with the loader lock held. */
3077 void
3078 mono_class_setup_interface_id_nolock (MonoClass *klass)
3080 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->interface_id)
3081 return;
3082 klass->interface_id = mono_get_unique_iid (klass);
3084 if (mono_is_corlib_image (klass->image) && !strcmp (m_class_get_name_space (klass), "System.Collections.Generic")) {
3085 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
3086 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
3087 * MS returns diferrent types based on which instance is called. For example:
3088 * object obj = new byte[10][];
3089 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
3090 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
3091 * a != b ==> true
3093 const char *name = m_class_get_name (klass);
3094 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
3095 klass->is_array_special_interface = 1;
3101 * LOCKING: this assumes the loader lock is held
3103 void
3104 mono_class_setup_mono_type (MonoClass *klass)
3106 const char *name = klass->name;
3107 const char *nspace = klass->name_space;
3108 gboolean is_corlib = mono_is_corlib_image (klass->image);
3110 klass->this_arg.byref = 1;
3111 klass->this_arg.data.klass = klass;
3112 klass->this_arg.type = MONO_TYPE_CLASS;
3113 klass->_byval_arg.data.klass = klass;
3114 klass->_byval_arg.type = MONO_TYPE_CLASS;
3116 if (is_corlib && !strcmp (nspace, "System")) {
3117 if (!strcmp (name, "ValueType")) {
3119 * do not set the valuetype bit for System.ValueType.
3120 * klass->valuetype = 1;
3122 klass->blittable = TRUE;
3123 } else if (!strcmp (name, "Enum")) {
3125 * do not set the valuetype bit for System.Enum.
3126 * klass->valuetype = 1;
3128 klass->valuetype = 0;
3129 klass->enumtype = 0;
3130 } else if (!strcmp (name, "Object")) {
3131 klass->_byval_arg.type = MONO_TYPE_OBJECT;
3132 klass->this_arg.type = MONO_TYPE_OBJECT;
3133 } else if (!strcmp (name, "String")) {
3134 klass->_byval_arg.type = MONO_TYPE_STRING;
3135 klass->this_arg.type = MONO_TYPE_STRING;
3136 } else if (!strcmp (name, "TypedReference")) {
3137 klass->_byval_arg.type = MONO_TYPE_TYPEDBYREF;
3138 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
3142 if (klass->valuetype) {
3143 int t = MONO_TYPE_VALUETYPE;
3145 if (is_corlib && !strcmp (nspace, "System")) {
3146 switch (*name) {
3147 case 'B':
3148 if (!strcmp (name, "Boolean")) {
3149 t = MONO_TYPE_BOOLEAN;
3150 } else if (!strcmp(name, "Byte")) {
3151 t = MONO_TYPE_U1;
3152 klass->blittable = TRUE;
3154 break;
3155 case 'C':
3156 if (!strcmp (name, "Char")) {
3157 t = MONO_TYPE_CHAR;
3159 break;
3160 case 'D':
3161 if (!strcmp (name, "Double")) {
3162 t = MONO_TYPE_R8;
3163 klass->blittable = TRUE;
3165 break;
3166 case 'I':
3167 if (!strcmp (name, "Int32")) {
3168 t = MONO_TYPE_I4;
3169 klass->blittable = TRUE;
3170 } else if (!strcmp(name, "Int16")) {
3171 t = MONO_TYPE_I2;
3172 klass->blittable = TRUE;
3173 } else if (!strcmp(name, "Int64")) {
3174 t = MONO_TYPE_I8;
3175 klass->blittable = TRUE;
3176 } else if (!strcmp(name, "IntPtr")) {
3177 t = MONO_TYPE_I;
3178 klass->blittable = TRUE;
3180 break;
3181 case 'S':
3182 if (!strcmp (name, "Single")) {
3183 t = MONO_TYPE_R4;
3184 klass->blittable = TRUE;
3185 } else if (!strcmp(name, "SByte")) {
3186 t = MONO_TYPE_I1;
3187 klass->blittable = TRUE;
3189 break;
3190 case 'U':
3191 if (!strcmp (name, "UInt32")) {
3192 t = MONO_TYPE_U4;
3193 klass->blittable = TRUE;
3194 } else if (!strcmp(name, "UInt16")) {
3195 t = MONO_TYPE_U2;
3196 klass->blittable = TRUE;
3197 } else if (!strcmp(name, "UInt64")) {
3198 t = MONO_TYPE_U8;
3199 klass->blittable = TRUE;
3200 } else if (!strcmp(name, "UIntPtr")) {
3201 t = MONO_TYPE_U;
3202 klass->blittable = TRUE;
3204 break;
3205 case 'T':
3206 if (!strcmp (name, "TypedReference")) {
3207 t = MONO_TYPE_TYPEDBYREF;
3208 klass->blittable = TRUE;
3210 break;
3211 case 'V':
3212 if (!strcmp (name, "Void")) {
3213 t = MONO_TYPE_VOID;
3215 break;
3216 default:
3217 break;
3220 klass->_byval_arg.type = (MonoTypeEnum)t;
3221 klass->this_arg.type = (MonoTypeEnum)t;
3224 mono_class_setup_interface_id_nolock (klass);
3227 static MonoMethod*
3228 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
3230 MonoMethod *method;
3232 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
3233 method->klass = klass;
3234 method->flags = METHOD_ATTRIBUTE_PUBLIC;
3235 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
3236 method->signature = sig;
3237 method->name = name;
3238 method->slot = -1;
3239 /* .ctor */
3240 if (name [0] == '.') {
3241 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
3242 } else {
3243 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
3245 return method;
3249 * mono_class_setup_methods:
3250 * @class: a class
3252 * Initializes the 'methods' array in CLASS.
3253 * Calling this method should be avoided if possible since it allocates a lot
3254 * of long-living MonoMethod structures.
3255 * Methods belonging to an interface are assigned a sequential slot starting
3256 * from 0.
3258 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
3260 void
3261 mono_class_setup_methods (MonoClass *klass)
3263 int i, count;
3264 MonoMethod **methods;
3266 if (klass->methods)
3267 return;
3269 if (mono_class_is_ginst (klass)) {
3270 ERROR_DECL (error);
3271 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3273 mono_class_init_internal (gklass);
3274 if (!mono_class_has_failure (gklass))
3275 mono_class_setup_methods (gklass);
3276 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
3277 return;
3279 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
3280 count = mono_class_get_method_count (gklass);
3281 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
3283 for (i = 0; i < count; i++) {
3284 methods [i] = mono_class_inflate_generic_method_full_checked (
3285 gklass->methods [i], klass, mono_class_get_context (klass), error);
3286 if (!is_ok (error)) {
3287 char *method = mono_method_full_name (gklass->methods [i], TRUE);
3288 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (error));
3290 g_free (method);
3291 mono_error_cleanup (error);
3292 return;
3295 } else if (klass->rank) {
3296 ERROR_DECL (error);
3297 MonoMethod *amethod;
3298 MonoMethodSignature *sig;
3299 int count_generic = 0, first_generic = 0;
3300 int method_num = 0;
3302 count = array_get_method_count (klass);
3304 mono_class_setup_interfaces (klass, error);
3305 g_assert (is_ok (error)); /*FIXME can this fail for array types?*/
3307 if (klass->interface_count) {
3308 count_generic = generic_array_methods (klass);
3309 first_generic = count;
3310 count += klass->interface_count * count_generic;
3313 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
3315 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
3316 sig->ret = mono_get_void_type ();
3317 sig->pinvoke = TRUE;
3318 sig->hasthis = TRUE;
3319 for (i = 0; i < klass->rank; ++i)
3320 sig->params [i] = mono_get_int32_type ();
3322 amethod = create_array_method (klass, ".ctor", sig);
3323 methods [method_num++] = amethod;
3325 if (array_supports_additional_ctor_method (klass)) {
3326 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
3327 sig->ret = mono_get_void_type ();
3328 sig->pinvoke = TRUE;
3329 sig->hasthis = TRUE;
3330 for (i = 0; i < klass->rank * 2; ++i)
3331 sig->params [i] = mono_get_int32_type ();
3333 amethod = create_array_method (klass, ".ctor", sig);
3334 methods [method_num++] = amethod;
3337 /* element Get (idx11, [idx2, ...]) */
3338 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
3339 sig->ret = m_class_get_byval_arg (m_class_get_element_class (klass));
3340 sig->pinvoke = TRUE;
3341 sig->hasthis = TRUE;
3342 for (i = 0; i < klass->rank; ++i)
3343 sig->params [i] = mono_get_int32_type ();
3344 amethod = create_array_method (klass, "Get", sig);
3345 methods [method_num++] = amethod;
3346 /* element& Address (idx11, [idx2, ...]) */
3347 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
3348 sig->ret = &klass->element_class->this_arg;
3349 sig->pinvoke = TRUE;
3350 sig->hasthis = TRUE;
3351 for (i = 0; i < klass->rank; ++i)
3352 sig->params [i] = mono_get_int32_type ();
3353 amethod = create_array_method (klass, "Address", sig);
3354 methods [method_num++] = amethod;
3355 /* void Set (idx11, [idx2, ...], element) */
3356 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
3357 sig->ret = mono_get_void_type ();
3358 sig->pinvoke = TRUE;
3359 sig->hasthis = TRUE;
3360 for (i = 0; i < klass->rank; ++i)
3361 sig->params [i] = mono_get_int32_type ();
3362 sig->params [i] = m_class_get_byval_arg (m_class_get_element_class (klass));
3363 amethod = create_array_method (klass, "Set", sig);
3364 methods [method_num++] = amethod;
3366 GHashTable *cache = g_hash_table_new (NULL, NULL);
3367 for (i = 0; i < klass->interface_count; i++)
3368 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
3369 g_hash_table_destroy (cache);
3370 } else if (mono_class_has_static_metadata (klass)) {
3371 ERROR_DECL (error);
3372 int first_idx = mono_class_get_first_method_idx (klass);
3374 count = mono_class_get_method_count (klass);
3375 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
3376 for (i = 0; i < count; ++i) {
3377 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
3378 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, error);
3379 if (!methods [i]) {
3380 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (error));
3381 mono_error_cleanup (error);
3384 } else {
3385 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
3386 count = 0;
3389 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
3390 int slot = 0;
3391 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
3392 for (i = 0; i < count; ++i) {
3393 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
3395 if (method_is_reabstracted (methods[i]->flags)) {
3396 if (!methods [i]->is_inflated)
3397 mono_method_set_is_reabstracted (methods [i]);
3398 continue;
3400 methods [i]->slot = slot++;
3405 mono_image_lock (klass->image);
3407 if (!klass->methods) {
3408 mono_class_set_method_count (klass, count);
3410 /* Needed because of the double-checking locking pattern */
3411 mono_memory_barrier ();
3413 klass->methods = methods;
3416 mono_image_unlock (klass->image);
3420 * mono_class_setup_properties:
3422 * Initialize klass->ext.property and klass->ext.properties.
3424 * This method can fail the class.
3426 void
3427 mono_class_setup_properties (MonoClass *klass)
3429 guint startm, endm, i, j;
3430 guint32 cols [MONO_PROPERTY_SIZE];
3431 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
3432 MonoProperty *properties;
3433 guint32 last;
3434 int first, count;
3435 MonoClassPropertyInfo *info;
3437 info = mono_class_get_property_info (klass);
3438 if (info)
3439 return;
3441 if (mono_class_is_ginst (klass)) {
3442 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3444 mono_class_init_internal (gklass);
3445 mono_class_setup_properties (gklass);
3446 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
3447 return;
3449 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
3450 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
3452 for (i = 0; i < ginfo->count; i++) {
3453 ERROR_DECL (error);
3454 MonoProperty *prop = &properties [i];
3456 *prop = ginfo->properties [i];
3458 if (prop->get)
3459 prop->get = mono_class_inflate_generic_method_full_checked (
3460 prop->get, klass, mono_class_get_context (klass), error);
3461 if (prop->set)
3462 prop->set = mono_class_inflate_generic_method_full_checked (
3463 prop->set, klass, mono_class_get_context (klass), error);
3465 g_assert (is_ok (error)); /*FIXME proper error handling*/
3466 prop->parent = klass;
3469 first = ginfo->first;
3470 count = ginfo->count;
3471 } else {
3472 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
3473 count = last - first;
3475 if (count) {
3476 mono_class_setup_methods (klass);
3477 if (mono_class_has_failure (klass))
3478 return;
3481 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
3482 for (i = first; i < last; ++i) {
3483 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
3484 properties [i - first].parent = klass;
3485 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
3486 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
3488 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
3489 int first_idx = mono_class_get_first_method_idx (klass);
3490 for (j = startm; j < endm; ++j) {
3491 MonoMethod *method;
3493 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
3495 if (klass->image->uncompressed_metadata) {
3496 ERROR_DECL (error);
3497 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
3498 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
3499 mono_error_cleanup (error); /* FIXME don't swallow this error */
3500 } else {
3501 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
3504 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
3505 case METHOD_SEMANTIC_SETTER:
3506 properties [i - first].set = method;
3507 break;
3508 case METHOD_SEMANTIC_GETTER:
3509 properties [i - first].get = method;
3510 break;
3511 default:
3512 break;
3518 info = (MonoClassPropertyInfo*)mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
3519 info->first = first;
3520 info->count = count;
3521 info->properties = properties;
3522 mono_memory_barrier ();
3524 /* This might leak 'info' which was allocated from the image mempool */
3525 mono_class_set_property_info (klass, info);
3528 static MonoMethod**
3529 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
3531 MonoMethod **om, **retval;
3532 int count;
3534 for (om = methods, count = 0; *om; ++om, ++count)
3537 retval = g_new0 (MonoMethod*, count + 1);
3538 count = 0;
3539 for (om = methods, count = 0; *om; ++om, ++count) {
3540 ERROR_DECL (error);
3541 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, error);
3542 g_assert (is_ok (error)); /*FIXME proper error handling*/
3545 return retval;
3548 /*This method can fail the class.*/
3549 void
3550 mono_class_setup_events (MonoClass *klass)
3552 int first, count;
3553 guint startm, endm, i, j;
3554 guint32 cols [MONO_EVENT_SIZE];
3555 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
3556 guint32 last;
3557 MonoEvent *events;
3559 MonoClassEventInfo *info = mono_class_get_event_info (klass);
3560 if (info)
3561 return;
3563 if (mono_class_is_ginst (klass)) {
3564 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3565 MonoGenericContext *context = NULL;
3567 mono_class_setup_events (gklass);
3568 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
3569 return;
3571 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
3572 first = ginfo->first;
3573 count = ginfo->count;
3575 events = mono_class_new0 (klass, MonoEvent, count);
3577 if (count)
3578 context = mono_class_get_context (klass);
3580 for (i = 0; i < count; i++) {
3581 ERROR_DECL (error);
3582 MonoEvent *event = &events [i];
3583 MonoEvent *gevent = &ginfo->events [i];
3585 event->parent = klass;
3586 event->name = gevent->name;
3587 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, error) : NULL;
3588 g_assert (is_ok (error)); /*FIXME proper error handling*/
3589 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, error) : NULL;
3590 g_assert (is_ok (error)); /*FIXME proper error handling*/
3591 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, error) : NULL;
3592 g_assert (is_ok (error)); /*FIXME proper error handling*/
3594 #ifndef MONO_SMALL_CONFIG
3595 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
3596 #endif
3597 event->attrs = gevent->attrs;
3599 } else {
3600 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
3601 count = last - first;
3603 if (count) {
3604 mono_class_setup_methods (klass);
3605 if (mono_class_has_failure (klass)) {
3606 return;
3610 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
3611 for (i = first; i < last; ++i) {
3612 MonoEvent *event = &events [i - first];
3614 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
3615 event->parent = klass;
3616 event->attrs = cols [MONO_EVENT_FLAGS];
3617 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
3619 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
3620 int first_idx = mono_class_get_first_method_idx (klass);
3621 for (j = startm; j < endm; ++j) {
3622 MonoMethod *method;
3624 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
3626 if (klass->image->uncompressed_metadata) {
3627 ERROR_DECL (error);
3628 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
3629 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
3630 mono_error_cleanup (error); /* FIXME don't swallow this error */
3631 } else {
3632 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
3635 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
3636 case METHOD_SEMANTIC_ADD_ON:
3637 event->add = method;
3638 break;
3639 case METHOD_SEMANTIC_REMOVE_ON:
3640 event->remove = method;
3641 break;
3642 case METHOD_SEMANTIC_FIRE:
3643 event->raise = method;
3644 break;
3645 case METHOD_SEMANTIC_OTHER: {
3646 #ifndef MONO_SMALL_CONFIG
3647 int n = 0;
3649 if (event->other == NULL) {
3650 event->other = g_new0 (MonoMethod*, 2);
3651 } else {
3652 while (event->other [n])
3653 n++;
3654 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
3656 event->other [n] = method;
3657 /* NULL terminated */
3658 event->other [n + 1] = NULL;
3659 #endif
3660 break;
3662 default:
3663 break;
3669 info = (MonoClassEventInfo*)mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
3670 info->events = events;
3671 info->first = first;
3672 info->count = count;
3674 mono_memory_barrier ();
3676 mono_class_set_event_info (klass, info);
3681 * mono_class_setup_interface_id:
3683 * Initializes MonoClass::interface_id if required.
3685 * LOCKING: Acquires the loader lock.
3687 void
3688 mono_class_setup_interface_id (MonoClass *klass)
3690 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
3691 mono_loader_lock ();
3692 mono_class_setup_interface_id_nolock (klass);
3693 mono_loader_unlock ();
3697 * mono_class_setup_interfaces:
3699 * Initialize klass->interfaces/interfaces_count.
3700 * LOCKING: Acquires the loader lock.
3701 * This function can fail the type.
3703 void
3704 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
3706 int i, interface_count;
3707 MonoClass **interfaces;
3709 error_init (error);
3711 if (klass->interfaces_inited)
3712 return;
3714 if (klass->rank == 1 && m_class_get_byval_arg (klass)->type != MONO_TYPE_ARRAY) {
3715 MonoType *args [1];
3717 /* IList and IReadOnlyList -> 2x if enum*/
3718 interface_count = klass->element_class->enumtype ? 4 : 2;
3719 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
3721 args [0] = m_class_get_byval_arg (m_class_get_element_class (klass));
3722 interfaces [0] = mono_class_bind_generic_parameters (
3723 mono_defaults.generic_ilist_class, 1, args, FALSE);
3724 interfaces [1] = mono_class_bind_generic_parameters (
3725 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
3726 if (klass->element_class->enumtype) {
3727 args [0] = mono_class_enum_basetype_internal (klass->element_class);
3728 interfaces [2] = mono_class_bind_generic_parameters (
3729 mono_defaults.generic_ilist_class, 1, args, FALSE);
3730 interfaces [3] = mono_class_bind_generic_parameters (
3731 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
3733 } else if (mono_class_is_ginst (klass)) {
3734 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3736 mono_class_setup_interfaces (gklass, error);
3737 if (!is_ok (error)) {
3738 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
3739 return;
3742 interface_count = gklass->interface_count;
3743 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
3744 for (i = 0; i < interface_count; i++) {
3745 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
3746 if (!is_ok (error)) {
3747 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
3748 return;
3751 } else {
3752 interface_count = 0;
3753 interfaces = NULL;
3756 mono_loader_lock ();
3757 if (!klass->interfaces_inited) {
3758 klass->interface_count = interface_count;
3759 klass->interfaces = interfaces;
3761 mono_memory_barrier ();
3763 klass->interfaces_inited = TRUE;
3765 mono_loader_unlock ();
3770 * mono_class_setup_has_finalizer:
3772 * Initialize klass->has_finalizer if it isn't already initialized.
3774 * LOCKING: Acquires the loader lock.
3776 void
3777 mono_class_setup_has_finalizer (MonoClass *klass)
3779 gboolean has_finalize = FALSE;
3781 if (m_class_is_has_finalize_inited (klass))
3782 return;
3784 /* Interfaces and valuetypes are not supposed to have finalizers */
3785 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_is_valuetype (klass))) {
3786 MonoMethod *cmethod = NULL;
3788 if (m_class_get_rank (klass) == 1 && m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
3789 } else if (mono_class_is_ginst (klass)) {
3790 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3792 has_finalize = mono_class_has_finalizer (gklass);
3793 } else if (m_class_get_parent (klass) && m_class_has_finalize (m_class_get_parent (klass))) {
3794 has_finalize = TRUE;
3795 } else {
3796 if (m_class_get_parent (klass)) {
3798 * Can't search in metadata for a method named Finalize, because that
3799 * ignores overrides.
3801 mono_class_setup_vtable (klass);
3802 if (mono_class_has_failure (klass))
3803 cmethod = NULL;
3804 else
3805 cmethod = m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
3808 if (cmethod) {
3809 g_assert (m_class_get_vtable_size (klass) > mono_class_get_object_finalize_slot ());
3811 if (m_class_get_parent (klass)) {
3812 if (cmethod->is_inflated)
3813 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
3814 if (cmethod != mono_class_get_default_finalize_method ())
3815 has_finalize = TRUE;
3821 mono_loader_lock ();
3822 if (!m_class_is_has_finalize_inited (klass)) {
3823 klass->has_finalize = has_finalize ? 1 : 0;
3825 mono_memory_barrier ();
3826 klass->has_finalize_inited = TRUE;
3828 mono_loader_unlock ();
3832 * mono_class_setup_supertypes:
3833 * @class: a class
3835 * Build the data structure needed to make fast type checks work.
3836 * This currently sets two fields in @class:
3837 * - idepth: distance between @class and System.Object in the type
3838 * hierarchy + 1
3839 * - supertypes: array of classes: each element has a class in the hierarchy
3840 * starting from @class up to System.Object
3842 * LOCKING: Acquires the loader lock.
3844 void
3845 mono_class_setup_supertypes (MonoClass *klass)
3847 int ms, idepth;
3848 MonoClass **supertypes;
3850 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
3851 if (supertypes)
3852 return;
3854 if (klass->parent && !klass->parent->supertypes)
3855 mono_class_setup_supertypes (klass->parent);
3856 if (klass->parent)
3857 idepth = klass->parent->idepth + 1;
3858 else
3859 idepth = 1;
3861 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
3862 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
3864 if (klass->parent) {
3865 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
3867 int supertype_idx;
3868 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
3869 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
3870 } else {
3871 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
3874 mono_memory_barrier ();
3876 mono_loader_lock ();
3877 klass->idepth = idepth;
3878 /* Needed so idepth is visible before supertypes is set */
3879 mono_memory_barrier ();
3880 klass->supertypes = supertypes;
3881 mono_loader_unlock ();
3884 /* mono_class_setup_nested_types:
3886 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
3888 * LOCKING: Acquires the loader lock.
3890 void
3891 mono_class_setup_nested_types (MonoClass *klass)
3893 ERROR_DECL (error);
3894 GList *classes, *nested_classes, *l;
3895 int i;
3897 if (klass->nested_classes_inited)
3898 return;
3900 if (!klass->type_token) {
3901 mono_loader_lock ();
3902 klass->nested_classes_inited = TRUE;
3903 mono_loader_unlock ();
3904 return;
3907 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
3908 classes = NULL;
3909 while (i) {
3910 MonoClass* nclass;
3911 guint32 cols [MONO_NESTED_CLASS_SIZE];
3912 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
3913 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], error);
3914 if (!is_ok (error)) {
3915 /*FIXME don't swallow the error message*/
3916 mono_error_cleanup (error);
3918 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
3919 continue;
3922 classes = g_list_prepend (classes, nclass);
3924 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
3927 nested_classes = NULL;
3928 for (l = classes; l; l = l->next)
3929 nested_classes = mono_g_list_prepend_image (klass->image, nested_classes, l->data);
3930 g_list_free (classes);
3932 mono_loader_lock ();
3933 if (!klass->nested_classes_inited) {
3934 mono_class_set_nested_classes_property (klass, nested_classes);
3935 mono_memory_barrier ();
3936 klass->nested_classes_inited = TRUE;
3938 mono_loader_unlock ();
3942 * mono_class_setup_runtime_info:
3943 * \param klass the class to setup
3944 * \param domain the domain of the \p vtable
3945 * \param vtable
3947 * Store \p vtable in \c klass->runtime_info.
3949 * Sets the following field in MonoClass:
3950 * - runtime_info
3952 * LOCKING: domain lock and loaderlock must be held.
3954 void
3955 mono_class_setup_runtime_info (MonoClass *klass, MonoDomain *domain, MonoVTable *vtable)
3957 MonoClassRuntimeInfo *old_info = m_class_get_runtime_info (klass);
3958 if (old_info && old_info->max_domain >= domain->domain_id) {
3959 /* someone already created a large enough runtime info */
3960 old_info->domain_vtables [domain->domain_id] = vtable;
3961 } else {
3962 int new_size = domain->domain_id;
3963 if (old_info)
3964 new_size = MAX (new_size, old_info->max_domain);
3965 new_size++;
3966 /* make the new size a power of two */
3967 int i = 2;
3968 while (new_size > i)
3969 i <<= 1;
3970 new_size = i;
3971 /* this is a bounded memory retention issue: may want to
3972 * handle it differently when we'll have a rcu-like system.
3974 MonoClassRuntimeInfo *runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
3975 runtime_info->max_domain = new_size - 1;
3976 /* copy the stuff from the older info */
3977 if (old_info) {
3978 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
3980 runtime_info->domain_vtables [domain->domain_id] = vtable;
3981 /* keep this last*/
3982 mono_memory_barrier ();
3983 klass->runtime_info = runtime_info;
3988 * mono_class_create_array_fill_type:
3990 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
3992 MonoClass *
3993 mono_class_create_array_fill_type (void)
3995 static MonoClass klass;
3997 klass.element_class = mono_defaults.int64_class;
3998 klass.rank = 1;
3999 klass.instance_size = MONO_SIZEOF_MONO_ARRAY;
4000 klass.sizes.element_size = 8;
4001 klass.size_inited = 1;
4002 klass.name = "array_filler_type";
4004 return &klass;
4008 * mono_classes_init:
4010 * Initialize the resources used by this module.
4011 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
4013 MONO_NO_SANITIZE_THREAD
4014 void
4015 mono_classes_init (void)
4017 mono_os_mutex_init (&classes_mutex);
4019 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
4020 mono_native_tls_alloc (&init_pending_tls_id, NULL);
4022 mono_counters_register ("MonoClassDef count",
4023 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
4024 mono_counters_register ("MonoClassGtd count",
4025 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
4026 mono_counters_register ("MonoClassGenericInst count",
4027 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
4028 mono_counters_register ("MonoClassGenericParam count",
4029 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
4030 mono_counters_register ("MonoClassArray count",
4031 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
4032 mono_counters_register ("MonoClassPointer count",
4033 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
4034 mono_counters_register ("Inflated methods size",
4035 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mono_inflated_methods_size);
4036 mono_counters_register ("Inflated classes size",
4037 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
4038 mono_counters_register ("MonoClass size",
4039 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
4043 * mono_classes_cleanup:
4045 * Free the resources used by this module.
4047 void
4048 mono_classes_cleanup (void)
4050 mono_native_tls_free (setup_fields_tls_id);
4051 mono_native_tls_free (init_pending_tls_id);
4053 if (global_interface_bitset)
4054 mono_bitset_free (global_interface_bitset);
4055 global_interface_bitset = NULL;
4056 mono_os_mutex_destroy (&classes_mutex);