[mini] Always emit safepoints, except WASM
[mono-project.git] / mono / metadata / class-init.c
blobdcfc42ea788087a9b9e813ffc2a3cc72ec54485a
1 /**
2 * \file MonoClass construction and initialization
4 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
5 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
6 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
7 * Copyright 2018 Microsoft
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 */
10 #include <config.h>
11 #include <mono/metadata/class-init.h>
12 #include <mono/metadata/class-internals.h>
13 #include <mono/metadata/custom-attrs-internals.h>
14 #include <mono/metadata/debug-helpers.h>
15 #include <mono/metadata/exception-internals.h>
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/metadata/object-internals.h>
18 #include <mono/metadata/profiler-private.h>
19 #include <mono/metadata/security-core-clr.h>
20 #include <mono/metadata/security-manager.h>
21 #include <mono/metadata/verify-internals.h>
22 #include <mono/metadata/abi-details.h>
23 #include <mono/utils/checked-build.h>
24 #include <mono/utils/mono-counters.h>
25 #include <mono/utils/mono-error-internals.h>
26 #include <mono/utils/mono-logger-internals.h>
27 #include <mono/utils/mono-memory-model.h>
28 #include <mono/utils/unlocked.h>
29 #ifdef MONO_CLASS_DEF_PRIVATE
30 /* Class initialization gets to see the fields of MonoClass */
31 #define REALLY_INCLUDE_CLASS_DEF 1
32 #include <mono/metadata/class-private-definition.h>
33 #undef REALLY_INCLUDE_CLASS_DEF
34 #endif
37 gboolean mono_print_vtable = FALSE;
38 gboolean mono_align_small_structs = FALSE;
40 /* Statistics */
41 static gint32 classes_size;
42 static gint32 inflated_classes_size;
43 gint32 mono_inflated_methods_size;
44 static gint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
46 /* Low level lock which protects data structures in this module */
47 static mono_mutex_t classes_mutex;
49 static gboolean class_kind_may_contain_generic_instances (MonoTypeKind kind);
50 static int setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite);
51 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
52 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd);
53 static int generic_array_methods (MonoClass *klass);
54 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache);
55 static gboolean class_has_isbyreflike_attribute (MonoClass *klass);
56 static void mono_class_setup_interface_id_internal (MonoClass *klass);
58 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
59 static MonoNativeTlsKey setup_fields_tls_id;
61 static MonoNativeTlsKey init_pending_tls_id;
63 static inline void
64 classes_lock (void)
66 mono_locks_os_acquire (&classes_mutex, ClassesLock);
69 static inline void
70 classes_unlock (void)
72 mono_locks_os_release (&classes_mutex, ClassesLock);
76 We use gclass recording to allow recursive system f types to be referenced by a parent.
78 Given the following type hierarchy:
80 class TextBox : TextBoxBase<TextBox> {}
81 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
82 class TextInput<T> : Input<T> where T: TextInput<T> {}
83 class Input<T> {}
85 The runtime tries to load TextBoxBase<>.
86 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
87 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
88 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
90 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
91 at this point, iow, both are registered in the type map and both and a NULL parent. This means
92 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
94 To fix that what we do is to record all generic instantes created while resolving the parent of
95 any generic type definition and, after resolved, correct the parent field if needed.
98 static int record_gclass_instantiation;
99 static GSList *gclass_recorded_list;
100 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
103 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
105 static void
106 enable_gclass_recording (void)
108 ++record_gclass_instantiation;
112 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
114 static void
115 disable_gclass_recording (gclass_record_func func, void *user_data)
117 GSList **head = &gclass_recorded_list;
119 g_assert (record_gclass_instantiation > 0);
120 --record_gclass_instantiation;
122 while (*head) {
123 GSList *node = *head;
124 if (func ((MonoClass*)node->data, user_data)) {
125 *head = node->next;
126 g_slist_free_1 (node);
127 } else {
128 head = &node->next;
132 /* We automatically discard all recorded gclasses when disabled. */
133 if (!record_gclass_instantiation && gclass_recorded_list) {
134 g_slist_free (gclass_recorded_list);
135 gclass_recorded_list = NULL;
139 #define mono_class_new0(klass,struct_type, n_structs) \
140 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
143 * mono_class_setup_basic_field_info:
144 * \param class The class to initialize
146 * Initializes the following fields in MonoClass:
147 * * klass->fields (only field->parent and field->name)
148 * * klass->field.count
149 * * klass->first_field_idx
150 * LOCKING: Acquires the loader lock
152 void
153 mono_class_setup_basic_field_info (MonoClass *klass)
155 MonoGenericClass *gklass;
156 MonoClassField *field;
157 MonoClassField *fields;
158 MonoClass *gtd;
159 MonoImage *image;
160 int i, top;
162 if (klass->fields)
163 return;
165 gklass = mono_class_try_get_generic_class (klass);
166 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
167 image = klass->image;
170 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
172 * This happens when a generic instance of an unfinished generic typebuilder
173 * is used as an element type for creating an array type. We can't initialize
174 * the fields of this class using the fields of gklass, since gklass is not
175 * finished yet, fields could be added to it later.
177 return;
180 if (gtd) {
181 mono_class_setup_basic_field_info (gtd);
183 mono_loader_lock ();
184 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
185 mono_loader_unlock ();
188 top = mono_class_get_field_count (klass);
190 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
193 * Fetch all the field information.
195 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
196 for (i = 0; i < top; i++) {
197 field = &fields [i];
198 field->parent = klass;
200 if (gtd) {
201 field->name = mono_field_get_name (&gtd->fields [i]);
202 } else {
203 int idx = first_field_idx + i;
204 /* first_field_idx and idx points into the fieldptr table */
205 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
206 /* The name is needed for fieldrefs */
207 field->name = mono_metadata_string_heap (image, name_idx);
211 mono_memory_barrier ();
213 mono_loader_lock ();
214 if (!klass->fields)
215 klass->fields = fields;
216 mono_loader_unlock ();
220 * mono_class_setup_fields:
221 * \p klass The class to initialize
223 * Initializes klass->fields, computes class layout and sizes.
224 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
225 * Sets the following fields in \p klass:
226 * - all the fields initialized by mono_class_init_sizes ()
227 * - element_class/cast_class (for enums)
228 * - sizes:element_size (for arrays)
229 * - field->type/offset for all fields
230 * - fields_inited
232 * LOCKING: Acquires the loader lock.
234 void
235 mono_class_setup_fields (MonoClass *klass)
237 ERROR_DECL (error);
238 MonoImage *m = klass->image;
239 int top;
240 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
241 int i;
242 guint32 real_size = 0;
243 guint32 packing_size = 0;
244 int instance_size;
245 gboolean explicit_size;
246 MonoClassField *field;
247 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
248 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
250 if (klass->fields_inited)
251 return;
253 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
255 * This happens when a generic instance of an unfinished generic typebuilder
256 * is used as an element type for creating an array type. We can't initialize
257 * the fields of this class using the fields of gklass, since gklass is not
258 * finished yet, fields could be added to it later.
260 return;
263 mono_class_setup_basic_field_info (klass);
264 top = mono_class_get_field_count (klass);
266 if (gtd) {
267 mono_class_setup_fields (gtd);
268 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
269 return;
272 instance_size = 0;
273 if (klass->parent) {
274 /* For generic instances, klass->parent might not have been initialized */
275 mono_class_init_internal (klass->parent);
276 mono_class_setup_fields (klass->parent);
277 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
278 return;
279 instance_size = klass->parent->instance_size;
280 } else {
281 instance_size = MONO_ABI_SIZEOF (MonoObject);
284 /* Get the real size */
285 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
286 if (explicit_size)
287 instance_size += real_size;
290 * This function can recursively call itself.
291 * Prevent infinite recursion by using a list in TLS.
293 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
294 if (g_slist_find (init_list, klass))
295 return;
296 init_list = g_slist_prepend (init_list, klass);
297 mono_native_tls_set_value (setup_fields_tls_id, init_list);
300 * Fetch all the field information.
302 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
303 for (i = 0; i < top; i++) {
304 int idx = first_field_idx + i;
305 field = &klass->fields [i];
307 if (!field->type) {
308 mono_field_resolve_type (field, error);
309 if (!mono_error_ok (error)) {
310 /*mono_field_resolve_type already failed class*/
311 mono_error_cleanup (error);
312 break;
314 if (!field->type)
315 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
316 g_assert (field->type);
319 if (!mono_type_get_underlying_type (field->type)) {
320 mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
321 break;
324 if (mono_field_is_deleted (field))
325 continue;
326 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
327 guint32 uoffset;
328 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
329 int offset = uoffset;
331 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
332 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
333 break;
335 if (offset < -1) { /*-1 is used to encode special static fields */
336 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
337 break;
339 if (mono_class_is_gtd (klass)) {
340 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
341 break;
344 if (mono_type_has_exceptions (field->type)) {
345 char *class_name = mono_type_get_full_name (klass);
346 char *type_name = mono_type_full_name (field->type);
348 mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
349 g_free (class_name);
350 g_free (type_name);
351 break;
353 /* The def_value of fields is compute lazily during vtable creation */
356 if (!mono_class_has_failure (klass)) {
357 mono_loader_lock ();
358 mono_class_layout_fields (klass, instance_size, packing_size, real_size, FALSE);
359 mono_loader_unlock ();
362 init_list = g_slist_remove (init_list, klass);
363 mono_native_tls_set_value (setup_fields_tls_id, init_list);
366 static gboolean
367 discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
369 return mono_class_get_generic_class (gclass)->container_class == user_data;
372 static gboolean
373 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
375 MonoClass *gtd = (MonoClass*)user_data;
376 /* Only try to fix generic instances of @gtd */
377 if (mono_class_get_generic_class (gclass)->container_class != gtd)
378 return FALSE;
380 /* Check if the generic instance has no parent. */
381 if (gtd->parent && !gclass->parent)
382 mono_generic_class_setup_parent (gclass, gtd);
384 return TRUE;
387 static void
388 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
390 mono_class_set_type_load_failure (klass, "%s", msg);
391 mono_error_set_type_load_class (error, klass, "%s", msg);
395 * mono_class_create_from_typedef:
396 * \param image: image where the token is valid
397 * \param type_token: typedef token
398 * \param error: used to return any error found while creating the type
400 * Create the MonoClass* representing the specified type token.
401 * \p type_token must be a TypeDef token.
403 * FIXME: don't return NULL on failure, just let the caller figure it out.
405 MonoClass *
406 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
408 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
409 MonoClass *klass, *parent = NULL;
410 guint32 cols [MONO_TYPEDEF_SIZE];
411 guint32 cols_next [MONO_TYPEDEF_SIZE];
412 guint tidx = mono_metadata_token_index (type_token);
413 MonoGenericContext *context = NULL;
414 const char *name, *nspace;
415 guint icount = 0;
416 MonoClass **interfaces;
417 guint32 field_last, method_last;
418 guint32 nesting_tokeen;
420 error_init (error);
422 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
423 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
424 return NULL;
427 mono_loader_lock ();
429 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
430 mono_loader_unlock ();
431 return klass;
434 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
436 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
437 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
439 if (mono_metadata_has_generic_params (image, type_token)) {
440 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassGtd));
441 klass->class_kind = MONO_CLASS_GTD;
442 UnlockedAdd (&classes_size, sizeof (MonoClassGtd));
443 ++class_gtd_count;
444 } else {
445 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassDef));
446 klass->class_kind = MONO_CLASS_DEF;
447 UnlockedAdd (&classes_size, sizeof (MonoClassDef));
448 ++class_def_count;
451 klass->name = name;
452 klass->name_space = nspace;
454 MONO_PROFILER_RAISE (class_loading, (klass));
456 klass->image = image;
457 klass->type_token = type_token;
458 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
460 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
463 * Check whether we're a generic type definition.
465 if (mono_class_is_gtd (klass)) {
466 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL, klass);
467 context = &generic_container->context;
468 mono_class_set_generic_container (klass, generic_container);
469 MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
470 canonical_inst->type = MONO_TYPE_GENERICINST;
471 canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
472 enable_gclass_recording ();
475 if (cols [MONO_TYPEDEF_EXTENDS]) {
476 MonoClass *tmp;
477 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
479 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
480 /*WARNING: this must satisfy mono_metadata_type_hash*/
481 klass->this_arg.byref = 1;
482 klass->this_arg.data.klass = klass;
483 klass->this_arg.type = MONO_TYPE_CLASS;
484 klass->_byval_arg.data.klass = klass;
485 klass->_byval_arg.type = MONO_TYPE_CLASS;
487 parent = mono_class_get_checked (image, parent_token, error);
488 if (parent && context) /* Always inflate */
489 parent = mono_class_inflate_generic_class_checked (parent, context, error);
491 if (parent == NULL) {
492 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
493 goto parent_failure;
496 for (tmp = parent; tmp; tmp = tmp->parent) {
497 if (tmp == klass) {
498 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
499 goto parent_failure;
501 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
502 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
503 goto parent_failure;
508 mono_class_setup_parent (klass, parent);
510 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
511 mono_class_setup_mono_type (klass);
513 if (mono_class_is_gtd (klass))
514 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
517 * This might access klass->_byval_arg for recursion generated by generic constraints,
518 * so it has to come after setup_mono_type ().
520 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
521 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
522 if (!mono_error_ok (error)) {
523 /*FIXME implement a mono_class_set_failure_from_mono_error */
524 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
525 mono_loader_unlock ();
526 MONO_PROFILER_RAISE (class_failed, (klass));
527 return NULL;
531 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
532 klass->unicode = 1;
534 #ifdef HOST_WIN32
535 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
536 klass->unicode = 1;
537 #endif
539 klass->cast_class = klass->element_class = klass;
540 if (mono_is_corlib_image (klass->image)) {
541 switch (m_class_get_byval_arg (klass)->type) {
542 case MONO_TYPE_I1:
543 if (mono_defaults.byte_class)
544 klass->cast_class = mono_defaults.byte_class;
545 break;
546 case MONO_TYPE_U1:
547 if (mono_defaults.sbyte_class)
548 mono_defaults.sbyte_class = klass;
549 break;
550 case MONO_TYPE_I2:
551 if (mono_defaults.uint16_class)
552 mono_defaults.uint16_class = klass;
553 break;
554 case MONO_TYPE_U2:
555 if (mono_defaults.int16_class)
556 klass->cast_class = mono_defaults.int16_class;
557 break;
558 case MONO_TYPE_I4:
559 if (mono_defaults.uint32_class)
560 mono_defaults.uint32_class = klass;
561 break;
562 case MONO_TYPE_U4:
563 if (mono_defaults.int32_class)
564 klass->cast_class = mono_defaults.int32_class;
565 break;
566 case MONO_TYPE_I8:
567 if (mono_defaults.uint64_class)
568 mono_defaults.uint64_class = klass;
569 break;
570 case MONO_TYPE_U8:
571 if (mono_defaults.int64_class)
572 klass->cast_class = mono_defaults.int64_class;
573 break;
577 if (!klass->enumtype) {
578 if (!mono_metadata_interfaces_from_typedef_full (
579 image, type_token, &interfaces, &icount, FALSE, context, error)){
581 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
582 mono_loader_unlock ();
583 MONO_PROFILER_RAISE (class_failed, (klass));
584 return NULL;
587 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
588 g_assert(icount <= 65535);
590 klass->interfaces = interfaces;
591 klass->interface_count = icount;
592 klass->interfaces_inited = 1;
595 /*g_print ("Load class %s\n", name);*/
598 * Compute the field and method lists
600 int first_field_idx;
601 first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
602 mono_class_set_first_field_idx (klass, first_field_idx);
603 int first_method_idx;
604 first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
605 mono_class_set_first_method_idx (klass, first_method_idx);
607 if (tt->rows > tidx){
608 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
609 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
610 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
611 } else {
612 field_last = image->tables [MONO_TABLE_FIELD].rows;
613 method_last = image->tables [MONO_TABLE_METHOD].rows;
616 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
617 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
618 mono_class_set_field_count (klass, field_last - first_field_idx);
619 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
620 mono_class_set_method_count (klass, method_last - first_method_idx);
622 /* reserve space to store vector pointer in arrays */
623 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
624 klass->instance_size += 2 * TARGET_SIZEOF_VOID_P;
625 g_assert (mono_class_get_field_count (klass) == 0);
628 if (klass->enumtype) {
629 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
630 if (!enum_basetype) {
631 /*set it to a default value as the whole runtime can't handle this to be null*/
632 klass->cast_class = klass->element_class = mono_defaults.int32_class;
633 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
634 mono_loader_unlock ();
635 MONO_PROFILER_RAISE (class_failed, (klass));
636 return NULL;
638 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (enum_basetype);
642 * If we're a generic type definition, load the constraints.
643 * We must do this after the class has been constructed to make certain recursive scenarios
644 * work.
646 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
647 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
648 mono_loader_unlock ();
649 MONO_PROFILER_RAISE (class_failed, (klass));
650 return NULL;
653 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
654 if (!strncmp (name, "Vector", 6))
655 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");
656 } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
657 /* The JIT can't handle SIMD types with != 16 size yet */
658 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
659 if (!strcmp (name, "Vector4"))
660 klass->simd_type = 1;
663 // compute is_byreflike
664 if (m_class_is_valuetype (klass)) {
665 /* TypedReference and RuntimeArgumentHandle are byreflike by
666 * definition. Otherwise, look for IsByRefLikeAttribute.
668 if (mono_is_corlib_image (image) &&
669 ((m_class_get_byval_arg (klass)->type == MONO_TYPE_TYPEDBYREF) ||
670 (!strcmp (m_class_get_name_space (klass), "System") &&
671 !strcmp (m_class_get_name (klass), "RuntimeArgumentHandle"))))
672 klass->is_byreflike = 1;
673 else if (class_has_isbyreflike_attribute (klass))
674 klass->is_byreflike = 1;
677 mono_loader_unlock ();
679 MONO_PROFILER_RAISE (class_loaded, (klass));
681 return klass;
683 parent_failure:
684 if (mono_class_is_gtd (klass))
685 disable_gclass_recording (discard_gclass_due_to_failure, klass);
687 mono_class_setup_mono_type (klass);
688 mono_loader_unlock ();
689 MONO_PROFILER_RAISE (class_failed, (klass));
690 return NULL;
694 static void
695 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
697 if (gtd->parent) {
698 ERROR_DECL (error);
699 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
701 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), error);
702 if (!mono_error_ok (error)) {
703 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
704 klass->parent = mono_defaults.object_class;
705 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error));
706 mono_error_cleanup (error);
709 mono_loader_lock ();
710 if (klass->parent)
711 mono_class_setup_parent (klass, klass->parent);
713 if (klass->enumtype) {
714 klass->cast_class = gtd->cast_class;
715 klass->element_class = gtd->element_class;
717 mono_loader_unlock ();
720 struct HasIsByrefLikeUD {
721 gboolean has_isbyreflike;
724 static gboolean
725 has_isbyreflike_attribute_func (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
727 struct HasIsByrefLikeUD *has_isbyreflike = (struct HasIsByrefLikeUD *)user_data;
728 if (!strcmp (name, "IsByRefLikeAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
729 has_isbyreflike->has_isbyreflike = TRUE;
730 return TRUE;
732 return FALSE;
735 static gboolean
736 class_has_isbyreflike_attribute (MonoClass *klass)
738 struct HasIsByrefLikeUD has_isbyreflike;
739 has_isbyreflike.has_isbyreflike = FALSE;
740 mono_class_metadata_foreach_custom_attr (klass, has_isbyreflike_attribute_func, &has_isbyreflike);
741 return has_isbyreflike.has_isbyreflike;
745 static gboolean
746 check_valid_generic_inst_arguments (MonoGenericInst *inst, MonoError *error)
748 for (int i = 0; i < inst->type_argc; i++) {
749 if (!mono_type_is_valid_generic_argument (inst->type_argv [i])) {
750 char *type_name = mono_type_full_name (inst->type_argv [i]);
751 mono_error_set_invalid_program (error, "generic type cannot be instantiated with type '%s'", type_name);
752 g_free (type_name);
753 return FALSE;
756 return TRUE;
760 * Create the `MonoClass' for an instantiation of a generic type.
761 * We only do this if we actually need it.
763 MonoClass*
764 mono_class_create_generic_inst (MonoGenericClass *gclass)
766 MonoClass *klass, *gklass;
768 if (gclass->cached_class)
769 return gclass->cached_class;
771 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
773 gklass = gclass->container_class;
775 if (gklass->nested_in) {
776 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
777 klass->nested_in = gklass->nested_in;
780 klass->name = gklass->name;
781 klass->name_space = gklass->name_space;
783 klass->image = gklass->image;
784 klass->type_token = gklass->type_token;
786 klass->class_kind = MONO_CLASS_GINST;
787 //FIXME add setter
788 ((MonoClassGenericInst*)klass)->generic_class = gclass;
790 klass->_byval_arg.type = MONO_TYPE_GENERICINST;
791 klass->this_arg.type = m_class_get_byval_arg (klass)->type;
792 klass->this_arg.data.generic_class = klass->_byval_arg.data.generic_class = gclass;
793 klass->this_arg.byref = TRUE;
794 klass->enumtype = gklass->enumtype;
795 klass->valuetype = gklass->valuetype;
798 if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
799 g_assert (gclass->context.class_inst);
800 g_assert (gclass->context.class_inst->type_argc > 0);
801 if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
802 klass->simd_type = 1;
804 klass->is_array_special_interface = gklass->is_array_special_interface;
806 klass->cast_class = klass->element_class = klass;
808 if (m_class_is_valuetype (klass)) {
809 klass->is_byreflike = gklass->is_byreflike;
812 if (gclass->is_dynamic) {
814 * 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.
815 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
816 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
818 if (!gklass->wastypebuilder)
819 klass->inited = 1;
821 if (klass->enumtype) {
823 * For enums, gklass->fields might not been set, but instance_size etc. is
824 * already set in mono_reflection_create_internal_class (). For non-enums,
825 * these will be computed normally in mono_class_layout_fields ().
827 klass->instance_size = gklass->instance_size;
828 klass->sizes.class_size = gklass->sizes.class_size;
829 klass->size_inited = 1;
834 ERROR_DECL (error_inst);
835 if (!check_valid_generic_inst_arguments (gclass->context.class_inst, error_inst)) {
836 char *gklass_name = mono_type_get_full_name (gklass);
837 mono_class_set_type_load_failure (klass, "Could not instantiate %s due to %s", gklass_name, mono_error_get_message (error_inst));
838 g_free (gklass_name);
839 mono_error_cleanup (error_inst);
843 mono_loader_lock ();
845 if (gclass->cached_class) {
846 mono_loader_unlock ();
847 return gclass->cached_class;
850 if (record_gclass_instantiation > 0)
851 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
853 if (mono_class_is_nullable (klass))
854 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
856 MONO_PROFILER_RAISE (class_loading, (klass));
858 mono_generic_class_setup_parent (klass, gklass);
860 if (gclass->is_dynamic)
861 mono_class_setup_supertypes (klass);
863 mono_memory_barrier ();
864 gclass->cached_class = klass;
866 MONO_PROFILER_RAISE (class_loaded, (klass));
868 ++class_ginst_count;
869 inflated_classes_size += sizeof (MonoClassGenericInst);
871 mono_loader_unlock ();
873 return klass;
876 static gboolean
877 class_kind_may_contain_generic_instances (MonoTypeKind kind)
879 /* classes of type generic inst may contain generic arguments from other images,
880 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
881 return (kind == MONO_CLASS_GINST || kind == MONO_CLASS_ARRAY || kind == MONO_CLASS_POINTER);
885 * mono_class_create_bounded_array:
886 * \param element_class element class
887 * \param rank the dimension of the array class
888 * \param bounded whenever the array has non-zero bounds
889 * \returns A class object describing the array with element type \p element_type and
890 * dimension \p rank.
892 MonoClass *
893 mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bounded)
895 MonoImage *image;
896 MonoClass *klass, *cached, *k;
897 MonoClass *parent = NULL;
898 GSList *list, *rootlist = NULL;
899 int nsize;
900 char *name;
901 MonoImageSet* image_set;
903 g_assert (rank <= 255);
905 if (rank > 1)
906 /* bounded only matters for one-dimensional arrays */
907 bounded = FALSE;
909 image = eclass->image;
910 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)eclass->class_kind) ? mono_metadata_get_image_set_for_class (eclass) : NULL;
912 /* Check cache */
913 cached = NULL;
914 if (rank == 1 && !bounded) {
915 if (image_set) {
916 mono_image_set_lock (image_set);
917 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
918 mono_image_set_unlock (image_set);
919 } else {
921 * This case is very frequent not just during compilation because of calls
922 * from mono_class_from_mono_type_internal (), mono_array_new (),
923 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
925 mono_os_mutex_lock (&image->szarray_cache_lock);
926 if (!image->szarray_cache)
927 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
928 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
929 mono_os_mutex_unlock (&image->szarray_cache_lock);
931 } else {
932 if (image_set) {
933 mono_image_set_lock (image_set);
934 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
935 for (list = rootlist; list; list = list->next) {
936 k = (MonoClass *)list->data;
937 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
938 cached = k;
939 break;
942 mono_image_set_unlock (image_set);
943 } else {
944 mono_loader_lock ();
945 if (!image->array_cache)
946 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
947 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
948 for (list = rootlist; list; list = list->next) {
949 k = (MonoClass *)list->data;
950 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
951 cached = k;
952 break;
955 mono_loader_unlock ();
958 if (cached)
959 return cached;
961 parent = mono_defaults.array_class;
962 if (!parent->inited)
963 mono_class_init_internal (parent);
965 klass = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
967 klass->image = image;
968 klass->name_space = eclass->name_space;
969 klass->class_kind = MONO_CLASS_ARRAY;
971 nsize = strlen (eclass->name);
972 name = (char *)g_malloc (nsize + 2 + rank + 1);
973 memcpy (name, eclass->name, nsize);
974 name [nsize] = '[';
975 if (rank > 1)
976 memset (name + nsize + 1, ',', rank - 1);
977 if (bounded)
978 name [nsize + rank] = '*';
979 name [nsize + rank + bounded] = ']';
980 name [nsize + rank + bounded + 1] = 0;
981 klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
982 g_free (name);
984 klass->type_token = 0;
985 klass->parent = parent;
986 klass->instance_size = mono_class_instance_size (klass->parent);
988 if (m_class_get_byval_arg (eclass)->type == MONO_TYPE_TYPEDBYREF) {
989 /*Arrays of those two types are invalid.*/
990 ERROR_DECL (prepared_error);
991 mono_error_set_invalid_program (prepared_error, "Arrays of System.TypedReference types are invalid.");
992 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
993 mono_error_cleanup (prepared_error);
994 } else if (m_class_is_byreflike (eclass)) {
995 /* .NET Core throws a type load exception: "Could not create array type 'fullname[]'" */
996 char *full_name = mono_type_get_full_name (eclass);
997 mono_class_set_type_load_failure (klass, "Could not create array type '%s[]'", full_name);
998 g_free (full_name);
999 } else if (eclass->enumtype && !mono_class_enum_basetype_internal (eclass)) {
1000 guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass);
1001 if (!ref_info_handle || eclass->wastypebuilder) {
1002 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
1003 g_assert (ref_info_handle && !eclass->wastypebuilder);
1005 /* element_size -1 is ok as this is not an instantitable type*/
1006 klass->sizes.element_size = -1;
1007 } else
1008 klass->sizes.element_size = -1;
1010 mono_class_setup_supertypes (klass);
1012 if (mono_class_is_ginst (eclass))
1013 mono_class_init_internal (eclass);
1014 if (!eclass->size_inited)
1015 mono_class_setup_fields (eclass);
1016 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
1017 /*FIXME we fail the array type, but we have to let other fields be set.*/
1019 klass->has_references = MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (eclass)) || m_class_has_references (eclass)? TRUE: FALSE;
1021 klass->rank = rank;
1023 if (eclass->enumtype)
1024 klass->cast_class = eclass->element_class;
1025 else
1026 klass->cast_class = eclass;
1028 switch (m_class_get_byval_arg (m_class_get_cast_class (klass))->type) {
1029 case MONO_TYPE_I1:
1030 klass->cast_class = mono_defaults.byte_class;
1031 break;
1032 case MONO_TYPE_U2:
1033 klass->cast_class = mono_defaults.int16_class;
1034 break;
1035 case MONO_TYPE_U4:
1036 #if TARGET_SIZEOF_VOID_P == 4
1037 case MONO_TYPE_I:
1038 case MONO_TYPE_U:
1039 #endif
1040 klass->cast_class = mono_defaults.int32_class;
1041 break;
1042 case MONO_TYPE_U8:
1043 #if TARGET_SIZEOF_VOID_P == 8
1044 case MONO_TYPE_I:
1045 case MONO_TYPE_U:
1046 #endif
1047 klass->cast_class = mono_defaults.int64_class;
1048 break;
1049 default:
1050 break;
1053 klass->element_class = eclass;
1055 if ((rank > 1) || bounded) {
1056 MonoArrayType *at = image_set ? (MonoArrayType *)mono_image_set_alloc0 (image_set, sizeof (MonoArrayType)) : (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
1057 klass->_byval_arg.type = MONO_TYPE_ARRAY;
1058 klass->_byval_arg.data.array = at;
1059 at->eklass = eclass;
1060 at->rank = rank;
1061 /* FIXME: complete.... */
1062 } else {
1063 klass->_byval_arg.type = MONO_TYPE_SZARRAY;
1064 klass->_byval_arg.data.klass = eclass;
1066 klass->this_arg = klass->_byval_arg;
1067 klass->this_arg.byref = 1;
1069 if (rank > 32) {
1070 ERROR_DECL (prepared_error);
1071 name = mono_type_get_full_name (klass);
1072 mono_error_set_type_load_class (prepared_error, klass, "%s has too many dimensions.", name);
1073 mono_class_set_failure (klass, mono_error_box (prepared_error, klass->image));
1074 mono_error_cleanup (prepared_error);
1075 g_free (name);
1078 mono_loader_lock ();
1080 /* Check cache again */
1081 cached = NULL;
1082 if (rank == 1 && !bounded) {
1083 if (image_set) {
1084 mono_image_set_lock (image_set);
1085 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
1086 mono_image_set_unlock (image_set);
1087 } else {
1088 mono_os_mutex_lock (&image->szarray_cache_lock);
1089 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
1090 mono_os_mutex_unlock (&image->szarray_cache_lock);
1092 } else {
1093 if (image_set) {
1094 mono_image_set_lock (image_set);
1095 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
1096 for (list = rootlist; list; list = list->next) {
1097 k = (MonoClass *)list->data;
1098 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1099 cached = k;
1100 break;
1103 mono_image_set_unlock (image_set);
1104 } else {
1105 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
1106 for (list = rootlist; list; list = list->next) {
1107 k = (MonoClass *)list->data;
1108 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1109 cached = k;
1110 break;
1115 if (cached) {
1116 mono_loader_unlock ();
1117 return cached;
1120 MONO_PROFILER_RAISE (class_loading, (klass));
1122 UnlockedAdd (&classes_size, sizeof (MonoClassArray));
1123 ++class_array_count;
1125 if (rank == 1 && !bounded) {
1126 if (image_set) {
1127 mono_image_set_lock (image_set);
1128 g_hash_table_insert (image_set->szarray_cache, eclass, klass);
1129 mono_image_set_unlock (image_set);
1130 } else {
1131 mono_os_mutex_lock (&image->szarray_cache_lock);
1132 g_hash_table_insert (image->szarray_cache, eclass, klass);
1133 mono_os_mutex_unlock (&image->szarray_cache_lock);
1135 } else {
1136 if (image_set) {
1137 mono_image_set_lock (image_set);
1138 list = g_slist_append (rootlist, klass);
1139 g_hash_table_insert (image_set->array_cache, eclass, list);
1140 mono_image_set_unlock (image_set);
1141 } else {
1142 list = g_slist_append (rootlist, klass);
1143 g_hash_table_insert (image->array_cache, eclass, list);
1147 mono_loader_unlock ();
1149 MONO_PROFILER_RAISE (class_loaded, (klass));
1151 return klass;
1155 * mono_class_create_array:
1156 * \param element_class element class
1157 * \param rank the dimension of the array class
1158 * \returns A class object describing the array with element type \p element_type and
1159 * dimension \p rank.
1161 MonoClass *
1162 mono_class_create_array (MonoClass *eclass, guint32 rank)
1164 return mono_class_create_bounded_array (eclass, rank, FALSE);
1167 // This is called by mono_class_create_generic_parameter when a new class must be created.
1168 static MonoClass*
1169 make_generic_param_class (MonoGenericParam *param)
1171 MonoClass *klass, **ptr;
1172 int count, pos, i;
1173 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1174 MonoGenericContainer *container = mono_generic_param_owner (param);
1175 g_assert_checked (container);
1177 MonoImage *image = mono_get_image_for_generic_param (param);
1178 gboolean is_mvar = container->is_method;
1179 gboolean is_anonymous = container->is_anonymous;
1181 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
1182 klass->class_kind = MONO_CLASS_GPARAM;
1183 UnlockedAdd (&classes_size, sizeof (MonoClassGenericParam));
1184 UnlockedIncrement (&class_gparam_count);
1186 if (!is_anonymous) {
1187 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
1188 } else {
1189 int n = mono_generic_param_num (param);
1190 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , mono_make_generic_name_string (image, n) );
1193 if (is_anonymous) {
1194 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
1195 } else if (is_mvar) {
1196 MonoMethod *omethod = container->owner.method;
1197 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
1198 } else {
1199 MonoClass *oklass = container->owner.klass;
1200 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
1203 MONO_PROFILER_RAISE (class_loading, (klass));
1205 // Count non-NULL items in pinfo->constraints
1206 count = 0;
1207 if (!is_anonymous)
1208 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
1211 pos = 0;
1212 if ((count > 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo->constraints [0])) {
1213 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
1214 pos++;
1215 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
1216 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
1217 } else {
1218 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
1221 if (count - pos > 0) {
1222 klass->interface_count = count - pos;
1223 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
1224 klass->interfaces_inited = TRUE;
1225 for (i = pos; i < count; i++)
1226 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
1229 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
1231 klass->inited = TRUE;
1232 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
1233 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
1235 MonoTypeEnum t = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
1236 klass->_byval_arg.type = t;
1237 klass->this_arg.type = t;
1238 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
1239 CHECKED_METADATA_WRITE_PTR ( klass->_byval_arg.data.generic_param , param );
1240 klass->this_arg.byref = TRUE;
1242 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1243 klass->sizes.generic_param_token = !is_anonymous ? pinfo->token : 0;
1245 /*Init these fields to sane values*/
1246 klass->min_align = 1;
1248 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1249 * constrained to, the JIT depends on this.
1251 klass->instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_stack_size_internal (m_class_get_byval_arg (klass), NULL, TRUE);
1252 mono_memory_barrier ();
1253 klass->size_inited = 1;
1255 mono_class_setup_supertypes (klass);
1257 if (count - pos > 0) {
1258 mono_class_setup_vtable (klass->parent);
1259 if (mono_class_has_failure (klass->parent))
1260 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
1261 else
1262 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
1265 return klass;
1269 * LOCKING: Acquires the image lock (@image).
1271 MonoClass *
1272 mono_class_create_generic_parameter (MonoGenericParam *param)
1274 MonoImage *image = mono_get_image_for_generic_param (param);
1275 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1276 MonoClass *klass, *klass2;
1278 // If a klass already exists for this object and is cached, return it.
1279 klass = pinfo->pklass;
1281 if (klass)
1282 return klass;
1284 // Create a new klass
1285 klass = make_generic_param_class (param);
1287 // Now we need to cache the klass we created.
1288 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1289 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1290 // and allow our newly-created klass object to just leak.
1291 mono_memory_barrier ();
1293 mono_image_lock (image);
1295 // Here "klass2" refers to the klass potentially created by the other thread.
1296 klass2 = pinfo->pklass;
1298 if (klass2) {
1299 klass = klass2;
1300 } else {
1301 pinfo->pklass = klass;
1303 mono_image_unlock (image);
1305 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1306 if (klass2)
1307 MONO_PROFILER_RAISE (class_failed, (klass2));
1308 else
1309 MONO_PROFILER_RAISE (class_loaded, (klass));
1311 return klass;
1315 * mono_class_create_ptr:
1317 MonoClass *
1318 mono_class_create_ptr (MonoType *type)
1320 MonoClass *result;
1321 MonoClass *el_class;
1322 MonoImage *image;
1323 char *name;
1324 MonoImageSet* image_set;
1326 el_class = mono_class_from_mono_type_internal (type);
1327 image = el_class->image;
1328 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)el_class->class_kind) ? mono_metadata_get_image_set_for_class (el_class) : NULL;
1330 if (image_set) {
1331 mono_image_set_lock (image_set);
1332 if (image_set->ptr_cache) {
1333 if ((result = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1334 mono_image_set_unlock (image_set);
1335 return result;
1338 mono_image_set_unlock (image_set);
1339 } else {
1340 mono_image_lock (image);
1341 if (image->ptr_cache) {
1342 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1343 mono_image_unlock (image);
1344 return result;
1347 mono_image_unlock (image);
1350 result = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
1352 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1353 ++class_pointer_count;
1355 result->parent = NULL; /* no parent for PTR types */
1356 result->name_space = el_class->name_space;
1357 name = g_strdup_printf ("%s*", el_class->name);
1358 result->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
1359 result->class_kind = MONO_CLASS_POINTER;
1360 g_free (name);
1362 MONO_PROFILER_RAISE (class_loading, (result));
1364 result->image = el_class->image;
1365 result->inited = TRUE;
1366 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1367 result->min_align = sizeof (gpointer);
1368 result->cast_class = result->element_class = el_class;
1369 result->blittable = TRUE;
1371 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_PTR;
1372 result->this_arg.data.type = result->_byval_arg.data.type = m_class_get_byval_arg (el_class);
1373 result->this_arg.byref = TRUE;
1375 mono_class_setup_supertypes (result);
1377 if (image_set) {
1378 mono_image_set_lock (image_set);
1379 if (image_set->ptr_cache) {
1380 MonoClass *result2;
1381 if ((result2 = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1382 mono_image_set_unlock (image_set);
1383 MONO_PROFILER_RAISE (class_failed, (result));
1384 return result2;
1387 else {
1388 image_set->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1390 g_hash_table_insert (image_set->ptr_cache, el_class, result);
1391 mono_image_set_unlock (image_set);
1392 } else {
1393 mono_image_lock (image);
1394 if (image->ptr_cache) {
1395 MonoClass *result2;
1396 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1397 mono_image_unlock (image);
1398 MONO_PROFILER_RAISE (class_failed, (result));
1399 return result2;
1401 } else {
1402 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1404 g_hash_table_insert (image->ptr_cache, el_class, result);
1405 mono_image_unlock (image);
1408 MONO_PROFILER_RAISE (class_loaded, (result));
1410 return result;
1413 MonoClass *
1414 mono_class_create_fnptr (MonoMethodSignature *sig)
1416 MonoClass *result, *cached;
1417 static GHashTable *ptr_hash = NULL;
1419 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1421 mono_loader_lock ();
1422 if (!ptr_hash)
1423 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1424 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1425 mono_loader_unlock ();
1426 if (cached)
1427 return cached;
1429 result = g_new0 (MonoClass, 1);
1431 result->parent = NULL; /* no parent for PTR types */
1432 result->name_space = "System";
1433 result->name = "MonoFNPtrFakeClass";
1434 result->class_kind = MONO_CLASS_POINTER;
1436 result->image = mono_defaults.corlib; /* need to fix... */
1437 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1438 result->min_align = sizeof (gpointer);
1439 result->cast_class = result->element_class = result;
1440 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_FNPTR;
1441 result->this_arg.data.method = result->_byval_arg.data.method = sig;
1442 result->this_arg.byref = TRUE;
1443 result->blittable = TRUE;
1444 result->inited = TRUE;
1446 mono_class_setup_supertypes (result);
1448 mono_loader_lock ();
1450 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1451 if (cached) {
1452 g_free (result);
1453 mono_loader_unlock ();
1454 return cached;
1457 MONO_PROFILER_RAISE (class_loading, (result));
1459 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1460 ++class_pointer_count;
1462 g_hash_table_insert (ptr_hash, sig, result);
1464 mono_loader_unlock ();
1466 MONO_PROFILER_RAISE (class_loaded, (result));
1468 return result;
1472 static void
1473 print_implemented_interfaces (MonoClass *klass)
1475 char *name;
1476 ERROR_DECL (error);
1477 GPtrArray *ifaces = NULL;
1478 int i;
1479 int ancestor_level = 0;
1481 name = mono_type_get_full_name (klass);
1482 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
1483 g_free (name);
1485 for (i = 0; i < klass->interface_offsets_count; i++) {
1486 char *ic_name = mono_type_get_full_name (klass->interfaces_packed [i]);
1487 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i,
1488 klass->interfaces_packed [i]->interface_id,
1489 klass->interface_offsets_packed [i],
1490 mono_class_get_method_count (klass->interfaces_packed [i]),
1491 ic_name);
1492 g_free (ic_name);
1494 printf ("Interface flags: ");
1495 for (i = 0; i <= klass->max_interface_id; i++)
1496 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
1497 printf ("(%d,T)", i);
1498 else
1499 printf ("(%d,F)", i);
1500 printf ("\n");
1501 printf ("Dump interface flags:");
1502 #ifdef COMPRESSED_INTERFACE_BITMAP
1504 const uint8_t* p = klass->interface_bitmap;
1505 i = klass->max_interface_id;
1506 while (i > 0) {
1507 printf (" %d x 00 %02X", p [0], p [1]);
1508 i -= p [0] * 8;
1509 i -= 8;
1512 #else
1513 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
1514 printf (" %02X", klass->interface_bitmap [i]);
1515 #endif
1516 printf ("\n");
1517 while (klass != NULL) {
1518 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
1519 ifaces = mono_class_get_implemented_interfaces (klass, error);
1520 if (!mono_error_ok (error)) {
1521 printf (" Type failed due to %s\n", mono_error_get_message (error));
1522 mono_error_cleanup (error);
1523 } else if (ifaces) {
1524 for (i = 0; i < ifaces->len; i++) {
1525 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1526 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
1527 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
1528 ic->interface_id,
1529 mono_class_interface_offset (klass, ic),
1530 mono_class_get_method_count (ic),
1531 ic->name_space,
1532 ic->name );
1534 g_ptr_array_free (ifaces, TRUE);
1536 ancestor_level ++;
1537 klass = klass->parent;
1542 * Return the number of virtual methods.
1543 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1544 * Return -1 on failure.
1545 * FIXME It would be nice if this information could be cached somewhere.
1547 static int
1548 count_virtual_methods (MonoClass *klass)
1550 int i, mcount, vcount = 0;
1551 guint32 flags;
1552 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
1554 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
1555 mono_class_setup_methods (klass);
1556 if (mono_class_has_failure (klass))
1557 return -1;
1559 mcount = mono_class_get_method_count (klass);
1560 for (i = 0; i < mcount; ++i) {
1561 flags = klass->methods [i]->flags;
1562 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
1563 ++vcount;
1565 } else {
1566 int first_idx = mono_class_get_first_method_idx (klass);
1567 mcount = mono_class_get_method_count (klass);
1568 for (i = 0; i < mcount; ++i) {
1569 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
1571 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
1572 ++vcount;
1575 return vcount;
1578 static int
1579 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
1581 int m, l = 0;
1582 if (!num_ifaces)
1583 return -1;
1584 while (1) {
1585 if (l > num_ifaces)
1586 return -1;
1587 m = (l + num_ifaces) / 2;
1588 if (interfaces_full [m] == ic)
1589 return m;
1590 if (l == num_ifaces)
1591 return -1;
1592 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
1593 num_ifaces = m - 1;
1594 } else {
1595 l = m + 1;
1600 static mono_bool
1601 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
1603 int i = find_interface (num_ifaces, interfaces_full, ic);
1604 if (i >= 0) {
1605 if (!force_set)
1606 return TRUE;
1607 interface_offsets_full [i] = offset;
1608 return FALSE;
1610 for (i = 0; i < num_ifaces; ++i) {
1611 if (interfaces_full [i]) {
1612 int end;
1613 if (interfaces_full [i]->interface_id < ic->interface_id)
1614 continue;
1615 end = i + 1;
1616 while (end < num_ifaces && interfaces_full [end]) end++;
1617 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
1618 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
1620 interfaces_full [i] = ic;
1621 interface_offsets_full [i] = offset;
1622 break;
1624 return FALSE;
1627 #ifdef COMPRESSED_INTERFACE_BITMAP
1630 * Compressed interface bitmap design.
1632 * Interface bitmaps take a large amount of memory, because their size is
1633 * linear with the maximum interface id assigned in the process (each interface
1634 * is assigned a unique id as it is loaded). The number of interface classes
1635 * is high because of the many implicit interfaces implemented by arrays (we'll
1636 * need to lazy-load them in the future).
1637 * Most classes implement a very small number of interfaces, so the bitmap is
1638 * sparse. This bitmap needs to be checked by interface casts, so access to the
1639 * needed bit must be fast and doable with few jit instructions.
1641 * The current compression format is as follows:
1642 * *) it is a sequence of one or more two-byte elements
1643 * *) the first byte in the element is the count of empty bitmap bytes
1644 * at the current bitmap position
1645 * *) the second byte in the element is an actual bitmap byte at the current
1646 * bitmap position
1648 * As an example, the following compressed bitmap bytes:
1649 * 0x07 0x01 0x00 0x7
1650 * correspond to the following bitmap:
1651 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1653 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1654 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1655 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1659 * mono_compress_bitmap:
1660 * \param dest destination buffer
1661 * \param bitmap bitmap buffer
1662 * \param size size of \p bitmap in bytes
1664 * This is a mono internal function.
1665 * The \p bitmap data is compressed into a format that is small but
1666 * still searchable in few instructions by the JIT and runtime.
1667 * The compressed data is stored in the buffer pointed to by the
1668 * \p dest array. Passing a NULL value for \p dest allows to just compute
1669 * the size of the buffer.
1670 * This compression algorithm assumes the bits set in the bitmap are
1671 * few and far between, like in interface bitmaps.
1672 * \returns The size of the compressed bitmap in bytes.
1675 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
1677 int numz = 0;
1678 int res = 0;
1679 const uint8_t *end = bitmap + size;
1680 while (bitmap < end) {
1681 if (*bitmap || numz == 255) {
1682 if (dest) {
1683 *dest++ = numz;
1684 *dest++ = *bitmap;
1686 res += 2;
1687 numz = 0;
1688 bitmap++;
1689 continue;
1691 bitmap++;
1692 numz++;
1694 if (numz) {
1695 res += 2;
1696 if (dest) {
1697 *dest++ = numz;
1698 *dest++ = 0;
1701 return res;
1705 * mono_class_interface_match:
1706 * \param bitmap a compressed bitmap buffer
1707 * \param id the index to check in the bitmap
1709 * This is a mono internal function.
1710 * Checks if a bit is set in a compressed interface bitmap. \p id must
1711 * be already checked for being smaller than the maximum id encoded in the
1712 * bitmap.
1714 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1715 * FALSE otherwise.
1718 mono_class_interface_match (const uint8_t *bitmap, int id)
1720 while (TRUE) {
1721 id -= bitmap [0] * 8;
1722 if (id < 8) {
1723 if (id < 0)
1724 return 0;
1725 return bitmap [1] & (1 << id);
1727 bitmap += 2;
1728 id -= 8;
1731 #endif
1733 typedef struct {
1734 MonoClass *ic;
1735 int offset;
1736 int insertion_order;
1737 } ClassAndOffset;
1739 static int
1740 compare_by_interface_id (const void *a, const void *b)
1742 const ClassAndOffset *ca = (const ClassAndOffset*)a;
1743 const ClassAndOffset *cb = (const ClassAndOffset*)b;
1745 /* Sort on interface_id, but keep equal elements in the same relative
1746 * order. */
1747 int primary_order = ca->ic->interface_id - cb->ic->interface_id;
1748 if (primary_order != 0)
1749 return primary_order;
1750 else
1751 return ca->insertion_order - cb->insertion_order;
1755 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1756 * LOCKING: Acquires the loader lock.
1758 static int
1759 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
1761 ERROR_DECL (error);
1762 MonoClass *k, *ic;
1763 int i, j, num_ifaces;
1764 guint32 max_iid;
1765 MonoClass **interfaces_full = NULL;
1766 int *interface_offsets_full = NULL;
1767 GPtrArray *ifaces;
1768 GPtrArray **ifaces_array = NULL;
1769 int interface_offsets_count;
1770 max_iid = 0;
1771 num_ifaces = interface_offsets_count = 0;
1773 mono_loader_lock ();
1775 mono_class_setup_supertypes (klass);
1777 if (mono_class_is_ginst (klass)) {
1778 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1780 interface_offsets_count = num_ifaces = gklass->interface_offsets_count;
1781 interfaces_full = (MonoClass **)g_malloc (sizeof (MonoClass*) * num_ifaces);
1782 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1783 ClassAndOffset *co_pair = (ClassAndOffset *) g_malloc (sizeof (ClassAndOffset) * num_ifaces);
1785 cur_slot = 0;
1786 for (int i = 0; i < num_ifaces; ++i) {
1787 MonoClass *gklass_ic = gklass->interfaces_packed [i];
1788 MonoClass *inflated = mono_class_inflate_generic_class_checked (gklass_ic, mono_class_get_context(klass), error);
1789 if (!is_ok (error)) {
1790 char *name = mono_type_get_full_name (gklass_ic);
1791 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1792 g_free (name);
1793 cur_slot = -1;
1794 goto end;
1797 mono_class_setup_interface_id_internal (inflated);
1799 co_pair [i].ic = inflated;
1800 co_pair [i].offset = gklass->interface_offsets_packed [i];
1801 co_pair [i].insertion_order = i;
1803 int count = count_virtual_methods (inflated);
1804 if (count == -1) {
1805 char *name = mono_type_get_full_name (inflated);
1806 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1807 g_free (name);
1808 cur_slot = -1;
1809 goto end;
1812 cur_slot = MAX (cur_slot, interface_offsets_full [i] + count);
1813 max_iid = MAX (max_iid, inflated->interface_id);
1816 /* qsort() is not guaranteed to be a stable sort (elements with
1817 * equal keys stay in the same relative order). In practice,
1818 * qsort from MSVC isn't stable. So we add a
1819 * ClassAndOffset:insertion_order field and use it as a
1820 * secondary sorting key when the interface ids are equal. */
1821 qsort (co_pair, num_ifaces, sizeof (ClassAndOffset), compare_by_interface_id);
1822 for (int i = 0; i < num_ifaces; ++i) {
1823 interfaces_full [i] = co_pair [i].ic;
1824 interface_offsets_full [i] = co_pair [i].offset;
1826 g_assert (i == 0 || interfaces_full [i]->interface_id >= interfaces_full [i - 1]->interface_id);
1828 g_free (co_pair);
1830 goto publish;
1832 /* compute maximum number of slots and maximum interface id */
1833 max_iid = 0;
1834 num_ifaces = 0; /* this can include duplicated ones */
1835 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
1836 for (j = 0; j < klass->idepth; j++) {
1837 k = klass->supertypes [j];
1838 g_assert (k);
1839 num_ifaces += k->interface_count;
1840 for (i = 0; i < k->interface_count; i++) {
1841 ic = k->interfaces [i];
1843 /* A gparam does not have any interface_id set. */
1844 if (! mono_class_is_gparam (ic))
1845 mono_class_setup_interface_id_internal (ic);
1847 if (max_iid < ic->interface_id)
1848 max_iid = ic->interface_id;
1850 ifaces = mono_class_get_implemented_interfaces (k, error);
1851 if (!mono_error_ok (error)) {
1852 char *name = mono_type_get_full_name (k);
1853 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (error));
1854 g_free (name);
1855 mono_error_cleanup (error);
1856 cur_slot = -1;
1857 goto end;
1859 if (ifaces) {
1860 num_ifaces += ifaces->len;
1861 for (i = 0; i < ifaces->len; ++i) {
1862 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1863 if (max_iid < ic->interface_id)
1864 max_iid = ic->interface_id;
1866 ifaces_array [j] = ifaces;
1870 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
1871 num_ifaces++;
1872 if (max_iid < klass->interface_id)
1873 max_iid = klass->interface_id;
1876 /* compute vtable offset for interfaces */
1877 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
1878 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1880 for (i = 0; i < num_ifaces; i++)
1881 interface_offsets_full [i] = -1;
1883 /* skip the current class */
1884 for (j = 0; j < klass->idepth - 1; j++) {
1885 k = klass->supertypes [j];
1886 ifaces = ifaces_array [j];
1888 if (ifaces) {
1889 for (i = 0; i < ifaces->len; ++i) {
1890 int io;
1891 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1893 /*Force the sharing of interface offsets between parent and subtypes.*/
1894 io = mono_class_interface_offset (k, ic);
1895 g_assertf (io >= 0, "class %s parent %s has no offset for iface %s",
1896 mono_type_get_full_name (klass),
1897 mono_type_get_full_name (k),
1898 mono_type_get_full_name (ic));
1900 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
1905 g_assert (klass == klass->supertypes [klass->idepth - 1]);
1906 ifaces = ifaces_array [klass->idepth - 1];
1907 if (ifaces) {
1908 for (i = 0; i < ifaces->len; ++i) {
1909 int count;
1910 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1911 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
1912 continue;
1913 count = count_virtual_methods (ic);
1914 if (count == -1) {
1915 char *name = mono_type_get_full_name (ic);
1916 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1917 g_free (name);
1918 cur_slot = -1;
1919 goto end;
1921 cur_slot += count;
1925 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass))
1926 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
1928 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
1929 if (interface_offsets_full [i] != -1)
1930 interface_offsets_count ++;
1933 publish:
1934 /* Publish the data */
1935 klass->max_interface_id = max_iid;
1937 * We might get called multiple times:
1938 * - mono_class_init_internal ()
1939 * - mono_class_setup_vtable ().
1940 * - mono_class_setup_interface_offsets ().
1941 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1942 * means we have to overwrite those when called from other places (#4440).
1944 if (klass->interfaces_packed) {
1945 if (!overwrite)
1946 g_assert (klass->interface_offsets_count == interface_offsets_count);
1947 } else {
1948 uint8_t *bitmap;
1949 int bsize;
1950 klass->interface_offsets_count = interface_offsets_count;
1951 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
1952 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
1953 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
1954 #ifdef COMPRESSED_INTERFACE_BITMAP
1955 bitmap = g_malloc0 (bsize);
1956 #else
1957 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
1958 #endif
1959 for (i = 0; i < interface_offsets_count; i++) {
1960 guint32 id = interfaces_full [i]->interface_id;
1961 bitmap [id >> 3] |= (1 << (id & 7));
1962 klass->interfaces_packed [i] = interfaces_full [i];
1963 klass->interface_offsets_packed [i] = interface_offsets_full [i];
1965 #ifdef COMPRESSED_INTERFACE_BITMAP
1966 i = mono_compress_bitmap (NULL, bitmap, bsize);
1967 klass->interface_bitmap = mono_class_alloc0 (klass, i);
1968 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
1969 g_free (bitmap);
1970 #else
1971 klass->interface_bitmap = bitmap;
1972 #endif
1974 end:
1975 mono_loader_unlock ();
1977 g_free (interfaces_full);
1978 g_free (interface_offsets_full);
1979 if (ifaces_array) {
1980 for (i = 0; i < klass->idepth; i++) {
1981 ifaces = ifaces_array [i];
1982 if (ifaces)
1983 g_ptr_array_free (ifaces, TRUE);
1985 g_free (ifaces_array);
1988 //printf ("JUST DONE: ");
1989 //print_implemented_interfaces (klass);
1991 return cur_slot;
1995 * Setup interface offsets for interfaces.
1996 * Initializes:
1997 * - klass->max_interface_id
1998 * - klass->interface_offsets_count
1999 * - klass->interfaces_packed
2000 * - klass->interface_offsets_packed
2001 * - klass->interface_bitmap
2003 * This function can fail @class.
2006 void
2007 mono_class_setup_interface_offsets (MonoClass *klass)
2009 /* NOTE: This function is only correct for interfaces.
2011 * It assumes that klass's interfaces can be assigned offsets starting
2012 * from 0. That assumption is incorrect for classes and valuetypes.
2014 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && !mono_class_is_ginst (klass));
2015 setup_interface_offsets (klass, 0, FALSE);
2018 #define DEBUG_INTERFACE_VTABLE_CODE 0
2019 #define TRACE_INTERFACE_VTABLE_CODE 0
2020 #define VERIFY_INTERFACE_VTABLE_CODE 0
2021 #define VTABLE_SELECTOR (1)
2023 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2024 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
2025 if (!(VTABLE_SELECTOR)) break; \
2026 stmt;\
2027 } while (0)
2028 #else
2029 #define DEBUG_INTERFACE_VTABLE(stmt)
2030 #endif
2032 #if TRACE_INTERFACE_VTABLE_CODE
2033 #define TRACE_INTERFACE_VTABLE(stmt) do {\
2034 if (!(VTABLE_SELECTOR)) break; \
2035 stmt;\
2036 } while (0)
2037 #else
2038 #define TRACE_INTERFACE_VTABLE(stmt)
2039 #endif
2041 #if VERIFY_INTERFACE_VTABLE_CODE
2042 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
2043 if (!(VTABLE_SELECTOR)) break; \
2044 stmt;\
2045 } while (0)
2046 #else
2047 #define VERIFY_INTERFACE_VTABLE(stmt)
2048 #endif
2051 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2052 static char*
2053 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
2055 int i;
2056 char *result;
2057 GString *res = g_string_new ("");
2059 g_string_append_c (res, '(');
2060 for (i = 0; i < sig->param_count; ++i) {
2061 if (i > 0)
2062 g_string_append_c (res, ',');
2063 mono_type_get_desc (res, sig->params [i], include_namespace);
2065 g_string_append (res, ")=>");
2066 if (sig->ret != NULL) {
2067 mono_type_get_desc (res, sig->ret, include_namespace);
2068 } else {
2069 g_string_append (res, "NULL");
2071 result = res->str;
2072 g_string_free (res, FALSE);
2073 return result;
2075 static void
2076 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
2077 char *im_sig = mono_signature_get_full_desc (mono_method_signature_internal (im), TRUE);
2078 char *cm_sig = mono_signature_get_full_desc (mono_method_signature_internal (cm), TRUE);
2079 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
2080 g_free (im_sig);
2081 g_free (cm_sig);
2085 #endif
2087 static gboolean
2088 is_wcf_hack_disabled (void)
2090 static gboolean disabled;
2091 static gboolean inited = FALSE;
2092 if (!inited) {
2093 disabled = g_hasenv ("MONO_DISABLE_WCF_HACK");
2094 inited = TRUE;
2096 return disabled;
2099 static gboolean
2100 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
2102 MonoMethodSignature *cmsig, *imsig;
2103 if (strcmp (im->name, cm->name) == 0) {
2104 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
2105 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2106 return FALSE;
2108 if (! slot_is_empty) {
2109 if (require_newslot) {
2110 if (! interface_is_explicitly_implemented_by_class) {
2111 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2112 return FALSE;
2114 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
2115 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2116 return FALSE;
2118 } else {
2119 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2122 cmsig = mono_method_signature_internal (cm);
2123 imsig = mono_method_signature_internal (im);
2124 if (!cmsig || !imsig) {
2125 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2126 return FALSE;
2129 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2130 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2131 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2132 TRACE_INTERFACE_VTABLE (printf ("]"));
2133 return FALSE;
2135 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2136 if (mono_security_core_clr_enabled ())
2137 mono_security_core_clr_check_override (klass, cm, im);
2139 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2140 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2141 char *body_name = mono_method_full_name (cm, TRUE);
2142 char *decl_name = mono_method_full_name (im, TRUE);
2143 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2144 g_free (body_name);
2145 g_free (decl_name);
2146 return FALSE;
2149 return TRUE;
2150 } else {
2151 MonoClass *ic = im->klass;
2152 const char *ic_name_space = ic->name_space;
2153 const char *ic_name = ic->name;
2154 char *subname;
2156 if (! require_newslot) {
2157 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2158 return FALSE;
2160 if (cm->klass->rank == 0) {
2161 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2162 return FALSE;
2164 cmsig = mono_method_signature_internal (cm);
2165 imsig = mono_method_signature_internal (im);
2166 if (!cmsig || !imsig) {
2167 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2168 return FALSE;
2171 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2172 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2173 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2174 TRACE_INTERFACE_VTABLE (printf ("]"));
2175 return FALSE;
2177 if (mono_class_get_image (ic) != mono_defaults.corlib) {
2178 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2179 return FALSE;
2181 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
2182 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2183 return FALSE;
2185 if ((ic_name == NULL) || ((strcmp (ic_name, "IEnumerable`1") != 0) && (strcmp (ic_name, "ICollection`1") != 0) && (strcmp (ic_name, "IList`1") != 0) && (strcmp (ic_name, "IReadOnlyList`1") != 0) && (strcmp (ic_name, "IReadOnlyCollection`1") != 0))) {
2186 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2187 return FALSE;
2190 subname = (char*)strstr (cm->name, ic_name_space);
2191 if (subname != cm->name) {
2192 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2193 return FALSE;
2195 subname += strlen (ic_name_space);
2196 if (subname [0] != '.') {
2197 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2198 return FALSE;
2200 subname ++;
2201 if (strstr (subname, ic_name) != subname) {
2202 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2203 return FALSE;
2205 subname += strlen (ic_name);
2206 if (subname [0] != '.') {
2207 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2208 return FALSE;
2210 subname ++;
2211 if (strcmp (subname, im->name) != 0) {
2212 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2213 return FALSE;
2216 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2217 if (mono_security_core_clr_enabled ())
2218 mono_security_core_clr_check_override (klass, cm, im);
2220 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2221 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2222 char *body_name = mono_method_full_name (cm, TRUE);
2223 char *decl_name = mono_method_full_name (im, TRUE);
2224 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2225 g_free (body_name);
2226 g_free (decl_name);
2227 return FALSE;
2230 return TRUE;
2234 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2235 static void
2236 foreach_override (gpointer key, gpointer value, gpointer user_data) {
2237 MonoMethod *method = key;
2238 MonoMethod *override = value;
2239 MonoClass *method_class = mono_method_get_class (method);
2240 MonoClass *override_class = mono_method_get_class (override);
2242 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
2243 m_class_get_name_space (method_class), m_class_get_name (method_class), mono_method_get_name (method),
2244 m_class_get_name_space (override_class), m_class_get_name (override_class), mono_method_get_name (override));
2246 static void
2247 print_overrides (GHashTable *override_map, const char *message) {
2248 if (override_map) {
2249 printf ("Override map \"%s\" START:\n", message);
2250 g_hash_table_foreach (override_map, foreach_override, NULL);
2251 printf ("Override map \"%s\" END.\n", message);
2252 } else {
2253 printf ("Override map \"%s\" EMPTY.\n", message);
2256 static void
2257 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
2258 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2259 int i;
2260 int parent_size;
2262 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
2264 if (print_interfaces) {
2265 print_implemented_interfaces (klass);
2266 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
2269 if (klass->parent) {
2270 parent_size = klass->parent->vtable_size;
2271 } else {
2272 parent_size = 0;
2274 for (i = 0; i < size; ++i) {
2275 MonoMethod *cm = vtable [i];
2276 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
2277 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
2279 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
2280 g_free (cm_name);
2283 g_free (full_name);
2285 #endif
2287 #if VERIFY_INTERFACE_VTABLE_CODE
2288 static int
2289 mono_method_try_get_vtable_index (MonoMethod *method)
2291 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2292 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
2293 if (imethod->declaring->is_generic)
2294 return imethod->declaring->slot;
2296 return method->slot;
2299 static void
2300 mono_class_verify_vtable (MonoClass *klass)
2302 int i, count;
2303 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2305 printf ("*** Verifying VTable of class '%s' \n", full_name);
2306 g_free (full_name);
2307 full_name = NULL;
2309 if (!klass->methods)
2310 return;
2312 count = mono_class_get_method_count (klass);
2313 for (i = 0; i < count; ++i) {
2314 MonoMethod *cm = klass->methods [i];
2315 int slot;
2317 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2318 continue;
2320 g_free (full_name);
2321 full_name = mono_method_full_name (cm, TRUE);
2323 slot = mono_method_try_get_vtable_index (cm);
2324 if (slot >= 0) {
2325 if (slot >= klass->vtable_size) {
2326 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
2327 continue;
2330 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
2331 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
2332 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
2333 g_free (other_name);
2335 } else
2336 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
2338 g_free (full_name);
2340 #endif
2342 static MonoMethod*
2343 mono_method_get_method_definition (MonoMethod *method)
2345 while (method->is_inflated)
2346 method = ((MonoMethodInflated*)method)->declaring;
2347 return method;
2350 static gboolean
2351 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
2353 int i;
2355 for (i = 0; i < onum; ++i) {
2356 MonoMethod *decl = overrides [i * 2];
2357 MonoMethod *body = overrides [i * 2 + 1];
2359 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
2360 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
2361 return FALSE;
2364 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
2365 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2366 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
2367 else
2368 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
2369 return FALSE;
2372 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
2373 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2374 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
2375 else
2376 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
2377 return FALSE;
2380 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
2381 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
2382 return FALSE;
2385 body = mono_method_get_method_definition (body);
2386 decl = mono_method_get_method_definition (decl);
2388 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
2389 char *body_name = mono_method_full_name (body, TRUE);
2390 char *decl_name = mono_method_full_name (decl, TRUE);
2391 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2392 g_free (body_name);
2393 g_free (decl_name);
2394 return FALSE;
2397 return TRUE;
2400 /*Checks if @klass has @parent as one of it's parents type gtd
2402 * For example:
2403 * Foo<T>
2404 * Bar<T> : Foo<Bar<Bar<T>>>
2407 static gboolean
2408 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
2410 klass = mono_class_get_generic_type_definition (klass);
2411 parent = mono_class_get_generic_type_definition (parent);
2412 mono_class_setup_supertypes (klass);
2413 mono_class_setup_supertypes (parent);
2415 return klass->idepth >= parent->idepth &&
2416 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
2419 gboolean
2420 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
2422 MonoGenericInst *ginst;
2423 int i;
2425 if (!mono_class_is_ginst (klass)) {
2426 mono_class_setup_vtable_full (klass, in_setup);
2427 return !mono_class_has_failure (klass);
2430 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
2431 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
2432 return FALSE;
2434 ginst = mono_class_get_generic_class (klass)->context.class_inst;
2435 for (i = 0; i < ginst->type_argc; ++i) {
2436 MonoClass *arg;
2437 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
2438 continue;
2439 arg = mono_class_from_mono_type_internal (ginst->type_argv [i]);
2440 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2441 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
2442 continue;
2443 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
2444 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
2445 return FALSE;
2448 return TRUE;
2452 * mono_class_setup_vtable:
2454 * Creates the generic vtable of CLASS.
2455 * Initializes the following fields in MonoClass:
2456 * - vtable
2457 * - vtable_size
2458 * Plus all the fields initialized by setup_interface_offsets ().
2459 * If there is an error during vtable construction, klass->has_failure
2460 * is set and details are stored in a MonoErrorBoxed.
2462 * LOCKING: Acquires the loader lock.
2464 void
2465 mono_class_setup_vtable (MonoClass *klass)
2467 mono_class_setup_vtable_full (klass, NULL);
2470 static void
2471 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
2473 ERROR_DECL (error);
2474 MonoMethod **overrides = NULL;
2475 MonoGenericContext *context;
2476 guint32 type_token;
2477 int onum = 0;
2479 if (klass->vtable)
2480 return;
2482 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
2483 /* This sets method->slot for all methods if this is an interface */
2484 mono_class_setup_methods (klass);
2485 return;
2488 if (mono_class_has_failure (klass))
2489 return;
2491 if (g_list_find (in_setup, klass))
2492 return;
2494 mono_loader_lock ();
2496 if (klass->vtable) {
2497 mono_loader_unlock ();
2498 return;
2501 UnlockedIncrement (&mono_stats.generic_vtable_count);
2502 in_setup = g_list_prepend (in_setup, klass);
2504 if (mono_class_is_ginst (klass)) {
2505 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
2506 mono_loader_unlock ();
2507 g_list_remove (in_setup, klass);
2508 return;
2511 context = mono_class_get_context (klass);
2512 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
2513 } else {
2514 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
2515 type_token = klass->type_token;
2518 if (image_is_dynamic (klass->image)) {
2519 /* Generic instances can have zero method overrides without causing any harm.
2520 * This is true since we don't do layout all over again for them, we simply inflate
2521 * the layout of the parent.
2523 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, error);
2524 if (!is_ok (error)) {
2525 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2526 goto done;
2528 } else {
2529 /* The following call fails if there are missing methods in the type */
2530 /* FIXME it's probably a good idea to avoid this for generic instances. */
2531 mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context, error);
2532 if (!is_ok (error)) {
2533 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2534 goto done;
2538 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
2540 done:
2541 g_free (overrides);
2542 mono_error_cleanup (error);
2544 mono_loader_unlock ();
2545 g_list_remove (in_setup, klass);
2547 return;
2550 static gboolean
2551 mono_class_need_stelemref_method (MonoClass *klass)
2553 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass)));
2556 static int
2557 apply_override (MonoClass *klass, MonoClass *override_class, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override,
2558 GHashTable **override_map, GHashTable **override_class_map, GHashTable **conflict_map)
2560 int dslot;
2561 dslot = mono_method_get_vtable_slot (decl);
2562 if (dslot == -1) {
2563 mono_class_set_type_load_failure (klass, "");
2564 return FALSE;
2567 dslot += mono_class_interface_offset (klass, decl->klass);
2568 vtable [dslot] = override;
2569 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass)) {
2571 * If override from an interface, then it is an override of a default interface method,
2572 * don't override its slot.
2574 vtable [dslot]->slot = dslot;
2577 if (!*override_map) {
2578 *override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2579 *override_class_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2581 GHashTable *map = *override_map;
2582 GHashTable *class_map = *override_class_map;
2584 MonoMethod *prev_override = (MonoMethod*)g_hash_table_lookup (map, decl);
2585 MonoClass *prev_override_class = (MonoClass*)g_hash_table_lookup (class_map, decl);
2587 g_hash_table_insert (map, decl, override);
2588 g_hash_table_insert (class_map, decl, override_class);
2590 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2591 if (prev_override) {
2592 ERROR_DECL (error);
2595 * The override methods are part of the generic definition, need to inflate them so their
2596 * parent class becomes the actual interface/class containing the override, i.e.
2597 * IFace<T> in:
2598 * class Foo<T> : IFace<T>
2599 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2600 * conflict resolution work.
2602 if (mono_class_is_ginst (override_class)) {
2603 override = mono_class_inflate_generic_method_checked (override, &mono_class_get_generic_class (override_class)->context, error);
2604 mono_error_assert_ok (error);
2607 if (mono_class_is_ginst (prev_override_class)) {
2608 prev_override = mono_class_inflate_generic_method_checked (prev_override, &mono_class_get_generic_class (prev_override_class)->context, error);
2609 mono_error_assert_ok (error);
2612 if (!*conflict_map)
2613 *conflict_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2614 GHashTable *cmap = *conflict_map;
2615 GSList *entries = (GSList*)g_hash_table_lookup (cmap, decl);
2616 if (!(decl->flags & METHOD_ATTRIBUTE_ABSTRACT))
2617 entries = g_slist_prepend (entries, decl);
2618 entries = g_slist_prepend (entries, prev_override);
2619 entries = g_slist_prepend (entries, override);
2621 g_hash_table_insert (cmap, decl, entries);
2624 return TRUE;
2627 static void
2628 handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflict_map)
2630 GHashTableIter iter;
2631 MonoMethod *decl;
2632 GSList *entries, *l, *l2;
2633 GSList *dim_conflicts = NULL;
2635 g_hash_table_iter_init (&iter, conflict_map);
2636 while (g_hash_table_iter_next (&iter, (gpointer*)&decl, (gpointer*)&entries)) {
2638 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2639 * class of another one.
2641 /* This is O(n^2), but that shouldn't be a problem in practice */
2642 for (l = entries; l; l = l->next) {
2643 for (l2 = entries; l2; l2 = l2->next) {
2644 MonoMethod *m1 = (MonoMethod*)l->data;
2645 MonoMethod *m2 = (MonoMethod*)l2->data;
2646 if (!m1 || !m2 || m1 == m2)
2647 continue;
2648 if (mono_class_is_assignable_from_internal (m1->klass, m2->klass))
2649 l->data = NULL;
2650 else if (mono_class_is_assignable_from_internal (m2->klass, m1->klass))
2651 l2->data = NULL;
2654 int nentries = 0;
2655 MonoMethod *impl = NULL;
2656 for (l = entries; l; l = l->next) {
2657 if (l->data) {
2658 nentries ++;
2659 impl = (MonoMethod*)l->data;
2662 if (nentries > 1) {
2663 /* If more than one method is left, we have a conflict */
2664 if (decl->is_inflated)
2665 decl = ((MonoMethodInflated*)decl)->declaring;
2666 dim_conflicts = g_slist_prepend (dim_conflicts, decl);
2668 for (l = entries; l; l = l->next) {
2669 if (l->data)
2670 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2673 } else {
2675 * Use the implementing method computed above instead of the already
2676 * computed one, which depends on interface ordering.
2678 int ic_offset = mono_class_interface_offset (klass, decl->klass);
2679 int im_slot = ic_offset + decl->slot;
2680 vtable [im_slot] = impl;
2682 g_slist_free (entries);
2684 if (dim_conflicts) {
2685 mono_loader_lock ();
2686 klass->has_dim_conflicts = 1;
2687 mono_loader_unlock ();
2690 * Exceptions are thrown at method call time and only for the methods which have
2691 * conflicts, so just save them in the class.
2694 /* Make a copy of the list from the class mempool */
2695 GSList *conflicts = (GSList*)mono_class_alloc0 (klass, g_slist_length (dim_conflicts) * sizeof (GSList));
2696 int i = 0;
2697 for (l = dim_conflicts; l; l = l->next) {
2698 conflicts [i].data = l->data;
2699 conflicts [i].next = &conflicts [i + 1];
2700 i ++;
2702 conflicts [i - 1].next = NULL;
2704 mono_class_set_dim_conflicts (klass, conflicts);
2705 g_slist_free (dim_conflicts);
2709 static void
2710 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
2712 int index, mcount;
2713 char *method_signature;
2714 char *type_name;
2716 for (index = 0; index < onum; ++index) {
2717 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name,
2718 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
2720 method_signature = mono_signature_get_desc (mono_method_signature_internal (im), FALSE);
2721 type_name = mono_type_full_name (m_class_get_byval_arg (klass));
2722 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s",
2723 mono_type_get_name (m_class_get_byval_arg (ic)), im->name, method_signature, type_name);
2724 g_free (method_signature);
2725 g_free (type_name);
2726 mono_class_setup_methods (klass);
2727 if (mono_class_has_failure (klass)) {
2728 char *name = mono_type_get_full_name (klass);
2729 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name);
2730 g_free (name);
2731 return;
2733 mcount = mono_class_get_method_count (klass);
2734 for (index = 0; index < mcount; ++index) {
2735 MonoMethod *cm = klass->methods [index];
2736 method_signature = mono_signature_get_desc (mono_method_signature_internal (cm), TRUE);
2738 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature);
2739 g_free (method_signature);
2744 * mono_class_get_virtual_methods:
2746 * Iterate over the virtual methods of KLASS.
2748 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2750 static MonoMethod*
2751 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
2753 gboolean static_iter = FALSE;
2755 if (!iter)
2756 return NULL;
2759 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2760 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2761 * klass->methods.
2763 if ((gsize)(*iter) & 1)
2764 static_iter = TRUE;
2765 /* Use the static metadata only if klass->methods is not yet initialized */
2766 if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
2767 static_iter = TRUE;
2769 if (!static_iter) {
2770 MonoMethod** methodptr;
2772 if (!*iter) {
2773 mono_class_setup_methods (klass);
2775 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2776 * FIXME we should better report this error to the caller
2778 if (!klass->methods)
2779 return NULL;
2780 /* start from the first */
2781 methodptr = &klass->methods [0];
2782 } else {
2783 methodptr = (MonoMethod **)*iter;
2784 methodptr++;
2786 if (*iter)
2787 g_assert ((guint64)(*iter) > 0x100);
2788 int mcount = mono_class_get_method_count (klass);
2789 while (methodptr < &klass->methods [mcount]) {
2790 if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
2791 break;
2792 methodptr ++;
2794 if (methodptr < &klass->methods [mcount]) {
2795 *iter = methodptr;
2796 return *methodptr;
2797 } else {
2798 return NULL;
2800 } else {
2801 /* Search directly in metadata to avoid calling setup_methods () */
2802 MonoMethod *res = NULL;
2803 int i, start_index;
2805 if (!*iter) {
2806 start_index = 0;
2807 } else {
2808 start_index = GPOINTER_TO_UINT (*iter) >> 1;
2811 int first_idx = mono_class_get_first_method_idx (klass);
2812 int mcount = mono_class_get_method_count (klass);
2813 for (i = start_index; i < mcount; ++i) {
2814 guint32 flags;
2816 /* first_idx points into the methodptr table */
2817 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
2819 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2820 break;
2823 if (i < mcount) {
2824 ERROR_DECL (error);
2825 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
2826 mono_error_cleanup (error); /* FIXME don't swallow the error */
2828 /* Add 1 here so the if (*iter) check fails */
2829 *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1);
2830 return res;
2831 } else {
2832 return NULL;
2837 static void
2838 print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot)
2840 int i, icount = 0;
2842 print_implemented_interfaces (klass);
2844 for (i = 0; i <= klass->max_interface_id; i++)
2845 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2846 icount++;
2848 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass)),
2849 klass->vtable_size, icount);
2851 for (i = 0; i < cur_slot; ++i) {
2852 MonoMethod *cm;
2854 cm = vtable [i];
2855 if (cm) {
2856 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
2857 mono_method_full_name (cm, TRUE));
2858 } else {
2859 printf (" slot assigned: %03d, <null>\n", i);
2864 if (icount) {
2865 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
2866 klass->name, klass->max_interface_id);
2868 for (i = 0; i < klass->interface_count; i++) {
2869 MonoClass *ic = klass->interfaces [i];
2870 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2871 mono_class_interface_offset (klass, ic),
2872 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2875 for (MonoClass *k = klass->parent; k ; k = k->parent) {
2876 for (i = 0; i < k->interface_count; i++) {
2877 MonoClass *ic = k->interfaces [i];
2878 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2879 mono_class_interface_offset (klass, ic),
2880 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2887 * LOCKING: this is supposed to be called with the loader lock held.
2889 void
2890 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
2892 ERROR_DECL (error);
2893 MonoClass *k, *ic;
2894 MonoMethod **vtable = NULL;
2895 int i, max_vtsize = 0, cur_slot = 0;
2896 GPtrArray *ifaces = NULL;
2897 GHashTable *override_map = NULL;
2898 GHashTable *override_class_map = NULL;
2899 GHashTable *conflict_map = NULL;
2900 MonoMethod *cm;
2901 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2902 int first_non_interface_slot;
2903 #endif
2904 GSList *virt_methods = NULL, *l;
2905 int stelemref_slot = 0;
2907 error_init (error);
2909 if (klass->vtable)
2910 return;
2912 if (overrides && !verify_class_overrides (klass, overrides, onum))
2913 return;
2915 ifaces = mono_class_get_implemented_interfaces (klass, error);
2916 if (!mono_error_ok (error)) {
2917 char *name = mono_type_get_full_name (klass);
2918 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (error));
2919 g_free (name);
2920 mono_error_cleanup (error);
2921 return;
2922 } else if (ifaces) {
2923 for (i = 0; i < ifaces->len; i++) {
2924 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2925 max_vtsize += mono_class_get_method_count (ic);
2927 g_ptr_array_free (ifaces, TRUE);
2928 ifaces = NULL;
2931 if (klass->parent) {
2932 mono_class_init_internal (klass->parent);
2933 mono_class_setup_vtable_full (klass->parent, in_setup);
2935 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
2936 return;
2938 max_vtsize += klass->parent->vtable_size;
2939 cur_slot = klass->parent->vtable_size;
2942 max_vtsize += mono_class_get_method_count (klass);
2944 /*Array have a slot for stelemref*/
2945 if (mono_class_need_stelemref_method (klass)) {
2946 stelemref_slot = cur_slot;
2947 ++max_vtsize;
2948 ++cur_slot;
2951 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
2953 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
2954 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
2955 return;
2957 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
2959 /* Optimized version for generic instances */
2960 if (mono_class_is_ginst (klass)) {
2961 ERROR_DECL (error);
2962 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2963 MonoMethod **tmp;
2965 mono_class_setup_vtable_full (gklass, in_setup);
2966 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
2967 return;
2969 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
2970 klass->vtable_size = gklass->vtable_size;
2971 for (i = 0; i < gklass->vtable_size; ++i)
2972 if (gklass->vtable [i]) {
2973 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), error);
2974 goto_if_nok (error, fail);
2975 tmp [i] = inflated;
2976 tmp [i]->slot = gklass->vtable [i]->slot;
2978 mono_memory_barrier ();
2979 klass->vtable = tmp;
2981 mono_loader_lock ();
2982 klass->has_dim_conflicts = gklass->has_dim_conflicts;
2983 mono_loader_unlock ();
2985 /* Have to set method->slot for abstract virtual methods */
2986 if (klass->methods && gklass->methods) {
2987 int mcount = mono_class_get_method_count (klass);
2988 for (i = 0; i < mcount; ++i)
2989 if (klass->methods [i]->slot == -1)
2990 klass->methods [i]->slot = gklass->methods [i]->slot;
2993 if (mono_print_vtable)
2994 print_vtable_layout_result (klass, klass->vtable, gklass->vtable_size);
2996 return;
2999 vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize);
3001 if (klass->parent && klass->parent->vtable_size) {
3002 MonoClass *parent = klass->parent;
3003 int i;
3005 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
3007 // Also inherit parent interface vtables, just as a starting point.
3008 // This is needed otherwise bug-77127.exe fails when the property methods
3009 // have different names in the iterface and the class, because for child
3010 // classes the ".override" information is not used anymore.
3011 for (i = 0; i < parent->interface_offsets_count; i++) {
3012 MonoClass *parent_interface = parent->interfaces_packed [i];
3013 int interface_offset = mono_class_interface_offset (klass, parent_interface);
3014 /*FIXME this is now dead code as this condition will never hold true.
3015 Since interface offsets are inherited then the offset of an interface implemented
3016 by a parent will never be the out of it's vtable boundary.
3018 if (interface_offset >= parent->vtable_size) {
3019 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
3020 int j;
3022 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
3023 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
3024 int mcount = mono_class_get_method_count (parent_interface);
3025 for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
3026 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
3027 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
3028 parent_interface_offset + j, parent_interface_offset, j,
3029 interface_offset + j, interface_offset, j));
3036 /*Array have a slot for stelemref*/
3037 if (mono_class_need_stelemref_method (klass)) {
3038 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
3039 if (!method->slot)
3040 method->slot = stelemref_slot;
3041 else
3042 g_assert (method->slot == stelemref_slot);
3044 vtable [stelemref_slot] = method;
3047 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
3049 /* Process overrides from interface default methods */
3050 // FIXME: Ordering between interfaces
3051 for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
3052 ic = klass->interfaces_packed [ifindex];
3054 mono_class_setup_methods (ic);
3055 if (mono_class_has_failure (ic))
3056 goto fail;
3058 MonoMethod **iface_overrides;
3059 int iface_onum;
3060 mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic), error);
3061 goto_if_nok (error, fail);
3062 for (int i = 0; i < iface_onum; i++) {
3063 MonoMethod *decl = iface_overrides [i*2];
3064 MonoMethod *override = iface_overrides [i*2 + 1];
3065 if (!apply_override (klass, ic, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3066 goto fail;
3068 g_free (iface_overrides);
3071 /* override interface methods */
3072 for (i = 0; i < onum; i++) {
3073 MonoMethod *decl = overrides [i*2];
3074 MonoMethod *override = overrides [i*2 + 1];
3075 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3076 if (!apply_override (klass, klass, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
3077 goto fail;
3081 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
3082 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
3085 * Create a list of virtual methods to avoid calling
3086 * mono_class_get_virtual_methods () which is slow because of the metadata
3087 * optimization.
3090 gpointer iter = NULL;
3091 MonoMethod *cm;
3093 virt_methods = NULL;
3094 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
3095 virt_methods = g_slist_prepend (virt_methods, cm);
3097 if (mono_class_has_failure (klass))
3098 goto fail;
3101 // Loop on all implemented interfaces...
3102 for (i = 0; i < klass->interface_offsets_count; i++) {
3103 MonoClass *parent = klass->parent;
3104 int ic_offset;
3105 gboolean interface_is_explicitly_implemented_by_class;
3106 int im_index;
3108 ic = klass->interfaces_packed [i];
3109 ic_offset = mono_class_interface_offset (klass, ic);
3111 mono_class_setup_methods (ic);
3112 if (mono_class_has_failure (ic))
3113 goto fail;
3115 // Check if this interface is explicitly implemented (instead of just inherited)
3116 if (parent != NULL) {
3117 int implemented_interfaces_index;
3118 interface_is_explicitly_implemented_by_class = FALSE;
3119 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
3120 if (ic == klass->interfaces [implemented_interfaces_index]) {
3121 interface_is_explicitly_implemented_by_class = TRUE;
3122 break;
3125 } else {
3126 interface_is_explicitly_implemented_by_class = TRUE;
3129 // Loop on all interface methods...
3130 int mcount = mono_class_get_method_count (ic);
3131 for (im_index = 0; im_index < mcount; im_index++) {
3132 MonoMethod *im = ic->methods [im_index];
3133 int im_slot = ic_offset + im->slot;
3134 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
3136 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3137 continue;
3139 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
3141 // If there is an explicit implementation, just use it right away,
3142 // otherwise look for a matching method
3143 if (override_im == NULL) {
3144 int cm_index;
3145 MonoMethod *cm;
3147 // First look for a suitable method among the class methods
3148 for (l = virt_methods; l; l = l->next) {
3149 cm = (MonoMethod *)l->data;
3150 TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL)));
3151 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
3152 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3153 vtable [im_slot] = cm;
3154 /* Why do we need this? */
3155 if (cm->slot < 0) {
3156 cm->slot = im_slot;
3159 TRACE_INTERFACE_VTABLE (printf ("\n"));
3160 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3161 goto fail;
3164 // If the slot is still empty, look in all the inherited virtual methods...
3165 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
3166 MonoClass *parent = klass->parent;
3167 // Reverse order, so that last added methods are preferred
3168 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
3169 MonoMethod *cm = parent->vtable [cm_index];
3171 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot, ic->name_space, ic->name, im->name, cm->klass->name_space, cm->klass->name, cm->name));
3172 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
3173 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3174 vtable [im_slot] = cm;
3175 /* Why do we need this? */
3176 if (cm->slot < 0) {
3177 cm->slot = im_slot;
3179 break;
3181 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3182 goto fail;
3183 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
3187 if (vtable [im_slot] == NULL) {
3188 if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
3189 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im, 1)));
3190 vtable [im_slot] = im;
3193 } else {
3194 g_assert (vtable [im_slot] == override_im);
3199 // If the class is not abstract, check that all its interface slots are full.
3200 // The check is done here and not directly at the end of the loop above because
3201 // it can happen (for injected generic array interfaces) that the same slot is
3202 // processed multiple times (those interfaces have overlapping slots), and it
3203 // will not always be the first pass the one that fills the slot.
3204 if (!mono_class_is_abstract (klass)) {
3205 for (i = 0; i < klass->interface_offsets_count; i++) {
3206 int ic_offset;
3207 int im_index;
3209 ic = klass->interfaces_packed [i];
3210 ic_offset = mono_class_interface_offset (klass, ic);
3212 int mcount = mono_class_get_method_count (ic);
3213 for (im_index = 0; im_index < mcount; im_index++) {
3214 MonoMethod *im = ic->methods [im_index];
3215 int im_slot = ic_offset + im->slot;
3217 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3218 continue;
3220 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3221 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
3222 if (vtable [im_slot] == NULL) {
3223 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
3224 goto fail;
3230 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
3231 for (l = virt_methods; l; l = l->next) {
3232 cm = (MonoMethod *)l->data;
3234 * If the method is REUSE_SLOT, we must check in the
3235 * base class for a method to override.
3237 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3238 int slot = -1;
3239 for (k = klass->parent; k ; k = k->parent) {
3240 gpointer k_iter;
3241 MonoMethod *m1;
3243 k_iter = NULL;
3244 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
3245 MonoMethodSignature *cmsig, *m1sig;
3247 cmsig = mono_method_signature_internal (cm);
3248 m1sig = mono_method_signature_internal (m1);
3250 if (!cmsig || !m1sig) /* FIXME proper error message, use signature_checked? */
3251 goto fail;
3253 if (!strcmp(cm->name, m1->name) &&
3254 mono_metadata_signature_equal (cmsig, m1sig)) {
3256 if (mono_security_core_clr_enabled ())
3257 mono_security_core_clr_check_override (klass, cm, m1);
3259 slot = mono_method_get_vtable_slot (m1);
3260 if (slot == -1)
3261 goto fail;
3263 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
3264 char *body_name = mono_method_full_name (cm, TRUE);
3265 char *decl_name = mono_method_full_name (m1, TRUE);
3266 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3267 g_free (body_name);
3268 g_free (decl_name);
3269 goto fail;
3272 g_assert (cm->slot < max_vtsize);
3273 if (!override_map)
3274 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3275 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3276 mono_method_full_name (m1, 1), m1,
3277 mono_method_full_name (cm, 1), cm));
3278 g_hash_table_insert (override_map, m1, cm);
3279 break;
3282 if (mono_class_has_failure (k))
3283 goto fail;
3285 if (slot >= 0)
3286 break;
3288 if (slot >= 0)
3289 cm->slot = slot;
3292 /*Non final newslot methods must be given a non-interface vtable slot*/
3293 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
3294 cm->slot = -1;
3296 if (cm->slot < 0)
3297 cm->slot = cur_slot++;
3299 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
3300 vtable [cm->slot] = cm;
3303 /* override non interface methods */
3304 for (i = 0; i < onum; i++) {
3305 MonoMethod *decl = overrides [i*2];
3306 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3307 g_assert (decl->slot != -1);
3308 vtable [decl->slot] = overrides [i*2 + 1];
3309 overrides [i * 2 + 1]->slot = decl->slot;
3310 if (!override_map)
3311 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3312 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3313 mono_method_full_name (decl, 1), decl,
3314 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
3315 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
3317 if (mono_security_core_clr_enabled ())
3318 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
3323 * If a method occupies more than one place in the vtable, and it is
3324 * overriden, then change the other occurances too.
3326 if (override_map) {
3327 MonoMethod *cm;
3329 for (i = 0; i < max_vtsize; ++i)
3330 if (vtable [i]) {
3331 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
3333 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
3334 if (cm)
3335 vtable [i] = cm;
3338 g_hash_table_destroy (override_map);
3339 override_map = NULL;
3342 if (override_class_map)
3343 g_hash_table_destroy (override_class_map);
3345 if (conflict_map) {
3346 handle_dim_conflicts (vtable, klass, conflict_map);
3347 g_hash_table_destroy (conflict_map);
3350 g_slist_free (virt_methods);
3351 virt_methods = NULL;
3353 g_assert (cur_slot <= max_vtsize);
3355 /* Ensure that all vtable slots are filled with concrete instance methods */
3356 if (!mono_class_is_abstract (klass)) {
3357 for (i = 0; i < cur_slot; ++i) {
3358 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
3359 char *type_name = mono_type_get_full_name (klass);
3360 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
3361 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
3362 g_free (type_name);
3363 g_free (method_name);
3365 if (mono_print_vtable)
3366 print_vtable_layout_result (klass, vtable, cur_slot);
3368 g_free (vtable);
3369 return;
3374 if (mono_class_is_ginst (klass)) {
3375 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3377 mono_class_init_internal (gklass);
3379 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
3380 } else {
3381 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
3382 if (klass->vtable_size)
3383 g_assert (cur_slot == klass->vtable_size);
3384 klass->vtable_size = cur_slot;
3387 /* Try to share the vtable with our parent. */
3388 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
3389 mono_memory_barrier ();
3390 klass->vtable = klass->parent->vtable;
3391 } else {
3392 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
3393 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
3394 mono_memory_barrier ();
3395 klass->vtable = tmp;
3398 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
3399 if (mono_print_vtable)
3400 print_vtable_layout_result (klass, vtable, cur_slot);
3402 g_free (vtable);
3404 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
3405 return;
3407 fail:
3409 char *name = mono_type_get_full_name (klass);
3410 if (!is_ok (error))
3411 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (error));
3412 else
3413 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
3414 mono_error_cleanup (error);
3415 g_free (name);
3416 if (mono_print_vtable)
3417 print_vtable_layout_result (klass, vtable, cur_slot);
3420 g_free (vtable);
3421 if (override_map)
3422 g_hash_table_destroy (override_map);
3423 if (virt_methods)
3424 g_slist_free (virt_methods);
3428 static char*
3429 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
3431 int null_length = strlen ("(null)");
3432 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
3433 char *s = (char *)mono_image_alloc (image, len);
3434 int result;
3436 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
3437 g_assert (result == len - 1);
3439 return s;
3443 static void
3444 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
3446 if (cached_info) {
3447 mono_loader_lock ();
3448 klass->instance_size = cached_info->instance_size;
3449 klass->sizes.class_size = cached_info->class_size;
3450 klass->packing_size = cached_info->packing_size;
3451 klass->min_align = cached_info->min_align;
3452 klass->blittable = cached_info->blittable;
3453 klass->has_references = cached_info->has_references;
3454 klass->has_static_refs = cached_info->has_static_refs;
3455 klass->no_special_static_fields = cached_info->no_special_static_fields;
3456 klass->has_weak_fields = cached_info->has_weak_fields;
3457 mono_loader_unlock ();
3459 else {
3460 if (!klass->size_inited)
3461 mono_class_setup_fields (klass);
3466 * mono_class_init_sizes:
3468 * Initializes the size related fields of @klass without loading all field data if possible.
3469 * Sets the following fields in @klass:
3470 * - instance_size
3471 * - sizes.class_size
3472 * - packing_size
3473 * - min_align
3474 * - blittable
3475 * - has_references
3476 * - has_static_refs
3477 * - size_inited
3478 * Can fail the class.
3480 * LOCKING: Acquires the loader lock.
3482 void
3483 mono_class_init_sizes (MonoClass *klass)
3485 MonoCachedClassInfo cached_info;
3486 gboolean has_cached_info;
3488 if (klass->size_inited)
3489 return;
3491 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
3493 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
3497 static gboolean
3498 class_has_references (MonoClass *klass)
3500 mono_class_init_sizes (klass);
3503 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3504 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3505 * embed themselves.
3507 return klass->has_references;
3510 static gboolean
3511 type_has_references (MonoClass *klass, MonoType *ftype)
3513 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)))))
3514 return TRUE;
3515 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
3516 MonoGenericParam *gparam = ftype->data.generic_param;
3518 if (gparam->gshared_constraint)
3519 return class_has_references (mono_class_from_mono_type_internal (gparam->gshared_constraint));
3521 return FALSE;
3525 * mono_class_layout_fields:
3526 * @class: a class
3527 * @base_instance_size: base instance size
3528 * @packing_size:
3530 * This contains the common code for computing the layout of classes and sizes.
3531 * This should only be called from mono_class_setup_fields () and
3532 * typebuilder_setup_fields ().
3534 * LOCKING: Acquires the loader lock
3536 void
3537 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int explicit_size, gboolean sre)
3539 int i;
3540 const int top = mono_class_get_field_count (klass);
3541 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
3542 guint32 pass, passes, real_size;
3543 gboolean gc_aware_layout = FALSE;
3544 gboolean has_static_fields = FALSE;
3545 gboolean has_references = FALSE;
3546 gboolean has_static_refs = FALSE;
3547 MonoClassField *field;
3548 gboolean blittable;
3549 int instance_size = base_instance_size;
3550 int element_size = -1;
3551 int class_size, min_align;
3552 int *field_offsets;
3553 gboolean *fields_has_references;
3556 * We want to avoid doing complicated work inside locks, so we compute all the required
3557 * information and write it to @klass inside a lock.
3559 if (klass->fields_inited)
3560 return;
3562 if ((packing_size & 0xffffff00) != 0) {
3563 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
3564 return;
3567 if (klass->parent) {
3568 min_align = klass->parent->min_align;
3569 /* we use | since it may have been set already */
3570 has_references = klass->has_references | klass->parent->has_references;
3571 } else {
3572 min_align = 1;
3574 /* We can't really enable 16 bytes alignment until the GC supports it.
3575 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3576 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3577 Bug #506144 is an example of this issue.
3579 if (klass->simd_type)
3580 min_align = 16;
3584 * When we do generic sharing we need to have layout
3585 * information for open generic classes (either with a generic
3586 * context containing type variables or with a generic
3587 * container), so we don't return in that case anymore.
3590 if (klass->enumtype) {
3591 for (i = 0; i < top; i++) {
3592 field = &klass->fields [i];
3593 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3594 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (field->type);
3595 break;
3599 if (!mono_class_enum_basetype_internal (klass)) {
3600 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
3601 return;
3606 * Enable GC aware auto layout: in this mode, reference
3607 * fields are grouped together inside objects, increasing collector
3608 * performance.
3609 * Requires that all classes whose layout is known to native code be annotated
3610 * with [StructLayout (LayoutKind.Sequential)]
3611 * Value types have gc_aware_layout disabled by default, as per
3612 * what the default is for other runtimes.
3614 /* corlib is missing [StructLayout] directives in many places */
3615 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
3616 if (!klass->valuetype)
3617 gc_aware_layout = TRUE;
3620 /* Compute klass->blittable */
3621 blittable = TRUE;
3622 if (klass->parent)
3623 blittable = klass->parent->blittable;
3624 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
3625 blittable = FALSE;
3626 for (i = 0; i < top; i++) {
3627 field = &klass->fields [i];
3629 if (mono_field_is_deleted (field))
3630 continue;
3631 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3632 continue;
3633 if (blittable) {
3634 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
3635 blittable = FALSE;
3636 } else {
3637 MonoClass *field_class = mono_class_from_mono_type_internal (field->type);
3638 if (field_class) {
3639 mono_class_setup_fields (field_class);
3640 if (mono_class_has_failure (field_class)) {
3641 ERROR_DECL (field_error);
3642 mono_error_set_for_class_failure (field_error, field_class);
3643 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (field_error));
3644 mono_error_cleanup (field_error);
3645 break;
3648 if (!field_class || !field_class->blittable)
3649 blittable = FALSE;
3652 if (klass->enumtype)
3653 blittable = klass->element_class->blittable;
3655 if (mono_class_has_failure (klass))
3656 return;
3657 if (klass == mono_defaults.string_class)
3658 blittable = FALSE;
3660 /* Compute klass->has_references */
3662 * Process non-static fields first, since static fields might recursively
3663 * refer to the class itself.
3665 for (i = 0; i < top; i++) {
3666 MonoType *ftype;
3668 field = &klass->fields [i];
3670 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3671 ftype = mono_type_get_underlying_type (field->type);
3672 ftype = mono_type_get_basic_type_from_generic (ftype);
3673 if (type_has_references (klass, ftype))
3674 has_references = TRUE;
3679 * Compute field layout and total size (not considering static fields)
3681 field_offsets = g_new0 (int, top);
3682 fields_has_references = g_new0 (gboolean, top);
3683 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
3684 switch (layout) {
3685 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
3686 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
3687 if (gc_aware_layout)
3688 passes = 2;
3689 else
3690 passes = 1;
3692 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
3693 passes = 1;
3695 if (klass->parent) {
3696 mono_class_setup_fields (klass->parent);
3697 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
3698 return;
3699 real_size = klass->parent->instance_size;
3700 } else {
3701 real_size = MONO_ABI_SIZEOF (MonoObject);
3704 for (pass = 0; pass < passes; ++pass) {
3705 for (i = 0; i < top; i++){
3706 gint32 align;
3707 guint32 size;
3708 MonoType *ftype;
3710 field = &klass->fields [i];
3712 if (mono_field_is_deleted (field))
3713 continue;
3714 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3715 continue;
3717 ftype = mono_type_get_underlying_type (field->type);
3718 ftype = mono_type_get_basic_type_from_generic (ftype);
3719 if (gc_aware_layout) {
3720 fields_has_references [i] = type_has_references (klass, ftype);
3721 if (fields_has_references [i]) {
3722 if (pass == 1)
3723 continue;
3724 } else {
3725 if (pass == 0)
3726 continue;
3730 if ((top == 1) && (instance_size == MONO_ABI_SIZEOF (MonoObject)) &&
3731 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
3732 /* This field is a hack inserted by MCS to empty structures */
3733 continue;
3736 size = mono_type_size (field->type, &align);
3738 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3739 align = packing_size ? MIN (packing_size, align): align;
3740 /* if the field has managed references, we need to force-align it
3741 * see bug #77788
3743 if (type_has_references (klass, ftype))
3744 align = MAX (align, TARGET_SIZEOF_VOID_P);
3746 min_align = MAX (align, min_align);
3747 field_offsets [i] = real_size;
3748 if (align) {
3749 field_offsets [i] += align - 1;
3750 field_offsets [i] &= ~(align - 1);
3752 /*TypeBuilders produce all sort of weird things*/
3753 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
3754 real_size = field_offsets [i] + size;
3757 instance_size = MAX (real_size, instance_size);
3759 if (instance_size & (min_align - 1)) {
3760 instance_size += min_align - 1;
3761 instance_size &= ~(min_align - 1);
3764 break;
3765 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
3766 guint8 *ref_bitmap;
3768 real_size = 0;
3769 for (i = 0; i < top; i++) {
3770 gint32 align;
3771 guint32 size;
3772 MonoType *ftype;
3774 field = &klass->fields [i];
3777 * There must be info about all the fields in a type if it
3778 * uses explicit layout.
3780 if (mono_field_is_deleted (field))
3781 continue;
3782 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3783 continue;
3785 size = mono_type_size (field->type, &align);
3786 align = packing_size ? MIN (packing_size, align): align;
3787 min_align = MAX (align, min_align);
3789 if (sre) {
3790 /* Already set by typebuilder_setup_fields () */
3791 field_offsets [i] = field->offset + MONO_ABI_SIZEOF (MonoObject);
3792 } else {
3793 int idx = first_field_idx + i;
3794 guint32 offset;
3795 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
3796 field_offsets [i] = offset + MONO_ABI_SIZEOF (MonoObject);
3798 ftype = mono_type_get_underlying_type (field->type);
3799 ftype = mono_type_get_basic_type_from_generic (ftype);
3800 if (type_has_references (klass, ftype)) {
3801 if (field_offsets [i] % TARGET_SIZEOF_VOID_P) {
3802 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
3807 * Calc max size.
3809 real_size = MAX (real_size, size + field_offsets [i]);
3812 if (klass->has_references) {
3813 ref_bitmap = g_new0 (guint8, real_size / TARGET_SIZEOF_VOID_P);
3815 /* Check for overlapping reference and non-reference fields */
3816 for (i = 0; i < top; i++) {
3817 MonoType *ftype;
3819 field = &klass->fields [i];
3821 if (mono_field_is_deleted (field))
3822 continue;
3823 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3824 continue;
3825 ftype = mono_type_get_underlying_type (field->type);
3826 if (MONO_TYPE_IS_REFERENCE (ftype))
3827 ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P] = 1;
3829 for (i = 0; i < top; i++) {
3830 field = &klass->fields [i];
3832 if (mono_field_is_deleted (field))
3833 continue;
3834 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3835 continue;
3837 // FIXME: Too much code does this
3838 #if 0
3839 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P]) {
3840 mono_class_set_type_load_failure (klass, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass->name, field_offsets [i]);
3842 #endif
3844 g_free (ref_bitmap);
3847 instance_size = MAX (real_size, instance_size);
3848 if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) {
3849 if (instance_size & (min_align - 1)) {
3850 instance_size += min_align - 1;
3851 instance_size &= ~(min_align - 1);
3854 break;
3858 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
3860 * This leads to all kinds of problems with nested structs, so only
3861 * enable it when a MONO_DEBUG property is set.
3863 * For small structs, set min_align to at least the struct size to improve
3864 * performance, and since the JIT memset/memcpy code assumes this and generates
3865 * unaligned accesses otherwise. See #78990 for a testcase.
3867 if (mono_align_small_structs && top) {
3868 if (instance_size <= MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer))
3869 min_align = MAX (min_align, instance_size - MONO_ABI_SIZEOF (MonoObject));
3873 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3874 if (klass_byval_arg->type == MONO_TYPE_VAR || klass_byval_arg->type == MONO_TYPE_MVAR)
3875 instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_stack_size_internal (klass_byval_arg, NULL, TRUE);
3876 else if (klass_byval_arg->type == MONO_TYPE_PTR)
3877 instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
3879 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3880 element_size = mono_class_array_element_size (klass->element_class);
3882 /* Publish the data */
3883 mono_loader_lock ();
3884 if (klass->instance_size && !klass->image->dynamic) {
3885 /* Might be already set using cached info */
3886 if (klass->instance_size != instance_size) {
3887 /* Emit info to help debugging */
3888 g_print ("%s\n", mono_class_full_name (klass));
3889 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
3890 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
3891 g_print ("%d %d\n", klass->min_align, min_align);
3892 for (i = 0; i < top; ++i) {
3893 field = &klass->fields [i];
3894 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3895 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
3898 g_assert (klass->instance_size == instance_size);
3899 } else {
3900 klass->instance_size = instance_size;
3902 klass->blittable = blittable;
3903 klass->has_references = has_references;
3904 klass->packing_size = packing_size;
3905 klass->min_align = min_align;
3906 for (i = 0; i < top; ++i) {
3907 field = &klass->fields [i];
3908 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3909 klass->fields [i].offset = field_offsets [i];
3912 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3913 klass->sizes.element_size = element_size;
3915 mono_memory_barrier ();
3916 klass->size_inited = 1;
3917 mono_loader_unlock ();
3920 * Compute static field layout and size
3921 * Static fields can reference the class itself, so this has to be
3922 * done after instance_size etc. are initialized.
3924 class_size = 0;
3925 for (i = 0; i < top; i++) {
3926 gint32 align;
3927 guint32 size;
3929 field = &klass->fields [i];
3931 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3932 continue;
3933 if (mono_field_is_deleted (field))
3934 continue;
3936 if (mono_type_has_exceptions (field->type)) {
3937 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
3938 break;
3941 has_static_fields = TRUE;
3943 size = mono_type_size (field->type, &align);
3944 field_offsets [i] = class_size;
3945 /*align is always non-zero here*/
3946 field_offsets [i] += align - 1;
3947 field_offsets [i] &= ~(align - 1);
3948 class_size = field_offsets [i] + size;
3951 if (has_static_fields && class_size == 0)
3952 /* Simplify code which depends on class_size != 0 if the class has static fields */
3953 class_size = 8;
3955 /* Compute klass->has_static_refs */
3956 has_static_refs = FALSE;
3957 for (i = 0; i < top; i++) {
3958 MonoType *ftype;
3960 field = &klass->fields [i];
3962 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3963 ftype = mono_type_get_underlying_type (field->type);
3964 ftype = mono_type_get_basic_type_from_generic (ftype);
3965 if (type_has_references (klass, ftype))
3966 has_static_refs = TRUE;
3970 /*valuetypes can't be neither bigger than 1Mb or empty. */
3971 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + MONO_ABI_SIZEOF (MonoObject)))) {
3972 /* Special case compiler generated types */
3973 /* Hard to check for [CompilerGenerated] here */
3974 if (!strstr (klass->name, "StaticArrayInitTypeSize") && !strstr (klass->name, "$ArrayType"))
3975 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
3978 // Weak field support
3980 // FIXME:
3981 // - generic instances
3982 // - Disallow on structs/static fields/nonref fields
3983 gboolean has_weak_fields = FALSE;
3985 if (mono_class_has_static_metadata (klass)) {
3986 for (MonoClass *p = klass; p != NULL; p = p->parent) {
3987 gpointer iter = NULL;
3988 guint32 first_field_idx = mono_class_get_first_field_idx (p);
3990 while ((field = mono_class_get_fields_internal (p, &iter))) {
3991 guint32 field_idx = first_field_idx + (field - p->fields);
3992 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
3993 has_weak_fields = TRUE;
3994 mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
4001 * Check that any fields of IsByRefLike type are instance
4002 * fields and only inside other IsByRefLike structs.
4004 * (Has to be done late because we call
4005 * mono_class_from_mono_type_internal which may recursively
4006 * refer to the current class)
4008 gboolean allow_isbyreflike_fields = m_class_is_byreflike (klass);
4009 for (i = 0; i < top; i++) {
4010 field = &klass->fields [i];
4012 if (mono_field_is_deleted (field))
4013 continue;
4014 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
4015 continue;
4016 MonoClass *field_class = NULL;
4017 /* have to be careful not to recursively invoke mono_class_init on a static field.
4018 * for example - if the field is an array of a subclass of klass, we can loop.
4020 switch (field->type->type) {
4021 case MONO_TYPE_TYPEDBYREF:
4022 case MONO_TYPE_VALUETYPE:
4023 case MONO_TYPE_GENERICINST:
4024 field_class = mono_class_from_mono_type_internal (field->type);
4025 break;
4026 default:
4027 break;
4029 if (!field_class || !m_class_is_byreflike (field_class))
4030 continue;
4031 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
4032 mono_class_set_type_load_failure (klass, "Static ByRefLike field '%s' is not allowed", field->name);
4033 return;
4034 } else {
4035 /* instance field */
4036 if (allow_isbyreflike_fields)
4037 continue;
4038 mono_class_set_type_load_failure (klass, "Instance ByRefLike field '%s' not in a ref struct", field->name);
4039 return;
4043 /* Publish the data */
4044 mono_loader_lock ();
4045 if (!klass->rank)
4046 klass->sizes.class_size = class_size;
4047 klass->has_static_refs = has_static_refs;
4048 klass->has_weak_fields = has_weak_fields;
4049 for (i = 0; i < top; ++i) {
4050 field = &klass->fields [i];
4052 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
4053 field->offset = field_offsets [i];
4055 mono_memory_barrier ();
4056 klass->fields_inited = 1;
4057 mono_loader_unlock ();
4059 g_free (field_offsets);
4060 g_free (fields_has_references);
4063 static MonoMethod *default_ghc = NULL;
4064 static MonoMethod *default_finalize = NULL;
4065 static int finalize_slot = -1;
4066 static int ghc_slot = -1;
4068 static void
4069 initialize_object_slots (MonoClass *klass)
4071 int i;
4072 if (default_ghc)
4073 return;
4074 if (klass == mono_defaults.object_class) {
4075 mono_class_setup_vtable (klass);
4076 for (i = 0; i < klass->vtable_size; ++i) {
4077 MonoMethod *cm = klass->vtable [i];
4079 if (!strcmp (cm->name, "GetHashCode"))
4080 ghc_slot = i;
4081 else if (!strcmp (cm->name, "Finalize"))
4082 finalize_slot = i;
4085 g_assert (ghc_slot > 0);
4086 default_ghc = klass->vtable [ghc_slot];
4088 g_assert (finalize_slot > 0);
4089 default_finalize = klass->vtable [finalize_slot];
4094 mono_class_get_object_finalize_slot ()
4096 return finalize_slot;
4099 MonoMethod *
4100 mono_class_get_default_finalize_method ()
4102 return default_finalize;
4105 typedef struct {
4106 MonoMethod *array_method;
4107 char *name;
4108 } GenericArrayMethodInfo;
4110 static int generic_array_method_num = 0;
4111 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4113 static void
4114 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
4116 MonoGenericContext tmp_context;
4117 int i;
4119 tmp_context.class_inst = NULL;
4120 tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
4121 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4123 for (i = 0; i < generic_array_method_num; i++) {
4124 ERROR_DECL (error);
4125 MonoMethod *m = generic_array_method_info [i].array_method;
4126 MonoMethod *inflated, *helper;
4128 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, error);
4129 mono_error_assert_ok (error);
4130 helper = (MonoMethod*)g_hash_table_lookup (cache, inflated);
4131 if (!helper) {
4132 helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
4133 g_hash_table_insert (cache, inflated, helper);
4135 methods [pos ++] = helper;
4139 static int
4140 generic_array_methods (MonoClass *klass)
4142 int i, count_generic = 0, mcount;
4143 GList *list = NULL, *tmp;
4144 if (generic_array_method_num)
4145 return generic_array_method_num;
4146 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4147 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4148 mcount = mono_class_get_method_count (klass->parent);
4149 for (i = 0; i < mcount; i++) {
4150 MonoMethod *m = klass->parent->methods [i];
4151 if (!strncmp (m->name, "InternalArray__", 15)) {
4152 count_generic++;
4153 list = g_list_prepend (list, m);
4156 list = g_list_reverse (list);
4157 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4158 i = 0;
4159 for (tmp = list; tmp; tmp = tmp->next) {
4160 const char *mname, *iname;
4161 gchar *name;
4162 MonoMethod *m = (MonoMethod *)tmp->data;
4163 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4164 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4166 generic_array_method_info [i].array_method = m;
4167 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4168 iname = "System.Collections.Generic.ICollection`1.";
4169 mname = m->name + 27;
4170 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4171 iname = "System.Collections.Generic.IEnumerable`1.";
4172 mname = m->name + 27;
4173 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4174 iname = "System.Collections.Generic.IReadOnlyList`1.";
4175 mname = m->name + strlen (ireadonlylist_prefix);
4176 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4177 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4178 mname = m->name + strlen (ireadonlycollection_prefix);
4179 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4180 iname = "System.Collections.Generic.IList`1.";
4181 mname = m->name + 15;
4182 } else {
4183 g_assert_not_reached ();
4186 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4187 strcpy (name, iname);
4188 strcpy (name + strlen (iname), mname);
4189 generic_array_method_info [i].name = name;
4190 i++;
4192 /*g_print ("array generic methods: %d\n", count_generic);*/
4194 generic_array_method_num = count_generic;
4195 g_list_free (list);
4196 return generic_array_method_num;
4200 * Global pool of interface IDs, represented as a bitset.
4201 * LOCKING: Protected by the classes lock.
4203 static MonoBitSet *global_interface_bitset = NULL;
4206 * mono_unload_interface_ids:
4207 * @bitset: bit set of interface IDs
4209 * When an image is unloaded, the interface IDs associated with
4210 * the image are put back in the global pool of IDs so the numbers
4211 * can be reused.
4213 void
4214 mono_unload_interface_ids (MonoBitSet *bitset)
4216 classes_lock ();
4217 mono_bitset_sub (global_interface_bitset, bitset);
4218 classes_unlock ();
4221 void
4222 mono_unload_interface_id (MonoClass *klass)
4224 if (global_interface_bitset && klass->interface_id) {
4225 classes_lock ();
4226 mono_bitset_clear (global_interface_bitset, klass->interface_id);
4227 classes_unlock ();
4232 * mono_get_unique_iid:
4233 * \param klass interface
4235 * Assign a unique integer ID to the interface represented by \p klass.
4236 * The ID will positive and as small as possible.
4237 * LOCKING: Acquires the classes lock.
4238 * \returns The new ID.
4240 static guint32
4241 mono_get_unique_iid (MonoClass *klass)
4243 int iid;
4245 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
4247 classes_lock ();
4249 if (!global_interface_bitset) {
4250 global_interface_bitset = mono_bitset_new (128, 0);
4251 mono_bitset_set (global_interface_bitset, 0); //don't let 0 be a valid iid
4254 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
4255 if (iid < 0) {
4256 int old_size = mono_bitset_size (global_interface_bitset);
4257 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
4258 mono_bitset_free (global_interface_bitset);
4259 global_interface_bitset = new_set;
4260 iid = old_size;
4262 mono_bitset_set (global_interface_bitset, iid);
4263 /* set the bit also in the per-image set */
4264 if (!mono_class_is_ginst (klass)) {
4265 if (klass->image->interface_bitset) {
4266 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
4267 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
4268 mono_bitset_free (klass->image->interface_bitset);
4269 klass->image->interface_bitset = new_set;
4271 } else {
4272 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
4274 mono_bitset_set (klass->image->interface_bitset, iid);
4277 classes_unlock ();
4279 #ifndef MONO_SMALL_CONFIG
4280 if (mono_print_vtable) {
4281 int generic_id;
4282 char *type_name = mono_type_full_name (m_class_get_byval_arg (klass));
4283 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
4284 if (gklass && !gklass->context.class_inst->is_open) {
4285 generic_id = gklass->context.class_inst->id;
4286 g_assert (generic_id != 0);
4287 } else {
4288 generic_id = 0;
4290 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->assembly_name, type_name, generic_id);
4291 g_free (type_name);
4293 #endif
4295 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4296 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4297 g_assert (iid < INT_MAX);
4298 return iid;
4302 * mono_class_init_internal:
4303 * \param klass the class to initialize
4305 * Compute the \c instance_size, \c class_size and other infos that cannot be
4306 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4307 * Initializes the following fields in \p klass:
4308 * - all the fields initialized by \c mono_class_init_sizes
4309 * - has_cctor
4310 * - ghcimpl
4311 * - inited
4313 * LOCKING: Acquires the loader lock.
4315 * \returns TRUE on success or FALSE if there was a problem in loading
4316 * the type (incorrect assemblies, missing assemblies, methods, etc).
4318 gboolean
4319 mono_class_init_internal (MonoClass *klass)
4321 int i, vtable_size = 0, array_method_count = 0;
4322 MonoCachedClassInfo cached_info;
4323 gboolean has_cached_info;
4324 gboolean locked = FALSE;
4325 gboolean ghcimpl = FALSE;
4326 gboolean has_cctor = FALSE;
4327 int first_iface_slot = 0;
4329 g_assert (klass);
4331 /* Double-checking locking pattern */
4332 if (klass->inited || mono_class_has_failure (klass))
4333 return !mono_class_has_failure (klass);
4335 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4338 * This function can recursively call itself.
4340 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
4341 if (g_slist_find (init_list, klass)) {
4342 mono_class_set_type_load_failure (klass, "Recursive type definition detected %s.%s", klass->name_space, klass->name);
4343 goto leave_no_init_pending;
4345 init_list = g_slist_prepend (init_list, klass);
4346 mono_native_tls_set_value (init_pending_tls_id, init_list);
4349 * We want to avoid doing complicated work inside locks, so we compute all the required
4350 * information and write it to @klass inside a lock.
4353 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
4354 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
4355 goto leave;
4358 MonoType *klass_byval_arg;
4359 klass_byval_arg = m_class_get_byval_arg (klass);
4360 if (klass_byval_arg->type == MONO_TYPE_ARRAY || klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4361 MonoClass *element_class = klass->element_class;
4362 MonoClass *cast_class = klass->cast_class;
4364 if (!element_class->inited)
4365 mono_class_init_internal (element_class);
4366 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
4367 goto leave;
4368 if (!cast_class->inited)
4369 mono_class_init_internal (cast_class);
4370 if (mono_class_set_type_load_failure_causedby_class (klass, cast_class, "Could not load array cast class"))
4371 goto leave;
4374 UnlockedIncrement (&mono_stats.initialized_class_count);
4376 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
4377 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4379 mono_class_init_internal (gklass);
4380 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
4381 goto leave;
4383 mono_class_setup_interface_id_internal (klass);
4386 if (klass->parent && !klass->parent->inited)
4387 mono_class_init_internal (klass->parent);
4389 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
4391 /* Compute instance size etc. */
4392 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
4393 if (mono_class_has_failure (klass))
4394 goto leave;
4396 mono_class_setup_supertypes (klass);
4398 if (!default_ghc)
4399 initialize_object_slots (klass);
4402 * Initialize the rest of the data without creating a generic vtable if possible.
4403 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4404 * also avoid computing a generic vtable.
4406 if (has_cached_info) {
4407 /* AOT case */
4408 vtable_size = cached_info.vtable_size;
4409 ghcimpl = cached_info.ghcimpl;
4410 has_cctor = cached_info.has_cctor;
4411 } else if (klass->rank == 1 && klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4412 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4413 * The first slot if for array with.
4415 static int szarray_vtable_size[3] = { 0 };
4417 int slot;
4419 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass))))
4420 slot = 0;
4421 else if (klass->element_class->enumtype)
4422 slot = 1;
4423 else
4424 slot = 2;
4426 /* SZARRAY case */
4427 if (!szarray_vtable_size [slot]) {
4428 mono_class_setup_vtable (klass);
4429 szarray_vtable_size [slot] = klass->vtable_size;
4430 vtable_size = klass->vtable_size;
4431 } else {
4432 vtable_size = szarray_vtable_size[slot];
4434 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4435 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4437 /* Generic instance case */
4438 ghcimpl = gklass->ghcimpl;
4439 has_cctor = gklass->has_cctor;
4441 mono_class_setup_vtable (gklass);
4442 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
4443 goto leave;
4445 vtable_size = gklass->vtable_size;
4446 } else {
4447 /* General case */
4449 /* ghcimpl is not currently used
4450 klass->ghcimpl = 1;
4451 if (klass->parent) {
4452 MonoMethod *cmethod = klass->vtable [ghc_slot];
4453 if (cmethod->is_inflated)
4454 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
4455 if (cmethod == default_ghc) {
4456 klass->ghcimpl = 0;
4461 /* C# doesn't allow interfaces to have cctors */
4462 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->image != mono_defaults.corlib) {
4463 MonoMethod *cmethod = NULL;
4465 if (mono_class_is_ginst (klass)) {
4466 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4468 /* Generic instance case */
4469 ghcimpl = gklass->ghcimpl;
4470 has_cctor = gklass->has_cctor;
4471 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
4472 cmethod = mono_find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
4473 /* The find_method function ignores the 'flags' argument */
4474 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
4475 has_cctor = 1;
4476 } else {
4477 mono_class_setup_methods (klass);
4478 if (mono_class_has_failure (klass))
4479 goto leave;
4481 int mcount = mono_class_get_method_count (klass);
4482 for (i = 0; i < mcount; ++i) {
4483 MonoMethod *method = klass->methods [i];
4484 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
4485 (strcmp (".cctor", method->name) == 0)) {
4486 has_cctor = 1;
4487 break;
4494 if (klass->rank) {
4495 array_method_count = 3 + (klass->rank > 1? 2: 1);
4497 if (klass->interface_count) {
4498 int count_generic = generic_array_methods (klass);
4499 array_method_count += klass->interface_count * count_generic;
4503 if (klass->parent) {
4504 if (!klass->parent->vtable_size)
4505 mono_class_setup_vtable (klass->parent);
4506 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
4507 goto leave;
4508 g_assert (klass->parent->vtable_size);
4509 first_iface_slot = klass->parent->vtable_size;
4510 if (mono_class_need_stelemref_method (klass))
4511 ++first_iface_slot;
4515 * Do the actual changes to @klass inside the loader lock
4517 mono_loader_lock ();
4518 locked = TRUE;
4520 if (klass->inited || mono_class_has_failure (klass)) {
4521 mono_loader_unlock ();
4522 /* Somebody might have gotten in before us */
4523 return !mono_class_has_failure (klass);
4526 UnlockedIncrement (&mono_stats.initialized_class_count);
4528 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
4529 UnlockedIncrement (&mono_stats.generic_class_count);
4531 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
4532 klass->nested_classes_inited = TRUE;
4533 klass->ghcimpl = ghcimpl;
4534 klass->has_cctor = has_cctor;
4535 if (vtable_size)
4536 klass->vtable_size = vtable_size;
4537 if (has_cached_info) {
4538 klass->has_finalize = cached_info.has_finalize;
4539 klass->has_finalize_inited = TRUE;
4541 if (klass->rank)
4542 mono_class_set_method_count (klass, array_method_count);
4544 mono_loader_unlock ();
4545 locked = FALSE;
4547 setup_interface_offsets (klass, first_iface_slot, TRUE);
4549 if (mono_security_core_clr_enabled ())
4550 mono_security_core_clr_check_inheritance (klass);
4552 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
4553 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
4555 goto leave;
4557 leave:
4558 init_list = (GSList*)mono_native_tls_get_value (init_pending_tls_id);
4559 init_list = g_slist_remove (init_list, klass);
4560 mono_native_tls_set_value (init_pending_tls_id, init_list);
4562 leave_no_init_pending:
4563 if (locked)
4564 mono_loader_unlock ();
4566 /* Leave this for last */
4567 mono_loader_lock ();
4568 klass->inited = 1;
4569 mono_loader_unlock ();
4571 return !mono_class_has_failure (klass);
4574 gboolean
4575 mono_class_init_checked (MonoClass *klass, MonoError *error)
4577 error_init (error);
4578 gboolean const success = mono_class_init_internal (klass);
4579 if (!success)
4580 mono_error_set_for_class_failure (error, klass);
4581 return success;
4584 #ifndef DISABLE_COM
4586 * COM initialization is delayed until needed.
4587 * However when a [ComImport] attribute is present on a type it will trigger
4588 * the initialization. This is not a problem unless the BCL being executed
4589 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4591 static void
4592 init_com_from_comimport (MonoClass *klass)
4594 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4595 if (mono_security_core_clr_enabled ()) {
4596 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4597 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
4598 /* but it can not be made available for application (i.e. user code) since all COM calls
4599 * are considered native calls. In this case we fail with a TypeLoadException (just like
4600 * Silverlight 2 does */
4601 mono_class_set_type_load_failure (klass, "");
4602 return;
4606 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4608 #endif /*DISABLE_COM*/
4611 * LOCKING: this assumes the loader lock is held
4613 void
4614 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
4616 gboolean system_namespace;
4617 gboolean is_corlib = mono_is_corlib_image (klass->image);
4619 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
4621 /* if root of the hierarchy */
4622 if (system_namespace && !strcmp (klass->name, "Object")) {
4623 klass->parent = NULL;
4624 klass->instance_size = MONO_ABI_SIZEOF (MonoObject);
4625 return;
4627 if (!strcmp (klass->name, "<Module>")) {
4628 klass->parent = NULL;
4629 klass->instance_size = 0;
4630 return;
4633 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4634 /* Imported COM Objects always derive from __ComObject. */
4635 #ifndef DISABLE_COM
4636 if (MONO_CLASS_IS_IMPORT (klass)) {
4637 init_com_from_comimport (klass);
4638 if (parent == mono_defaults.object_class)
4639 parent = mono_class_get_com_object_class ();
4641 #endif
4642 if (!parent) {
4643 /* set the parent to something useful and safe, but mark the type as broken */
4644 parent = mono_defaults.object_class;
4645 mono_class_set_type_load_failure (klass, "");
4646 g_assert (parent);
4649 klass->parent = parent;
4651 if (mono_class_is_ginst (parent) && !parent->name) {
4653 * If the parent is a generic instance, we may get
4654 * called before it is fully initialized, especially
4655 * before it has its name.
4657 return;
4660 #ifndef DISABLE_REMOTING
4661 klass->marshalbyref = parent->marshalbyref;
4662 klass->contextbound = parent->contextbound;
4663 #endif
4665 klass->delegate = parent->delegate;
4667 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
4668 mono_class_set_is_com_object (klass);
4670 if (system_namespace) {
4671 #ifndef DISABLE_REMOTING
4672 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
4673 klass->marshalbyref = 1;
4675 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
4676 klass->contextbound = 1;
4677 #endif
4678 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
4679 klass->delegate = 1;
4682 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
4683 (strcmp (klass->parent->name_space, "System") == 0)))
4684 klass->valuetype = 1;
4685 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
4686 klass->valuetype = klass->enumtype = 1;
4688 /*klass->enumtype = klass->parent->enumtype; */
4689 } else {
4690 /* initialize com types if COM interfaces are present */
4691 #ifndef DISABLE_COM
4692 if (MONO_CLASS_IS_IMPORT (klass))
4693 init_com_from_comimport (klass);
4694 #endif
4695 klass->parent = NULL;
4700 /* Locking: must be called with the loader lock held. */
4701 static void
4702 mono_class_setup_interface_id_internal (MonoClass *klass)
4704 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->interface_id)
4705 return;
4706 klass->interface_id = mono_get_unique_iid (klass);
4708 if (mono_is_corlib_image (klass->image) && !strcmp (m_class_get_name_space (klass), "System.Collections.Generic")) {
4709 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4710 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4711 * MS returns diferrent types based on which instance is called. For example:
4712 * object obj = new byte[10][];
4713 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4714 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4715 * a != b ==> true
4717 const char *name = m_class_get_name (klass);
4718 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
4719 klass->is_array_special_interface = 1;
4725 * LOCKING: this assumes the loader lock is held
4727 void
4728 mono_class_setup_mono_type (MonoClass *klass)
4730 const char *name = klass->name;
4731 const char *nspace = klass->name_space;
4732 gboolean is_corlib = mono_is_corlib_image (klass->image);
4734 klass->this_arg.byref = 1;
4735 klass->this_arg.data.klass = klass;
4736 klass->this_arg.type = MONO_TYPE_CLASS;
4737 klass->_byval_arg.data.klass = klass;
4738 klass->_byval_arg.type = MONO_TYPE_CLASS;
4740 if (is_corlib && !strcmp (nspace, "System")) {
4741 if (!strcmp (name, "ValueType")) {
4743 * do not set the valuetype bit for System.ValueType.
4744 * klass->valuetype = 1;
4746 klass->blittable = TRUE;
4747 } else if (!strcmp (name, "Enum")) {
4749 * do not set the valuetype bit for System.Enum.
4750 * klass->valuetype = 1;
4752 klass->valuetype = 0;
4753 klass->enumtype = 0;
4754 } else if (!strcmp (name, "Object")) {
4755 klass->_byval_arg.type = MONO_TYPE_OBJECT;
4756 klass->this_arg.type = MONO_TYPE_OBJECT;
4757 } else if (!strcmp (name, "String")) {
4758 klass->_byval_arg.type = MONO_TYPE_STRING;
4759 klass->this_arg.type = MONO_TYPE_STRING;
4760 } else if (!strcmp (name, "TypedReference")) {
4761 klass->_byval_arg.type = MONO_TYPE_TYPEDBYREF;
4762 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
4766 if (klass->valuetype) {
4767 int t = MONO_TYPE_VALUETYPE;
4769 if (is_corlib && !strcmp (nspace, "System")) {
4770 switch (*name) {
4771 case 'B':
4772 if (!strcmp (name, "Boolean")) {
4773 t = MONO_TYPE_BOOLEAN;
4774 } else if (!strcmp(name, "Byte")) {
4775 t = MONO_TYPE_U1;
4776 klass->blittable = TRUE;
4778 break;
4779 case 'C':
4780 if (!strcmp (name, "Char")) {
4781 t = MONO_TYPE_CHAR;
4783 break;
4784 case 'D':
4785 if (!strcmp (name, "Double")) {
4786 t = MONO_TYPE_R8;
4787 klass->blittable = TRUE;
4789 break;
4790 case 'I':
4791 if (!strcmp (name, "Int32")) {
4792 t = MONO_TYPE_I4;
4793 klass->blittable = TRUE;
4794 } else if (!strcmp(name, "Int16")) {
4795 t = MONO_TYPE_I2;
4796 klass->blittable = TRUE;
4797 } else if (!strcmp(name, "Int64")) {
4798 t = MONO_TYPE_I8;
4799 klass->blittable = TRUE;
4800 } else if (!strcmp(name, "IntPtr")) {
4801 t = MONO_TYPE_I;
4802 klass->blittable = TRUE;
4804 break;
4805 case 'S':
4806 if (!strcmp (name, "Single")) {
4807 t = MONO_TYPE_R4;
4808 klass->blittable = TRUE;
4809 } else if (!strcmp(name, "SByte")) {
4810 t = MONO_TYPE_I1;
4811 klass->blittable = TRUE;
4813 break;
4814 case 'U':
4815 if (!strcmp (name, "UInt32")) {
4816 t = MONO_TYPE_U4;
4817 klass->blittable = TRUE;
4818 } else if (!strcmp(name, "UInt16")) {
4819 t = MONO_TYPE_U2;
4820 klass->blittable = TRUE;
4821 } else if (!strcmp(name, "UInt64")) {
4822 t = MONO_TYPE_U8;
4823 klass->blittable = TRUE;
4824 } else if (!strcmp(name, "UIntPtr")) {
4825 t = MONO_TYPE_U;
4826 klass->blittable = TRUE;
4828 break;
4829 case 'T':
4830 if (!strcmp (name, "TypedReference")) {
4831 t = MONO_TYPE_TYPEDBYREF;
4832 klass->blittable = TRUE;
4834 break;
4835 case 'V':
4836 if (!strcmp (name, "Void")) {
4837 t = MONO_TYPE_VOID;
4839 break;
4840 default:
4841 break;
4844 klass->_byval_arg.type = (MonoTypeEnum)t;
4845 klass->this_arg.type = (MonoTypeEnum)t;
4848 mono_class_setup_interface_id_internal (klass);
4851 static MonoMethod*
4852 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
4854 MonoMethod *method;
4856 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
4857 method->klass = klass;
4858 method->flags = METHOD_ATTRIBUTE_PUBLIC;
4859 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
4860 method->signature = sig;
4861 method->name = name;
4862 method->slot = -1;
4863 /* .ctor */
4864 if (name [0] == '.') {
4865 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
4866 } else {
4867 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
4869 return method;
4873 * mono_class_setup_methods:
4874 * @class: a class
4876 * Initializes the 'methods' array in CLASS.
4877 * Calling this method should be avoided if possible since it allocates a lot
4878 * of long-living MonoMethod structures.
4879 * Methods belonging to an interface are assigned a sequential slot starting
4880 * from 0.
4882 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4884 void
4885 mono_class_setup_methods (MonoClass *klass)
4887 int i, count;
4888 MonoMethod **methods;
4890 if (klass->methods)
4891 return;
4893 if (mono_class_is_ginst (klass)) {
4894 ERROR_DECL (error);
4895 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4897 mono_class_init_internal (gklass);
4898 if (!mono_class_has_failure (gklass))
4899 mono_class_setup_methods (gklass);
4900 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
4901 return;
4903 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4904 count = mono_class_get_method_count (gklass);
4905 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
4907 for (i = 0; i < count; i++) {
4908 methods [i] = mono_class_inflate_generic_method_full_checked (
4909 gklass->methods [i], klass, mono_class_get_context (klass), error);
4910 if (!mono_error_ok (error)) {
4911 char *method = mono_method_full_name (gklass->methods [i], TRUE);
4912 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (error));
4914 g_free (method);
4915 mono_error_cleanup (error);
4916 return;
4919 } else if (klass->rank) {
4920 ERROR_DECL (error);
4921 MonoMethod *amethod;
4922 MonoMethodSignature *sig;
4923 int count_generic = 0, first_generic = 0;
4924 int method_num = 0;
4925 gboolean jagged_ctor = FALSE;
4927 count = 3 + (klass->rank > 1? 2: 1);
4929 mono_class_setup_interfaces (klass, error);
4930 g_assert (mono_error_ok (error)); /*FIXME can this fail for array types?*/
4932 if (klass->rank == 1 && klass->element_class->rank) {
4933 jagged_ctor = TRUE;
4934 count ++;
4937 if (klass->interface_count) {
4938 count_generic = generic_array_methods (klass);
4939 first_generic = count;
4940 count += klass->interface_count * count_generic;
4943 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
4945 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4946 sig->ret = mono_get_void_type ();
4947 sig->pinvoke = TRUE;
4948 sig->hasthis = TRUE;
4949 for (i = 0; i < klass->rank; ++i)
4950 sig->params [i] = mono_get_int32_type ();
4952 amethod = create_array_method (klass, ".ctor", sig);
4953 methods [method_num++] = amethod;
4954 if (klass->rank > 1) {
4955 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
4956 sig->ret = mono_get_void_type ();
4957 sig->pinvoke = TRUE;
4958 sig->hasthis = TRUE;
4959 for (i = 0; i < klass->rank * 2; ++i)
4960 sig->params [i] = mono_get_int32_type ();
4962 amethod = create_array_method (klass, ".ctor", sig);
4963 methods [method_num++] = amethod;
4966 if (jagged_ctor) {
4967 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4968 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4969 sig->ret = mono_get_void_type ();
4970 sig->pinvoke = TRUE;
4971 sig->hasthis = TRUE;
4972 for (i = 0; i < klass->rank + 1; ++i)
4973 sig->params [i] = mono_get_int32_type ();
4974 amethod = create_array_method (klass, ".ctor", sig);
4975 methods [method_num++] = amethod;
4978 /* element Get (idx11, [idx2, ...]) */
4979 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4980 sig->ret = m_class_get_byval_arg (m_class_get_element_class (klass));
4981 sig->pinvoke = TRUE;
4982 sig->hasthis = TRUE;
4983 for (i = 0; i < klass->rank; ++i)
4984 sig->params [i] = mono_get_int32_type ();
4985 amethod = create_array_method (klass, "Get", sig);
4986 methods [method_num++] = amethod;
4987 /* element& Address (idx11, [idx2, ...]) */
4988 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4989 sig->ret = &klass->element_class->this_arg;
4990 sig->pinvoke = TRUE;
4991 sig->hasthis = TRUE;
4992 for (i = 0; i < klass->rank; ++i)
4993 sig->params [i] = mono_get_int32_type ();
4994 amethod = create_array_method (klass, "Address", sig);
4995 methods [method_num++] = amethod;
4996 /* void Set (idx11, [idx2, ...], element) */
4997 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4998 sig->ret = mono_get_void_type ();
4999 sig->pinvoke = TRUE;
5000 sig->hasthis = TRUE;
5001 for (i = 0; i < klass->rank; ++i)
5002 sig->params [i] = mono_get_int32_type ();
5003 sig->params [i] = m_class_get_byval_arg (m_class_get_element_class (klass));
5004 amethod = create_array_method (klass, "Set", sig);
5005 methods [method_num++] = amethod;
5007 GHashTable *cache = g_hash_table_new (NULL, NULL);
5008 for (i = 0; i < klass->interface_count; i++)
5009 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
5010 g_hash_table_destroy (cache);
5011 } else if (mono_class_has_static_metadata (klass)) {
5012 ERROR_DECL (error);
5013 int first_idx = mono_class_get_first_method_idx (klass);
5015 count = mono_class_get_method_count (klass);
5016 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
5017 for (i = 0; i < count; ++i) {
5018 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
5019 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, error);
5020 if (!methods [i]) {
5021 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (error));
5022 mono_error_cleanup (error);
5025 } else {
5026 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
5027 count = 0;
5030 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
5031 int slot = 0;
5032 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
5033 for (i = 0; i < count; ++i) {
5034 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
5035 methods [i]->slot = slot++;
5039 mono_image_lock (klass->image);
5041 if (!klass->methods) {
5042 mono_class_set_method_count (klass, count);
5044 /* Needed because of the double-checking locking pattern */
5045 mono_memory_barrier ();
5047 klass->methods = methods;
5050 mono_image_unlock (klass->image);
5054 * mono_class_setup_properties:
5056 * Initialize klass->ext.property and klass->ext.properties.
5058 * This method can fail the class.
5060 void
5061 mono_class_setup_properties (MonoClass *klass)
5063 guint startm, endm, i, j;
5064 guint32 cols [MONO_PROPERTY_SIZE];
5065 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5066 MonoProperty *properties;
5067 guint32 last;
5068 int first, count;
5069 MonoClassPropertyInfo *info;
5071 info = mono_class_get_property_info (klass);
5072 if (info)
5073 return;
5075 if (mono_class_is_ginst (klass)) {
5076 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5078 mono_class_init_internal (gklass);
5079 mono_class_setup_properties (gklass);
5080 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5081 return;
5083 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
5084 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
5086 for (i = 0; i < ginfo->count; i++) {
5087 ERROR_DECL (error);
5088 MonoProperty *prop = &properties [i];
5090 *prop = ginfo->properties [i];
5092 if (prop->get)
5093 prop->get = mono_class_inflate_generic_method_full_checked (
5094 prop->get, klass, mono_class_get_context (klass), error);
5095 if (prop->set)
5096 prop->set = mono_class_inflate_generic_method_full_checked (
5097 prop->set, klass, mono_class_get_context (klass), error);
5099 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5100 prop->parent = klass;
5103 first = ginfo->first;
5104 count = ginfo->count;
5105 } else {
5106 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5107 count = last - first;
5109 if (count) {
5110 mono_class_setup_methods (klass);
5111 if (mono_class_has_failure (klass))
5112 return;
5115 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
5116 for (i = first; i < last; ++i) {
5117 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
5118 properties [i - first].parent = klass;
5119 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
5120 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
5122 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
5123 int first_idx = mono_class_get_first_method_idx (klass);
5124 for (j = startm; j < endm; ++j) {
5125 MonoMethod *method;
5127 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5129 if (klass->image->uncompressed_metadata) {
5130 ERROR_DECL (error);
5131 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5132 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5133 mono_error_cleanup (error); /* FIXME don't swallow this error */
5134 } else {
5135 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5138 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5139 case METHOD_SEMANTIC_SETTER:
5140 properties [i - first].set = method;
5141 break;
5142 case METHOD_SEMANTIC_GETTER:
5143 properties [i - first].get = method;
5144 break;
5145 default:
5146 break;
5152 info = (MonoClassPropertyInfo*)mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
5153 info->first = first;
5154 info->count = count;
5155 info->properties = properties;
5156 mono_memory_barrier ();
5158 /* This might leak 'info' which was allocated from the image mempool */
5159 mono_class_set_property_info (klass, info);
5162 static MonoMethod**
5163 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
5165 MonoMethod **om, **retval;
5166 int count;
5168 for (om = methods, count = 0; *om; ++om, ++count)
5171 retval = g_new0 (MonoMethod*, count + 1);
5172 count = 0;
5173 for (om = methods, count = 0; *om; ++om, ++count) {
5174 ERROR_DECL (error);
5175 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, error);
5176 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5179 return retval;
5182 /*This method can fail the class.*/
5183 void
5184 mono_class_setup_events (MonoClass *klass)
5186 int first, count;
5187 guint startm, endm, i, j;
5188 guint32 cols [MONO_EVENT_SIZE];
5189 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5190 guint32 last;
5191 MonoEvent *events;
5193 MonoClassEventInfo *info = mono_class_get_event_info (klass);
5194 if (info)
5195 return;
5197 if (mono_class_is_ginst (klass)) {
5198 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5199 MonoGenericContext *context = NULL;
5201 mono_class_setup_events (gklass);
5202 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5203 return;
5205 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
5206 first = ginfo->first;
5207 count = ginfo->count;
5209 events = mono_class_new0 (klass, MonoEvent, count);
5211 if (count)
5212 context = mono_class_get_context (klass);
5214 for (i = 0; i < count; i++) {
5215 ERROR_DECL (error);
5216 MonoEvent *event = &events [i];
5217 MonoEvent *gevent = &ginfo->events [i];
5219 error_init (error); //since we do conditional calls, we must ensure the default value is ok
5221 event->parent = klass;
5222 event->name = gevent->name;
5223 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, error) : NULL;
5224 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5225 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, error) : NULL;
5226 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5227 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, error) : NULL;
5228 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5230 #ifndef MONO_SMALL_CONFIG
5231 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
5232 #endif
5233 event->attrs = gevent->attrs;
5235 } else {
5236 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5237 count = last - first;
5239 if (count) {
5240 mono_class_setup_methods (klass);
5241 if (mono_class_has_failure (klass)) {
5242 return;
5246 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
5247 for (i = first; i < last; ++i) {
5248 MonoEvent *event = &events [i - first];
5250 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
5251 event->parent = klass;
5252 event->attrs = cols [MONO_EVENT_FLAGS];
5253 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
5255 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
5256 int first_idx = mono_class_get_first_method_idx (klass);
5257 for (j = startm; j < endm; ++j) {
5258 MonoMethod *method;
5260 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5262 if (klass->image->uncompressed_metadata) {
5263 ERROR_DECL (error);
5264 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5265 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5266 mono_error_cleanup (error); /* FIXME don't swallow this error */
5267 } else {
5268 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5271 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5272 case METHOD_SEMANTIC_ADD_ON:
5273 event->add = method;
5274 break;
5275 case METHOD_SEMANTIC_REMOVE_ON:
5276 event->remove = method;
5277 break;
5278 case METHOD_SEMANTIC_FIRE:
5279 event->raise = method;
5280 break;
5281 case METHOD_SEMANTIC_OTHER: {
5282 #ifndef MONO_SMALL_CONFIG
5283 int n = 0;
5285 if (event->other == NULL) {
5286 event->other = g_new0 (MonoMethod*, 2);
5287 } else {
5288 while (event->other [n])
5289 n++;
5290 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
5292 event->other [n] = method;
5293 /* NULL terminated */
5294 event->other [n + 1] = NULL;
5295 #endif
5296 break;
5298 default:
5299 break;
5305 info = (MonoClassEventInfo*)mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
5306 info->events = events;
5307 info->first = first;
5308 info->count = count;
5310 mono_memory_barrier ();
5312 mono_class_set_event_info (klass, info);
5317 * mono_class_setup_interface_id:
5319 * Initializes MonoClass::interface_id if required.
5321 * LOCKING: Acquires the loader lock.
5323 void
5324 mono_class_setup_interface_id (MonoClass *klass)
5326 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
5327 mono_loader_lock ();
5328 mono_class_setup_interface_id_internal (klass);
5329 mono_loader_unlock ();
5333 * mono_class_setup_interfaces:
5335 * Initialize klass->interfaces/interfaces_count.
5336 * LOCKING: Acquires the loader lock.
5337 * This function can fail the type.
5339 void
5340 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
5342 int i, interface_count;
5343 MonoClass **interfaces;
5345 error_init (error);
5347 if (klass->interfaces_inited)
5348 return;
5350 if (klass->rank == 1 && m_class_get_byval_arg (klass)->type != MONO_TYPE_ARRAY) {
5351 MonoType *args [1];
5353 /* IList and IReadOnlyList -> 2x if enum*/
5354 interface_count = klass->element_class->enumtype ? 4 : 2;
5355 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
5357 args [0] = m_class_get_byval_arg (m_class_get_element_class (klass));
5358 interfaces [0] = mono_class_bind_generic_parameters (
5359 mono_defaults.generic_ilist_class, 1, args, FALSE);
5360 interfaces [1] = mono_class_bind_generic_parameters (
5361 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5362 if (klass->element_class->enumtype) {
5363 args [0] = mono_class_enum_basetype_internal (klass->element_class);
5364 interfaces [2] = mono_class_bind_generic_parameters (
5365 mono_defaults.generic_ilist_class, 1, args, FALSE);
5366 interfaces [3] = mono_class_bind_generic_parameters (
5367 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5369 } else if (mono_class_is_ginst (klass)) {
5370 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5372 mono_class_setup_interfaces (gklass, error);
5373 if (!mono_error_ok (error)) {
5374 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5375 return;
5378 interface_count = gklass->interface_count;
5379 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
5380 for (i = 0; i < interface_count; i++) {
5381 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
5382 if (!mono_error_ok (error)) {
5383 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5384 return;
5387 } else {
5388 interface_count = 0;
5389 interfaces = NULL;
5392 mono_loader_lock ();
5393 if (!klass->interfaces_inited) {
5394 klass->interface_count = interface_count;
5395 klass->interfaces = interfaces;
5397 mono_memory_barrier ();
5399 klass->interfaces_inited = TRUE;
5401 mono_loader_unlock ();
5406 * mono_class_setup_has_finalizer:
5408 * Initialize klass->has_finalizer if it isn't already initialized.
5410 * LOCKING: Acquires the loader lock.
5412 void
5413 mono_class_setup_has_finalizer (MonoClass *klass)
5415 gboolean has_finalize = FALSE;
5417 if (m_class_is_has_finalize_inited (klass))
5418 return;
5420 /* Interfaces and valuetypes are not supposed to have finalizers */
5421 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_is_valuetype (klass))) {
5422 MonoMethod *cmethod = NULL;
5424 if (m_class_get_rank (klass) == 1 && m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
5425 } else if (mono_class_is_ginst (klass)) {
5426 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5428 has_finalize = mono_class_has_finalizer (gklass);
5429 } else if (m_class_get_parent (klass) && m_class_has_finalize (m_class_get_parent (klass))) {
5430 has_finalize = TRUE;
5431 } else {
5432 if (m_class_get_parent (klass)) {
5434 * Can't search in metadata for a method named Finalize, because that
5435 * ignores overrides.
5437 mono_class_setup_vtable (klass);
5438 if (mono_class_has_failure (klass))
5439 cmethod = NULL;
5440 else
5441 cmethod = m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
5444 if (cmethod) {
5445 g_assert (m_class_get_vtable_size (klass) > mono_class_get_object_finalize_slot ());
5447 if (m_class_get_parent (klass)) {
5448 if (cmethod->is_inflated)
5449 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5450 if (cmethod != mono_class_get_default_finalize_method ())
5451 has_finalize = TRUE;
5457 mono_loader_lock ();
5458 if (!m_class_is_has_finalize_inited (klass)) {
5459 klass->has_finalize = has_finalize ? 1 : 0;
5461 mono_memory_barrier ();
5462 klass->has_finalize_inited = TRUE;
5464 mono_loader_unlock ();
5468 * mono_class_setup_supertypes:
5469 * @class: a class
5471 * Build the data structure needed to make fast type checks work.
5472 * This currently sets two fields in @class:
5473 * - idepth: distance between @class and System.Object in the type
5474 * hierarchy + 1
5475 * - supertypes: array of classes: each element has a class in the hierarchy
5476 * starting from @class up to System.Object
5478 * LOCKING: Acquires the loader lock.
5480 void
5481 mono_class_setup_supertypes (MonoClass *klass)
5483 int ms, idepth;
5484 MonoClass **supertypes;
5486 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5487 if (supertypes)
5488 return;
5490 if (klass->parent && !klass->parent->supertypes)
5491 mono_class_setup_supertypes (klass->parent);
5492 if (klass->parent)
5493 idepth = klass->parent->idepth + 1;
5494 else
5495 idepth = 1;
5497 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5498 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5500 if (klass->parent) {
5501 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5503 int supertype_idx;
5504 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5505 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5506 } else {
5507 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5510 mono_memory_barrier ();
5512 mono_loader_lock ();
5513 klass->idepth = idepth;
5514 /* Needed so idepth is visible before supertypes is set */
5515 mono_memory_barrier ();
5516 klass->supertypes = supertypes;
5517 mono_loader_unlock ();
5520 /* mono_class_setup_nested_types:
5522 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5524 * LOCKING: Acquires the loader lock.
5526 void
5527 mono_class_setup_nested_types (MonoClass *klass)
5529 ERROR_DECL (error);
5530 GList *classes, *nested_classes, *l;
5531 int i;
5533 if (klass->nested_classes_inited)
5534 return;
5536 if (!klass->type_token) {
5537 mono_loader_lock ();
5538 klass->nested_classes_inited = TRUE;
5539 mono_loader_unlock ();
5540 return;
5543 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
5544 classes = NULL;
5545 while (i) {
5546 MonoClass* nclass;
5547 guint32 cols [MONO_NESTED_CLASS_SIZE];
5548 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
5549 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], error);
5550 if (!mono_error_ok (error)) {
5551 /*FIXME don't swallow the error message*/
5552 mono_error_cleanup (error);
5554 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5555 continue;
5558 classes = g_list_prepend (classes, nclass);
5560 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5563 nested_classes = NULL;
5564 for (l = classes; l; l = l->next)
5565 nested_classes = mono_g_list_prepend_image (klass->image, nested_classes, l->data);
5566 g_list_free (classes);
5568 mono_loader_lock ();
5569 if (!klass->nested_classes_inited) {
5570 mono_class_set_nested_classes_property (klass, nested_classes);
5571 mono_memory_barrier ();
5572 klass->nested_classes_inited = TRUE;
5574 mono_loader_unlock ();
5578 * mono_class_setup_runtime_info:
5579 * \param klass the class to setup
5580 * \param domain the domain of the \p vtable
5581 * \param vtable
5583 * Store \p vtable in \c klass->runtime_info.
5585 * Sets the following field in MonoClass:
5586 * - runtime_info
5588 * LOCKING: domain lock and loaderlock must be held.
5590 void
5591 mono_class_setup_runtime_info (MonoClass *klass, MonoDomain *domain, MonoVTable *vtable)
5593 MonoClassRuntimeInfo *old_info = m_class_get_runtime_info (klass);
5594 if (old_info && old_info->max_domain >= domain->domain_id) {
5595 /* someone already created a large enough runtime info */
5596 old_info->domain_vtables [domain->domain_id] = vtable;
5597 } else {
5598 int new_size = domain->domain_id;
5599 if (old_info)
5600 new_size = MAX (new_size, old_info->max_domain);
5601 new_size++;
5602 /* make the new size a power of two */
5603 int i = 2;
5604 while (new_size > i)
5605 i <<= 1;
5606 new_size = i;
5607 /* this is a bounded memory retention issue: may want to
5608 * handle it differently when we'll have a rcu-like system.
5610 MonoClassRuntimeInfo *runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
5611 runtime_info->max_domain = new_size - 1;
5612 /* copy the stuff from the older info */
5613 if (old_info) {
5614 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
5616 runtime_info->domain_vtables [domain->domain_id] = vtable;
5617 /* keep this last*/
5618 mono_memory_barrier ();
5619 klass->runtime_info = runtime_info;
5624 * mono_class_create_array_fill_type:
5626 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5628 MonoClass *
5629 mono_class_create_array_fill_type (void)
5631 static MonoClass klass;
5632 static gboolean inited = FALSE;
5634 if (!inited) {
5635 klass.element_class = mono_defaults.int64_class;
5636 klass.rank = 1;
5637 klass.instance_size = MONO_SIZEOF_MONO_ARRAY;
5638 klass.sizes.element_size = 8;
5639 klass.size_inited = 1;
5640 klass.name = "array_filler_type";
5642 inited = TRUE;
5644 return &klass;
5648 * mono_classes_init:
5650 * Initialize the resources used by this module.
5651 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5653 MONO_NO_SANITIZE_THREAD
5654 void
5655 mono_classes_init (void)
5657 mono_os_mutex_init (&classes_mutex);
5659 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
5660 mono_native_tls_alloc (&init_pending_tls_id, NULL);
5662 mono_counters_register ("MonoClassDef count",
5663 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
5664 mono_counters_register ("MonoClassGtd count",
5665 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
5666 mono_counters_register ("MonoClassGenericInst count",
5667 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
5668 mono_counters_register ("MonoClassGenericParam count",
5669 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
5670 mono_counters_register ("MonoClassArray count",
5671 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
5672 mono_counters_register ("MonoClassPointer count",
5673 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
5674 mono_counters_register ("Inflated methods size",
5675 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mono_inflated_methods_size);
5676 mono_counters_register ("Inflated classes size",
5677 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
5678 mono_counters_register ("MonoClass size",
5679 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
5683 * mono_classes_cleanup:
5685 * Free the resources used by this module.
5687 void
5688 mono_classes_cleanup (void)
5690 mono_native_tls_free (setup_fields_tls_id);
5691 mono_native_tls_free (init_pending_tls_id);
5693 if (global_interface_bitset)
5694 mono_bitset_free (global_interface_bitset);
5695 global_interface_bitset = NULL;
5696 mono_os_mutex_destroy (&classes_mutex);