Reduce TLS accesses. (#11487)
[mono-project.git] / mono / metadata / class-init.c
blob8db36860e413871226e0933078cd0cac3d6272c3
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);
57 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
58 static MonoNativeTlsKey setup_fields_tls_id;
60 static MonoNativeTlsKey init_pending_tls_id;
62 static inline void
63 classes_lock (void)
65 mono_locks_os_acquire (&classes_mutex, ClassesLock);
68 static inline void
69 classes_unlock (void)
71 mono_locks_os_release (&classes_mutex, ClassesLock);
75 We use gclass recording to allow recursive system f types to be referenced by a parent.
77 Given the following type hierarchy:
79 class TextBox : TextBoxBase<TextBox> {}
80 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
81 class TextInput<T> : Input<T> where T: TextInput<T> {}
82 class Input<T> {}
84 The runtime tries to load TextBoxBase<>.
85 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
86 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
87 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
89 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
90 at this point, iow, both are registered in the type map and both and a NULL parent. This means
91 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
93 To fix that what we do is to record all generic instantes created while resolving the parent of
94 any generic type definition and, after resolved, correct the parent field if needed.
97 static int record_gclass_instantiation;
98 static GSList *gclass_recorded_list;
99 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
102 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
104 static void
105 enable_gclass_recording (void)
107 ++record_gclass_instantiation;
111 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
113 static void
114 disable_gclass_recording (gclass_record_func func, void *user_data)
116 GSList **head = &gclass_recorded_list;
118 g_assert (record_gclass_instantiation > 0);
119 --record_gclass_instantiation;
121 while (*head) {
122 GSList *node = *head;
123 if (func ((MonoClass*)node->data, user_data)) {
124 *head = node->next;
125 g_slist_free_1 (node);
126 } else {
127 head = &node->next;
131 /* We automatically discard all recorded gclasses when disabled. */
132 if (!record_gclass_instantiation && gclass_recorded_list) {
133 g_slist_free (gclass_recorded_list);
134 gclass_recorded_list = NULL;
138 #define mono_class_new0(klass,struct_type, n_structs) \
139 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
142 * mono_class_setup_basic_field_info:
143 * \param class The class to initialize
145 * Initializes the following fields in MonoClass:
146 * * klass->fields (only field->parent and field->name)
147 * * klass->field.count
148 * * klass->first_field_idx
149 * LOCKING: Acquires the loader lock
151 void
152 mono_class_setup_basic_field_info (MonoClass *klass)
154 MonoGenericClass *gklass;
155 MonoClassField *field;
156 MonoClassField *fields;
157 MonoClass *gtd;
158 MonoImage *image;
159 int i, top;
161 if (klass->fields)
162 return;
164 gklass = mono_class_try_get_generic_class (klass);
165 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
166 image = klass->image;
169 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
171 * This happens when a generic instance of an unfinished generic typebuilder
172 * is used as an element type for creating an array type. We can't initialize
173 * the fields of this class using the fields of gklass, since gklass is not
174 * finished yet, fields could be added to it later.
176 return;
179 if (gtd) {
180 mono_class_setup_basic_field_info (gtd);
182 mono_loader_lock ();
183 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
184 mono_loader_unlock ();
187 top = mono_class_get_field_count (klass);
189 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
192 * Fetch all the field information.
194 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
195 for (i = 0; i < top; i++) {
196 field = &fields [i];
197 field->parent = klass;
199 if (gtd) {
200 field->name = mono_field_get_name (&gtd->fields [i]);
201 } else {
202 int idx = first_field_idx + i;
203 /* first_field_idx and idx points into the fieldptr table */
204 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
205 /* The name is needed for fieldrefs */
206 field->name = mono_metadata_string_heap (image, name_idx);
210 mono_memory_barrier ();
212 mono_loader_lock ();
213 if (!klass->fields)
214 klass->fields = fields;
215 mono_loader_unlock ();
219 * mono_class_setup_fields:
220 * \p klass The class to initialize
222 * Initializes klass->fields, computes class layout and sizes.
223 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
224 * Sets the following fields in \p klass:
225 * - all the fields initialized by mono_class_init_sizes ()
226 * - element_class/cast_class (for enums)
227 * - sizes:element_size (for arrays)
228 * - field->type/offset for all fields
229 * - fields_inited
231 * LOCKING: Acquires the loader lock.
233 void
234 mono_class_setup_fields (MonoClass *klass)
236 ERROR_DECL (error);
237 MonoImage *m = klass->image;
238 int top;
239 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
240 int i;
241 guint32 real_size = 0;
242 guint32 packing_size = 0;
243 int instance_size;
244 gboolean explicit_size;
245 MonoClassField *field;
246 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
247 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
249 if (klass->fields_inited)
250 return;
252 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
254 * This happens when a generic instance of an unfinished generic typebuilder
255 * is used as an element type for creating an array type. We can't initialize
256 * the fields of this class using the fields of gklass, since gklass is not
257 * finished yet, fields could be added to it later.
259 return;
262 mono_class_setup_basic_field_info (klass);
263 top = mono_class_get_field_count (klass);
265 if (gtd) {
266 mono_class_setup_fields (gtd);
267 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
268 return;
271 instance_size = 0;
272 if (klass->parent) {
273 /* For generic instances, klass->parent might not have been initialized */
274 mono_class_init (klass->parent);
275 mono_class_setup_fields (klass->parent);
276 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
277 return;
278 instance_size = klass->parent->instance_size;
279 } else {
280 instance_size = MONO_ABI_SIZEOF (MonoObject);
283 /* Get the real size */
284 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
285 if (explicit_size)
286 instance_size += real_size;
289 * This function can recursively call itself.
290 * Prevent infinite recursion by using a list in TLS.
292 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
293 if (g_slist_find (init_list, klass))
294 return;
295 init_list = g_slist_prepend (init_list, klass);
296 mono_native_tls_set_value (setup_fields_tls_id, init_list);
299 * Fetch all the field information.
301 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
302 for (i = 0; i < top; i++) {
303 int idx = first_field_idx + i;
304 field = &klass->fields [i];
306 if (!field->type) {
307 mono_field_resolve_type (field, error);
308 if (!mono_error_ok (error)) {
309 /*mono_field_resolve_type already failed class*/
310 mono_error_cleanup (error);
311 break;
313 if (!field->type)
314 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
315 g_assert (field->type);
318 if (!mono_type_get_underlying_type (field->type)) {
319 mono_class_set_type_load_failure (klass, "Field '%s' is an enum type with a bad underlying type", field->name);
320 break;
323 if (mono_field_is_deleted (field))
324 continue;
325 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
326 guint32 uoffset;
327 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
328 int offset = uoffset;
330 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
331 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
332 break;
334 if (offset < -1) { /*-1 is used to encode special static fields */
335 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
336 break;
338 if (mono_class_is_gtd (klass)) {
339 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
340 break;
343 if (mono_type_has_exceptions (field->type)) {
344 char *class_name = mono_type_get_full_name (klass);
345 char *type_name = mono_type_full_name (field->type);
347 mono_class_set_type_load_failure (klass, "Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
348 g_free (class_name);
349 g_free (type_name);
350 break;
352 /* The def_value of fields is compute lazily during vtable creation */
355 if (!mono_class_has_failure (klass)) {
356 mono_loader_lock ();
357 mono_class_layout_fields (klass, instance_size, packing_size, real_size, FALSE);
358 mono_loader_unlock ();
361 init_list = g_slist_remove (init_list, klass);
362 mono_native_tls_set_value (setup_fields_tls_id, init_list);
365 static gboolean
366 discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
368 return mono_class_get_generic_class (gclass)->container_class == user_data;
371 static gboolean
372 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
374 MonoClass *gtd = (MonoClass*)user_data;
375 /* Only try to fix generic instances of @gtd */
376 if (mono_class_get_generic_class (gclass)->container_class != gtd)
377 return FALSE;
379 /* Check if the generic instance has no parent. */
380 if (gtd->parent && !gclass->parent)
381 mono_generic_class_setup_parent (gclass, gtd);
383 return TRUE;
386 static void
387 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
389 mono_class_set_type_load_failure (klass, "%s", msg);
390 mono_error_set_type_load_class (error, klass, "%s", msg);
394 * mono_class_create_from_typedef:
395 * \param image: image where the token is valid
396 * \param type_token: typedef token
397 * \param error: used to return any error found while creating the type
399 * Create the MonoClass* representing the specified type token.
400 * \p type_token must be a TypeDef token.
402 * FIXME: don't return NULL on failure, just let the caller figure it out.
404 MonoClass *
405 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
407 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
408 MonoClass *klass, *parent = NULL;
409 guint32 cols [MONO_TYPEDEF_SIZE];
410 guint32 cols_next [MONO_TYPEDEF_SIZE];
411 guint tidx = mono_metadata_token_index (type_token);
412 MonoGenericContext *context = NULL;
413 const char *name, *nspace;
414 guint icount = 0;
415 MonoClass **interfaces;
416 guint32 field_last, method_last;
417 guint32 nesting_tokeen;
419 error_init (error);
421 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
422 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
423 return NULL;
426 mono_loader_lock ();
428 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
429 mono_loader_unlock ();
430 return klass;
433 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
435 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
436 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
438 if (mono_metadata_has_generic_params (image, type_token)) {
439 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassGtd));
440 klass->class_kind = MONO_CLASS_GTD;
441 UnlockedAdd (&classes_size, sizeof (MonoClassGtd));
442 ++class_gtd_count;
443 } else {
444 klass = (MonoClass*)mono_image_alloc0 (image, sizeof (MonoClassDef));
445 klass->class_kind = MONO_CLASS_DEF;
446 UnlockedAdd (&classes_size, sizeof (MonoClassDef));
447 ++class_def_count;
450 klass->name = name;
451 klass->name_space = nspace;
453 MONO_PROFILER_RAISE (class_loading, (klass));
455 klass->image = image;
456 klass->type_token = type_token;
457 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
459 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
462 * Check whether we're a generic type definition.
464 if (mono_class_is_gtd (klass)) {
465 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL, klass);
466 context = &generic_container->context;
467 mono_class_set_generic_container (klass, generic_container);
468 MonoType *canonical_inst = &((MonoClassGtd*)klass)->canonical_inst;
469 canonical_inst->type = MONO_TYPE_GENERICINST;
470 canonical_inst->data.generic_class = mono_metadata_lookup_generic_class (klass, context->class_inst, FALSE);
471 enable_gclass_recording ();
474 if (cols [MONO_TYPEDEF_EXTENDS]) {
475 MonoClass *tmp;
476 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
478 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
479 /*WARNING: this must satisfy mono_metadata_type_hash*/
480 klass->this_arg.byref = 1;
481 klass->this_arg.data.klass = klass;
482 klass->this_arg.type = MONO_TYPE_CLASS;
483 klass->_byval_arg.data.klass = klass;
484 klass->_byval_arg.type = MONO_TYPE_CLASS;
486 parent = mono_class_get_checked (image, parent_token, error);
487 if (parent && context) /* Always inflate */
488 parent = mono_class_inflate_generic_class_checked (parent, context, error);
490 if (parent == NULL) {
491 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
492 goto parent_failure;
495 for (tmp = parent; tmp; tmp = tmp->parent) {
496 if (tmp == klass) {
497 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
498 goto parent_failure;
500 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
501 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
502 goto parent_failure;
507 mono_class_setup_parent (klass, parent);
509 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
510 mono_class_setup_mono_type (klass);
512 if (mono_class_is_gtd (klass))
513 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
516 * This might access klass->_byval_arg for recursion generated by generic constraints,
517 * so it has to come after setup_mono_type ().
519 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
520 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
521 if (!mono_error_ok (error)) {
522 /*FIXME implement a mono_class_set_failure_from_mono_error */
523 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
524 mono_loader_unlock ();
525 MONO_PROFILER_RAISE (class_failed, (klass));
526 return NULL;
530 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
531 klass->unicode = 1;
533 #ifdef HOST_WIN32
534 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
535 klass->unicode = 1;
536 #endif
538 klass->cast_class = klass->element_class = klass;
539 if (mono_is_corlib_image (klass->image)) {
540 switch (m_class_get_byval_arg (klass)->type) {
541 case MONO_TYPE_I1:
542 if (mono_defaults.byte_class)
543 klass->cast_class = mono_defaults.byte_class;
544 break;
545 case MONO_TYPE_U1:
546 if (mono_defaults.sbyte_class)
547 mono_defaults.sbyte_class = klass;
548 break;
549 case MONO_TYPE_I2:
550 if (mono_defaults.uint16_class)
551 mono_defaults.uint16_class = klass;
552 break;
553 case MONO_TYPE_U2:
554 if (mono_defaults.int16_class)
555 klass->cast_class = mono_defaults.int16_class;
556 break;
557 case MONO_TYPE_I4:
558 if (mono_defaults.uint32_class)
559 mono_defaults.uint32_class = klass;
560 break;
561 case MONO_TYPE_U4:
562 if (mono_defaults.int32_class)
563 klass->cast_class = mono_defaults.int32_class;
564 break;
565 case MONO_TYPE_I8:
566 if (mono_defaults.uint64_class)
567 mono_defaults.uint64_class = klass;
568 break;
569 case MONO_TYPE_U8:
570 if (mono_defaults.int64_class)
571 klass->cast_class = mono_defaults.int64_class;
572 break;
576 if (!klass->enumtype) {
577 if (!mono_metadata_interfaces_from_typedef_full (
578 image, type_token, &interfaces, &icount, FALSE, context, error)){
580 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
581 mono_loader_unlock ();
582 MONO_PROFILER_RAISE (class_failed, (klass));
583 return NULL;
586 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
587 g_assert(icount <= 65535);
589 klass->interfaces = interfaces;
590 klass->interface_count = icount;
591 klass->interfaces_inited = 1;
594 /*g_print ("Load class %s\n", name);*/
597 * Compute the field and method lists
599 int first_field_idx;
600 first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
601 mono_class_set_first_field_idx (klass, first_field_idx);
602 int first_method_idx;
603 first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
604 mono_class_set_first_method_idx (klass, first_method_idx);
606 if (tt->rows > tidx){
607 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
608 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
609 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
610 } else {
611 field_last = image->tables [MONO_TABLE_FIELD].rows;
612 method_last = image->tables [MONO_TABLE_METHOD].rows;
615 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
616 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
617 mono_class_set_field_count (klass, field_last - first_field_idx);
618 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
619 mono_class_set_method_count (klass, method_last - first_method_idx);
621 /* reserve space to store vector pointer in arrays */
622 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
623 klass->instance_size += 2 * TARGET_SIZEOF_VOID_P;
624 g_assert (mono_class_get_field_count (klass) == 0);
627 if (klass->enumtype) {
628 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
629 if (!enum_basetype) {
630 /*set it to a default value as the whole runtime can't handle this to be null*/
631 klass->cast_class = klass->element_class = mono_defaults.int32_class;
632 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
633 mono_loader_unlock ();
634 MONO_PROFILER_RAISE (class_failed, (klass));
635 return NULL;
637 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (enum_basetype);
641 * If we're a generic type definition, load the constraints.
642 * We must do this after the class has been constructed to make certain recursive scenarios
643 * work.
645 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
646 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
647 mono_loader_unlock ();
648 MONO_PROFILER_RAISE (class_failed, (klass));
649 return NULL;
652 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
653 if (!strncmp (name, "Vector", 6))
654 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");
655 } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
656 /* The JIT can't handle SIMD types with != 16 size yet */
657 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
658 if (!strcmp (name, "Vector4"))
659 klass->simd_type = 1;
662 // compute is_byreflike
663 if (m_class_is_valuetype (klass)) {
664 /* TypedReference and RuntimeArgumentHandle are byreflike by
665 * definition. Otherwise, look for IsByRefLikeAttribute.
667 if (mono_is_corlib_image (image) &&
668 ((m_class_get_byval_arg (klass)->type == MONO_TYPE_TYPEDBYREF) ||
669 (!strcmp (m_class_get_name_space (klass), "System") &&
670 !strcmp (m_class_get_name (klass), "RuntimeArgumentHandle"))))
671 klass->is_byreflike = 1;
672 else if (class_has_isbyreflike_attribute (klass))
673 klass->is_byreflike = 1;
676 mono_loader_unlock ();
678 MONO_PROFILER_RAISE (class_loaded, (klass));
680 return klass;
682 parent_failure:
683 if (mono_class_is_gtd (klass))
684 disable_gclass_recording (discard_gclass_due_to_failure, klass);
686 mono_class_setup_mono_type (klass);
687 mono_loader_unlock ();
688 MONO_PROFILER_RAISE (class_failed, (klass));
689 return NULL;
693 static void
694 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
696 if (gtd->parent) {
697 ERROR_DECL (error);
698 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
700 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), error);
701 if (!mono_error_ok (error)) {
702 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
703 klass->parent = mono_defaults.object_class;
704 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error));
705 mono_error_cleanup (error);
708 mono_loader_lock ();
709 if (klass->parent)
710 mono_class_setup_parent (klass, klass->parent);
712 if (klass->enumtype) {
713 klass->cast_class = gtd->cast_class;
714 klass->element_class = gtd->element_class;
716 mono_loader_unlock ();
719 struct HasIsByrefLikeUD {
720 gboolean has_isbyreflike;
723 static gboolean
724 has_isbyreflike_attribute_func (MonoImage *image, guint32 typeref_scope_token, const char *nspace, const char *name, guint32 method_token, gpointer user_data)
726 struct HasIsByrefLikeUD *has_isbyreflike = (struct HasIsByrefLikeUD *)user_data;
727 if (!strcmp (name, "IsByRefLikeAttribute") && !strcmp (nspace, "System.Runtime.CompilerServices")) {
728 has_isbyreflike->has_isbyreflike = TRUE;
729 return TRUE;
731 return FALSE;
734 static gboolean
735 class_has_isbyreflike_attribute (MonoClass *klass)
737 struct HasIsByrefLikeUD has_isbyreflike;
738 has_isbyreflike.has_isbyreflike = FALSE;
739 mono_class_metadata_foreach_custom_attr (klass, has_isbyreflike_attribute_func, &has_isbyreflike);
740 return has_isbyreflike.has_isbyreflike;
744 static gboolean
745 check_valid_generic_inst_arguments (MonoGenericInst *inst, MonoError *error)
747 for (int i = 0; i < inst->type_argc; i++) {
748 if (!mono_type_is_valid_generic_argument (inst->type_argv [i])) {
749 char *type_name = mono_type_full_name (inst->type_argv [i]);
750 mono_error_set_invalid_program (error, "generic type cannot be instantiated with type '%s'", type_name);
751 g_free (type_name);
752 return FALSE;
755 return TRUE;
759 * Create the `MonoClass' for an instantiation of a generic type.
760 * We only do this if we actually need it.
762 MonoClass*
763 mono_class_create_generic_inst (MonoGenericClass *gclass)
765 MonoClass *klass, *gklass;
767 if (gclass->cached_class)
768 return gclass->cached_class;
770 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
772 gklass = gclass->container_class;
774 if (gklass->nested_in) {
775 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
776 klass->nested_in = gklass->nested_in;
779 klass->name = gklass->name;
780 klass->name_space = gklass->name_space;
782 klass->image = gklass->image;
783 klass->type_token = gklass->type_token;
785 klass->class_kind = MONO_CLASS_GINST;
786 //FIXME add setter
787 ((MonoClassGenericInst*)klass)->generic_class = gclass;
789 klass->_byval_arg.type = MONO_TYPE_GENERICINST;
790 klass->this_arg.type = m_class_get_byval_arg (klass)->type;
791 klass->this_arg.data.generic_class = klass->_byval_arg.data.generic_class = gclass;
792 klass->this_arg.byref = TRUE;
793 klass->enumtype = gklass->enumtype;
794 klass->valuetype = gklass->valuetype;
797 if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
798 g_assert (gclass->context.class_inst);
799 g_assert (gclass->context.class_inst->type_argc > 0);
800 if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
801 klass->simd_type = 1;
803 klass->is_array_special_interface = gklass->is_array_special_interface;
805 klass->cast_class = klass->element_class = klass;
807 if (m_class_is_valuetype (klass)) {
808 klass->is_byreflike = gklass->is_byreflike;
811 if (gclass->is_dynamic) {
813 * 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.
814 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
815 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
817 if (!gklass->wastypebuilder)
818 klass->inited = 1;
820 if (klass->enumtype) {
822 * For enums, gklass->fields might not been set, but instance_size etc. is
823 * already set in mono_reflection_create_internal_class (). For non-enums,
824 * these will be computed normally in mono_class_layout_fields ().
826 klass->instance_size = gklass->instance_size;
827 klass->sizes.class_size = gklass->sizes.class_size;
828 klass->size_inited = 1;
833 ERROR_DECL (error_inst);
834 if (!check_valid_generic_inst_arguments (gclass->context.class_inst, error_inst)) {
835 char *gklass_name = mono_type_get_full_name (gklass);
836 mono_class_set_type_load_failure (klass, "Could not instantiate %s due to %s", gklass_name, mono_error_get_message (error_inst));
837 g_free (gklass_name);
838 mono_error_cleanup (error_inst);
842 mono_loader_lock ();
844 if (gclass->cached_class) {
845 mono_loader_unlock ();
846 return gclass->cached_class;
849 if (record_gclass_instantiation > 0)
850 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
852 if (mono_class_is_nullable (klass))
853 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
855 MONO_PROFILER_RAISE (class_loading, (klass));
857 mono_generic_class_setup_parent (klass, gklass);
859 if (gclass->is_dynamic)
860 mono_class_setup_supertypes (klass);
862 mono_memory_barrier ();
863 gclass->cached_class = klass;
865 MONO_PROFILER_RAISE (class_loaded, (klass));
867 ++class_ginst_count;
868 inflated_classes_size += sizeof (MonoClassGenericInst);
870 mono_loader_unlock ();
872 return klass;
875 static gboolean
876 class_kind_may_contain_generic_instances (MonoTypeKind kind)
878 /* classes of type generic inst may contain generic arguments from other images,
879 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
880 return (kind == MONO_CLASS_GINST || kind == MONO_CLASS_ARRAY || kind == MONO_CLASS_POINTER);
884 * mono_class_create_bounded_array:
885 * \param element_class element class
886 * \param rank the dimension of the array class
887 * \param bounded whenever the array has non-zero bounds
888 * \returns A class object describing the array with element type \p element_type and
889 * dimension \p rank.
891 MonoClass *
892 mono_class_create_bounded_array (MonoClass *eclass, guint32 rank, gboolean bounded)
894 MonoImage *image;
895 MonoClass *klass, *cached, *k;
896 MonoClass *parent = NULL;
897 GSList *list, *rootlist = NULL;
898 int nsize;
899 char *name;
900 MonoImageSet* image_set;
902 g_assert (rank <= 255);
904 if (rank > 1)
905 /* bounded only matters for one-dimensional arrays */
906 bounded = FALSE;
908 image = eclass->image;
909 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)eclass->class_kind) ? mono_metadata_get_image_set_for_class (eclass) : NULL;
911 /* Check cache */
912 cached = NULL;
913 if (rank == 1 && !bounded) {
914 if (image_set) {
915 mono_image_set_lock (image_set);
916 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
917 mono_image_set_unlock (image_set);
918 } else {
920 * This case is very frequent not just during compilation because of calls
921 * from mono_class_from_mono_type_internal (), mono_array_new (),
922 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
924 mono_os_mutex_lock (&image->szarray_cache_lock);
925 if (!image->szarray_cache)
926 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
927 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
928 mono_os_mutex_unlock (&image->szarray_cache_lock);
930 } else {
931 if (image_set) {
932 mono_image_set_lock (image_set);
933 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
934 for (list = rootlist; list; list = list->next) {
935 k = (MonoClass *)list->data;
936 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
937 cached = k;
938 break;
941 mono_image_set_unlock (image_set);
942 } else {
943 mono_loader_lock ();
944 if (!image->array_cache)
945 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
946 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
947 for (list = rootlist; list; list = list->next) {
948 k = (MonoClass *)list->data;
949 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
950 cached = k;
951 break;
954 mono_loader_unlock ();
957 if (cached)
958 return cached;
960 parent = mono_defaults.array_class;
961 if (!parent->inited)
962 mono_class_init (parent);
964 klass = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassArray)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
966 klass->image = image;
967 klass->name_space = eclass->name_space;
968 klass->class_kind = MONO_CLASS_ARRAY;
970 nsize = strlen (eclass->name);
971 name = (char *)g_malloc (nsize + 2 + rank + 1);
972 memcpy (name, eclass->name, nsize);
973 name [nsize] = '[';
974 if (rank > 1)
975 memset (name + nsize + 1, ',', rank - 1);
976 if (bounded)
977 name [nsize + rank] = '*';
978 name [nsize + rank + bounded] = ']';
979 name [nsize + rank + bounded + 1] = 0;
980 klass->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
981 g_free (name);
983 klass->type_token = 0;
984 klass->parent = parent;
985 klass->instance_size = mono_class_instance_size (klass->parent);
987 if (m_class_get_byval_arg (eclass)->type == MONO_TYPE_TYPEDBYREF) {
988 /*Arrays of those two types are invalid.*/
989 ERROR_DECL_VALUE (prepared_error);
990 error_init (&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 (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 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 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_VALUE (prepared_error);
1071 error_init (&prepared_error);
1072 name = mono_type_get_full_name (klass);
1073 mono_error_set_type_load_class (&prepared_error, klass, "%s has too many dimensions.", name);
1074 mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
1075 mono_error_cleanup (&prepared_error);
1076 g_free (name);
1079 mono_loader_lock ();
1081 /* Check cache again */
1082 cached = NULL;
1083 if (rank == 1 && !bounded) {
1084 if (image_set) {
1085 mono_image_set_lock (image_set);
1086 cached = (MonoClass *)g_hash_table_lookup (image_set->szarray_cache, eclass);
1087 mono_image_set_unlock (image_set);
1088 } else {
1089 mono_os_mutex_lock (&image->szarray_cache_lock);
1090 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
1091 mono_os_mutex_unlock (&image->szarray_cache_lock);
1093 } else {
1094 if (image_set) {
1095 mono_image_set_lock (image_set);
1096 rootlist = (GSList *)g_hash_table_lookup (image_set->array_cache, eclass);
1097 for (list = rootlist; list; list = list->next) {
1098 k = (MonoClass *)list->data;
1099 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1100 cached = k;
1101 break;
1104 mono_image_set_unlock (image_set);
1105 } else {
1106 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
1107 for (list = rootlist; list; list = list->next) {
1108 k = (MonoClass *)list->data;
1109 if ((m_class_get_rank (k) == rank) && (m_class_get_byval_arg (k)->type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
1110 cached = k;
1111 break;
1116 if (cached) {
1117 mono_loader_unlock ();
1118 return cached;
1121 MONO_PROFILER_RAISE (class_loading, (klass));
1123 UnlockedAdd (&classes_size, sizeof (MonoClassArray));
1124 ++class_array_count;
1126 if (rank == 1 && !bounded) {
1127 if (image_set) {
1128 mono_image_set_lock (image_set);
1129 g_hash_table_insert (image_set->szarray_cache, eclass, klass);
1130 mono_image_set_unlock (image_set);
1131 } else {
1132 mono_os_mutex_lock (&image->szarray_cache_lock);
1133 g_hash_table_insert (image->szarray_cache, eclass, klass);
1134 mono_os_mutex_unlock (&image->szarray_cache_lock);
1136 } else {
1137 if (image_set) {
1138 mono_image_set_lock (image_set);
1139 list = g_slist_append (rootlist, klass);
1140 g_hash_table_insert (image_set->array_cache, eclass, list);
1141 mono_image_set_unlock (image_set);
1142 } else {
1143 list = g_slist_append (rootlist, klass);
1144 g_hash_table_insert (image->array_cache, eclass, list);
1148 mono_loader_unlock ();
1150 MONO_PROFILER_RAISE (class_loaded, (klass));
1152 return klass;
1156 * mono_class_create_array:
1157 * \param element_class element class
1158 * \param rank the dimension of the array class
1159 * \returns A class object describing the array with element type \p element_type and
1160 * dimension \p rank.
1162 MonoClass *
1163 mono_class_create_array (MonoClass *eclass, guint32 rank)
1165 return mono_class_create_bounded_array (eclass, rank, FALSE);
1168 // This is called by mono_class_create_generic_parameter when a new class must be created.
1169 static MonoClass*
1170 make_generic_param_class (MonoGenericParam *param)
1172 MonoClass *klass, **ptr;
1173 int count, pos, i;
1174 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1175 MonoGenericContainer *container = mono_generic_param_owner (param);
1176 g_assert_checked (container);
1178 MonoImage *image = mono_get_image_for_generic_param (param);
1179 gboolean is_mvar = container->is_method;
1180 gboolean is_anonymous = container->is_anonymous;
1182 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
1183 klass->class_kind = MONO_CLASS_GPARAM;
1184 UnlockedAdd (&classes_size, sizeof (MonoClassGenericParam));
1185 UnlockedIncrement (&class_gparam_count);
1187 if (!is_anonymous) {
1188 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
1189 } else {
1190 int n = mono_generic_param_num (param);
1191 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , mono_make_generic_name_string (image, n) );
1194 if (is_anonymous) {
1195 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
1196 } else if (is_mvar) {
1197 MonoMethod *omethod = container->owner.method;
1198 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
1199 } else {
1200 MonoClass *oklass = container->owner.klass;
1201 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
1204 MONO_PROFILER_RAISE (class_loading, (klass));
1206 // Count non-NULL items in pinfo->constraints
1207 count = 0;
1208 if (!is_anonymous)
1209 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
1212 pos = 0;
1213 if ((count > 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo->constraints [0])) {
1214 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
1215 pos++;
1216 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
1217 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
1218 } else {
1219 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
1222 if (count - pos > 0) {
1223 klass->interface_count = count - pos;
1224 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
1225 klass->interfaces_inited = TRUE;
1226 for (i = pos; i < count; i++)
1227 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
1230 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
1232 klass->inited = TRUE;
1233 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
1234 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
1236 MonoTypeEnum t = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
1237 klass->_byval_arg.type = t;
1238 klass->this_arg.type = t;
1239 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
1240 CHECKED_METADATA_WRITE_PTR ( klass->_byval_arg.data.generic_param , param );
1241 klass->this_arg.byref = TRUE;
1243 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1244 klass->sizes.generic_param_token = !is_anonymous ? pinfo->token : 0;
1246 /*Init these fields to sane values*/
1247 klass->min_align = 1;
1249 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1250 * constrained to, the JIT depends on this.
1252 klass->instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_stack_size_internal (m_class_get_byval_arg (klass), NULL, TRUE);
1253 mono_memory_barrier ();
1254 klass->size_inited = 1;
1256 mono_class_setup_supertypes (klass);
1258 if (count - pos > 0) {
1259 mono_class_setup_vtable (klass->parent);
1260 if (mono_class_has_failure (klass->parent))
1261 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
1262 else
1263 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
1266 return klass;
1270 * LOCKING: Acquires the image lock (@image).
1272 MonoClass *
1273 mono_class_create_generic_parameter (MonoGenericParam *param)
1275 MonoImage *image = mono_get_image_for_generic_param (param);
1276 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
1277 MonoClass *klass, *klass2;
1279 // If a klass already exists for this object and is cached, return it.
1280 klass = pinfo->pklass;
1282 if (klass)
1283 return klass;
1285 // Create a new klass
1286 klass = make_generic_param_class (param);
1288 // Now we need to cache the klass we created.
1289 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1290 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1291 // and allow our newly-created klass object to just leak.
1292 mono_memory_barrier ();
1294 mono_image_lock (image);
1296 // Here "klass2" refers to the klass potentially created by the other thread.
1297 klass2 = pinfo->pklass;
1299 if (klass2) {
1300 klass = klass2;
1301 } else {
1302 pinfo->pklass = klass;
1304 mono_image_unlock (image);
1306 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1307 if (klass2)
1308 MONO_PROFILER_RAISE (class_failed, (klass2));
1309 else
1310 MONO_PROFILER_RAISE (class_loaded, (klass));
1312 return klass;
1316 * mono_class_create_ptr:
1318 MonoClass *
1319 mono_class_create_ptr (MonoType *type)
1321 MonoClass *result;
1322 MonoClass *el_class;
1323 MonoImage *image;
1324 char *name;
1325 MonoImageSet* image_set;
1327 el_class = mono_class_from_mono_type_internal (type);
1328 image = el_class->image;
1329 image_set = class_kind_may_contain_generic_instances ((MonoTypeKind)el_class->class_kind) ? mono_metadata_get_image_set_for_class (el_class) : NULL;
1331 if (image_set) {
1332 mono_image_set_lock (image_set);
1333 if (image_set->ptr_cache) {
1334 if ((result = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1335 mono_image_set_unlock (image_set);
1336 return result;
1339 mono_image_set_unlock (image_set);
1340 } else {
1341 mono_image_lock (image);
1342 if (image->ptr_cache) {
1343 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1344 mono_image_unlock (image);
1345 return result;
1348 mono_image_unlock (image);
1351 result = image_set ? (MonoClass *)mono_image_set_alloc0 (image_set, sizeof (MonoClassPointer)) : (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
1353 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1354 ++class_pointer_count;
1356 result->parent = NULL; /* no parent for PTR types */
1357 result->name_space = el_class->name_space;
1358 name = g_strdup_printf ("%s*", el_class->name);
1359 result->name = image_set ? mono_image_set_strdup (image_set, name) : mono_image_strdup (image, name);
1360 result->class_kind = MONO_CLASS_POINTER;
1361 g_free (name);
1363 MONO_PROFILER_RAISE (class_loading, (result));
1365 result->image = el_class->image;
1366 result->inited = TRUE;
1367 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1368 result->min_align = sizeof (gpointer);
1369 result->cast_class = result->element_class = el_class;
1370 result->blittable = TRUE;
1372 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_PTR;
1373 result->this_arg.data.type = result->_byval_arg.data.type = m_class_get_byval_arg (el_class);
1374 result->this_arg.byref = TRUE;
1376 mono_class_setup_supertypes (result);
1378 if (image_set) {
1379 mono_image_set_lock (image_set);
1380 if (image_set->ptr_cache) {
1381 MonoClass *result2;
1382 if ((result2 = (MonoClass *)g_hash_table_lookup (image_set->ptr_cache, el_class))) {
1383 mono_image_set_unlock (image_set);
1384 MONO_PROFILER_RAISE (class_failed, (result));
1385 return result2;
1388 else {
1389 image_set->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1391 g_hash_table_insert (image_set->ptr_cache, el_class, result);
1392 mono_image_set_unlock (image_set);
1393 } else {
1394 mono_image_lock (image);
1395 if (image->ptr_cache) {
1396 MonoClass *result2;
1397 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
1398 mono_image_unlock (image);
1399 MONO_PROFILER_RAISE (class_failed, (result));
1400 return result2;
1402 } else {
1403 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
1405 g_hash_table_insert (image->ptr_cache, el_class, result);
1406 mono_image_unlock (image);
1409 MONO_PROFILER_RAISE (class_loaded, (result));
1411 return result;
1414 MonoClass *
1415 mono_class_create_fnptr (MonoMethodSignature *sig)
1417 MonoClass *result, *cached;
1418 static GHashTable *ptr_hash = NULL;
1420 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1422 mono_loader_lock ();
1423 if (!ptr_hash)
1424 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
1425 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1426 mono_loader_unlock ();
1427 if (cached)
1428 return cached;
1430 result = g_new0 (MonoClass, 1);
1432 result->parent = NULL; /* no parent for PTR types */
1433 result->name_space = "System";
1434 result->name = "MonoFNPtrFakeClass";
1435 result->class_kind = MONO_CLASS_POINTER;
1437 result->image = mono_defaults.corlib; /* need to fix... */
1438 result->instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
1439 result->min_align = sizeof (gpointer);
1440 result->cast_class = result->element_class = result;
1441 result->this_arg.type = result->_byval_arg.type = MONO_TYPE_FNPTR;
1442 result->this_arg.data.method = result->_byval_arg.data.method = sig;
1443 result->this_arg.byref = TRUE;
1444 result->blittable = TRUE;
1445 result->inited = TRUE;
1447 mono_class_setup_supertypes (result);
1449 mono_loader_lock ();
1451 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
1452 if (cached) {
1453 g_free (result);
1454 mono_loader_unlock ();
1455 return cached;
1458 MONO_PROFILER_RAISE (class_loading, (result));
1460 UnlockedAdd (&classes_size, sizeof (MonoClassPointer));
1461 ++class_pointer_count;
1463 g_hash_table_insert (ptr_hash, sig, result);
1465 mono_loader_unlock ();
1467 MONO_PROFILER_RAISE (class_loaded, (result));
1469 return result;
1473 static void
1474 print_implemented_interfaces (MonoClass *klass)
1476 char *name;
1477 ERROR_DECL (error);
1478 GPtrArray *ifaces = NULL;
1479 int i;
1480 int ancestor_level = 0;
1482 name = mono_type_get_full_name (klass);
1483 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
1484 g_free (name);
1486 for (i = 0; i < klass->interface_offsets_count; i++) {
1487 char *ic_name = mono_type_get_full_name (klass->interfaces_packed [i]);
1488 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i,
1489 klass->interfaces_packed [i]->interface_id,
1490 klass->interface_offsets_packed [i],
1491 mono_class_get_method_count (klass->interfaces_packed [i]),
1492 ic_name);
1493 g_free (ic_name);
1495 printf ("Interface flags: ");
1496 for (i = 0; i <= klass->max_interface_id; i++)
1497 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
1498 printf ("(%d,T)", i);
1499 else
1500 printf ("(%d,F)", i);
1501 printf ("\n");
1502 printf ("Dump interface flags:");
1503 #ifdef COMPRESSED_INTERFACE_BITMAP
1505 const uint8_t* p = klass->interface_bitmap;
1506 i = klass->max_interface_id;
1507 while (i > 0) {
1508 printf (" %d x 00 %02X", p [0], p [1]);
1509 i -= p [0] * 8;
1510 i -= 8;
1513 #else
1514 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
1515 printf (" %02X", klass->interface_bitmap [i]);
1516 #endif
1517 printf ("\n");
1518 while (klass != NULL) {
1519 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
1520 ifaces = mono_class_get_implemented_interfaces (klass, error);
1521 if (!mono_error_ok (error)) {
1522 printf (" Type failed due to %s\n", mono_error_get_message (error));
1523 mono_error_cleanup (error);
1524 } else if (ifaces) {
1525 for (i = 0; i < ifaces->len; i++) {
1526 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1527 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
1528 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
1529 ic->interface_id,
1530 mono_class_interface_offset (klass, ic),
1531 mono_class_get_method_count (ic),
1532 ic->name_space,
1533 ic->name );
1535 g_ptr_array_free (ifaces, TRUE);
1537 ancestor_level ++;
1538 klass = klass->parent;
1543 * Return the number of virtual methods.
1544 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1545 * Return -1 on failure.
1546 * FIXME It would be nice if this information could be cached somewhere.
1548 static int
1549 count_virtual_methods (MonoClass *klass)
1551 int i, mcount, vcount = 0;
1552 guint32 flags;
1553 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
1555 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
1556 mono_class_setup_methods (klass);
1557 if (mono_class_has_failure (klass))
1558 return -1;
1560 mcount = mono_class_get_method_count (klass);
1561 for (i = 0; i < mcount; ++i) {
1562 flags = klass->methods [i]->flags;
1563 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
1564 ++vcount;
1566 } else {
1567 int first_idx = mono_class_get_first_method_idx (klass);
1568 mcount = mono_class_get_method_count (klass);
1569 for (i = 0; i < mcount; ++i) {
1570 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
1572 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
1573 ++vcount;
1576 return vcount;
1579 static int
1580 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
1582 int m, l = 0;
1583 if (!num_ifaces)
1584 return -1;
1585 while (1) {
1586 if (l > num_ifaces)
1587 return -1;
1588 m = (l + num_ifaces) / 2;
1589 if (interfaces_full [m] == ic)
1590 return m;
1591 if (l == num_ifaces)
1592 return -1;
1593 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
1594 num_ifaces = m - 1;
1595 } else {
1596 l = m + 1;
1601 static mono_bool
1602 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
1604 int i = find_interface (num_ifaces, interfaces_full, ic);
1605 if (i >= 0) {
1606 if (!force_set)
1607 return TRUE;
1608 interface_offsets_full [i] = offset;
1609 return FALSE;
1611 for (i = 0; i < num_ifaces; ++i) {
1612 if (interfaces_full [i]) {
1613 int end;
1614 if (interfaces_full [i]->interface_id < ic->interface_id)
1615 continue;
1616 end = i + 1;
1617 while (end < num_ifaces && interfaces_full [end]) end++;
1618 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
1619 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
1621 interfaces_full [i] = ic;
1622 interface_offsets_full [i] = offset;
1623 break;
1625 return FALSE;
1628 #ifdef COMPRESSED_INTERFACE_BITMAP
1631 * Compressed interface bitmap design.
1633 * Interface bitmaps take a large amount of memory, because their size is
1634 * linear with the maximum interface id assigned in the process (each interface
1635 * is assigned a unique id as it is loaded). The number of interface classes
1636 * is high because of the many implicit interfaces implemented by arrays (we'll
1637 * need to lazy-load them in the future).
1638 * Most classes implement a very small number of interfaces, so the bitmap is
1639 * sparse. This bitmap needs to be checked by interface casts, so access to the
1640 * needed bit must be fast and doable with few jit instructions.
1642 * The current compression format is as follows:
1643 * *) it is a sequence of one or more two-byte elements
1644 * *) the first byte in the element is the count of empty bitmap bytes
1645 * at the current bitmap position
1646 * *) the second byte in the element is an actual bitmap byte at the current
1647 * bitmap position
1649 * As an example, the following compressed bitmap bytes:
1650 * 0x07 0x01 0x00 0x7
1651 * correspond to the following bitmap:
1652 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1654 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1655 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1656 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1660 * mono_compress_bitmap:
1661 * \param dest destination buffer
1662 * \param bitmap bitmap buffer
1663 * \param size size of \p bitmap in bytes
1665 * This is a mono internal function.
1666 * The \p bitmap data is compressed into a format that is small but
1667 * still searchable in few instructions by the JIT and runtime.
1668 * The compressed data is stored in the buffer pointed to by the
1669 * \p dest array. Passing a NULL value for \p dest allows to just compute
1670 * the size of the buffer.
1671 * This compression algorithm assumes the bits set in the bitmap are
1672 * few and far between, like in interface bitmaps.
1673 * \returns The size of the compressed bitmap in bytes.
1676 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
1678 int numz = 0;
1679 int res = 0;
1680 const uint8_t *end = bitmap + size;
1681 while (bitmap < end) {
1682 if (*bitmap || numz == 255) {
1683 if (dest) {
1684 *dest++ = numz;
1685 *dest++ = *bitmap;
1687 res += 2;
1688 numz = 0;
1689 bitmap++;
1690 continue;
1692 bitmap++;
1693 numz++;
1695 if (numz) {
1696 res += 2;
1697 if (dest) {
1698 *dest++ = numz;
1699 *dest++ = 0;
1702 return res;
1706 * mono_class_interface_match:
1707 * \param bitmap a compressed bitmap buffer
1708 * \param id the index to check in the bitmap
1710 * This is a mono internal function.
1711 * Checks if a bit is set in a compressed interface bitmap. \p id must
1712 * be already checked for being smaller than the maximum id encoded in the
1713 * bitmap.
1715 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1716 * FALSE otherwise.
1719 mono_class_interface_match (const uint8_t *bitmap, int id)
1721 while (TRUE) {
1722 id -= bitmap [0] * 8;
1723 if (id < 8) {
1724 if (id < 0)
1725 return 0;
1726 return bitmap [1] & (1 << id);
1728 bitmap += 2;
1729 id -= 8;
1732 #endif
1735 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1736 * LOCKING: Acquires the loader lock.
1738 static int
1739 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
1741 ERROR_DECL (error);
1742 MonoClass *k, *ic;
1743 int i, j, num_ifaces;
1744 guint32 max_iid;
1745 MonoClass **interfaces_full = NULL;
1746 int *interface_offsets_full = NULL;
1747 GPtrArray *ifaces;
1748 GPtrArray **ifaces_array = NULL;
1749 int interface_offsets_count;
1751 mono_loader_lock ();
1753 mono_class_setup_supertypes (klass);
1755 /* compute maximum number of slots and maximum interface id */
1756 max_iid = 0;
1757 num_ifaces = 0; /* this can include duplicated ones */
1758 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
1759 for (j = 0; j < klass->idepth; j++) {
1760 k = klass->supertypes [j];
1761 g_assert (k);
1762 num_ifaces += k->interface_count;
1763 for (i = 0; i < k->interface_count; i++) {
1764 ic = k->interfaces [i];
1766 /* A gparam does not have any interface_id set. */
1767 if (! mono_class_is_gparam (ic))
1768 mono_class_init (ic);
1770 if (max_iid < ic->interface_id)
1771 max_iid = ic->interface_id;
1773 ifaces = mono_class_get_implemented_interfaces (k, error);
1774 if (!mono_error_ok (error)) {
1775 char *name = mono_type_get_full_name (k);
1776 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (error));
1777 g_free (name);
1778 mono_error_cleanup (error);
1779 cur_slot = -1;
1780 goto end;
1782 if (ifaces) {
1783 num_ifaces += ifaces->len;
1784 for (i = 0; i < ifaces->len; ++i) {
1785 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1786 if (max_iid < ic->interface_id)
1787 max_iid = ic->interface_id;
1789 ifaces_array [j] = ifaces;
1793 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
1794 num_ifaces++;
1795 if (max_iid < klass->interface_id)
1796 max_iid = klass->interface_id;
1799 /* compute vtable offset for interfaces */
1800 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
1801 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
1803 for (i = 0; i < num_ifaces; i++)
1804 interface_offsets_full [i] = -1;
1806 /* skip the current class */
1807 for (j = 0; j < klass->idepth - 1; j++) {
1808 k = klass->supertypes [j];
1809 ifaces = ifaces_array [j];
1811 if (ifaces) {
1812 for (i = 0; i < ifaces->len; ++i) {
1813 int io;
1814 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1816 /*Force the sharing of interface offsets between parent and subtypes.*/
1817 io = mono_class_interface_offset (k, ic);
1818 g_assert (io >= 0);
1819 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
1824 g_assert (klass == klass->supertypes [klass->idepth - 1]);
1825 ifaces = ifaces_array [klass->idepth - 1];
1826 if (ifaces) {
1827 for (i = 0; i < ifaces->len; ++i) {
1828 int count;
1829 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
1830 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
1831 continue;
1832 count = count_virtual_methods (ic);
1833 if (count == -1) {
1834 char *name = mono_type_get_full_name (ic);
1835 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
1836 g_free (name);
1837 cur_slot = -1;
1838 goto end;
1840 cur_slot += count;
1844 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass))
1845 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
1847 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
1848 if (interface_offsets_full [i] != -1)
1849 interface_offsets_count ++;
1852 /* Publish the data */
1853 klass->max_interface_id = max_iid;
1855 * We might get called multiple times:
1856 * - mono_class_init ()
1857 * - mono_class_setup_vtable ().
1858 * - mono_class_setup_interface_offsets ().
1859 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1860 * means we have to overwrite those when called from other places (#4440).
1862 if (klass->interfaces_packed) {
1863 if (!overwrite)
1864 g_assert (klass->interface_offsets_count == interface_offsets_count);
1865 } else {
1866 uint8_t *bitmap;
1867 int bsize;
1868 klass->interface_offsets_count = interface_offsets_count;
1869 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
1870 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
1871 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
1872 #ifdef COMPRESSED_INTERFACE_BITMAP
1873 bitmap = g_malloc0 (bsize);
1874 #else
1875 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
1876 #endif
1877 for (i = 0; i < interface_offsets_count; i++) {
1878 guint32 id = interfaces_full [i]->interface_id;
1879 bitmap [id >> 3] |= (1 << (id & 7));
1880 klass->interfaces_packed [i] = interfaces_full [i];
1881 klass->interface_offsets_packed [i] = interface_offsets_full [i];
1883 #ifdef COMPRESSED_INTERFACE_BITMAP
1884 i = mono_compress_bitmap (NULL, bitmap, bsize);
1885 klass->interface_bitmap = mono_class_alloc0 (klass, i);
1886 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
1887 g_free (bitmap);
1888 #else
1889 klass->interface_bitmap = bitmap;
1890 #endif
1892 end:
1893 mono_loader_unlock ();
1895 g_free (interfaces_full);
1896 g_free (interface_offsets_full);
1897 for (i = 0; i < klass->idepth; i++) {
1898 ifaces = ifaces_array [i];
1899 if (ifaces)
1900 g_ptr_array_free (ifaces, TRUE);
1902 g_free (ifaces_array);
1904 //printf ("JUST DONE: ");
1905 //print_implemented_interfaces (klass);
1907 return cur_slot;
1911 * Setup interface offsets for interfaces.
1912 * Initializes:
1913 * - klass->max_interface_id
1914 * - klass->interface_offsets_count
1915 * - klass->interfaces_packed
1916 * - klass->interface_offsets_packed
1917 * - klass->interface_bitmap
1919 * This function can fail @class.
1922 void
1923 mono_class_setup_interface_offsets (MonoClass *klass)
1925 /* NOTE: This function is only correct for interfaces.
1927 * It assumes that klass's interfaces can be assigned offsets starting
1928 * from 0. That assumption is incorrect for classes and valuetypes.
1930 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass) && !mono_class_is_ginst (klass));
1931 setup_interface_offsets (klass, 0, FALSE);
1934 #define DEBUG_INTERFACE_VTABLE_CODE 0
1935 #define TRACE_INTERFACE_VTABLE_CODE 0
1936 #define VERIFY_INTERFACE_VTABLE_CODE 0
1937 #define VTABLE_SELECTOR (1)
1939 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
1940 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
1941 if (!(VTABLE_SELECTOR)) break; \
1942 stmt;\
1943 } while (0)
1944 #else
1945 #define DEBUG_INTERFACE_VTABLE(stmt)
1946 #endif
1948 #if TRACE_INTERFACE_VTABLE_CODE
1949 #define TRACE_INTERFACE_VTABLE(stmt) do {\
1950 if (!(VTABLE_SELECTOR)) break; \
1951 stmt;\
1952 } while (0)
1953 #else
1954 #define TRACE_INTERFACE_VTABLE(stmt)
1955 #endif
1957 #if VERIFY_INTERFACE_VTABLE_CODE
1958 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
1959 if (!(VTABLE_SELECTOR)) break; \
1960 stmt;\
1961 } while (0)
1962 #else
1963 #define VERIFY_INTERFACE_VTABLE(stmt)
1964 #endif
1967 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
1968 static char*
1969 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
1971 int i;
1972 char *result;
1973 GString *res = g_string_new ("");
1975 g_string_append_c (res, '(');
1976 for (i = 0; i < sig->param_count; ++i) {
1977 if (i > 0)
1978 g_string_append_c (res, ',');
1979 mono_type_get_desc (res, sig->params [i], include_namespace);
1981 g_string_append (res, ")=>");
1982 if (sig->ret != NULL) {
1983 mono_type_get_desc (res, sig->ret, include_namespace);
1984 } else {
1985 g_string_append (res, "NULL");
1987 result = res->str;
1988 g_string_free (res, FALSE);
1989 return result;
1991 static void
1992 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
1993 char *im_sig = mono_signature_get_full_desc (mono_method_signature_internal (im), TRUE);
1994 char *cm_sig = mono_signature_get_full_desc (mono_method_signature_internal (cm), TRUE);
1995 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
1996 g_free (im_sig);
1997 g_free (cm_sig);
2001 #endif
2003 static gboolean
2004 is_wcf_hack_disabled (void)
2006 static gboolean disabled;
2007 static gboolean inited = FALSE;
2008 if (!inited) {
2009 disabled = g_hasenv ("MONO_DISABLE_WCF_HACK");
2010 inited = TRUE;
2012 return disabled;
2015 static gboolean
2016 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
2018 MonoMethodSignature *cmsig, *imsig;
2019 if (strcmp (im->name, cm->name) == 0) {
2020 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
2021 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2022 return FALSE;
2024 if (! slot_is_empty) {
2025 if (require_newslot) {
2026 if (! interface_is_explicitly_implemented_by_class) {
2027 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2028 return FALSE;
2030 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
2031 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2032 return FALSE;
2034 } else {
2035 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2038 cmsig = mono_method_signature_internal (cm);
2039 imsig = mono_method_signature_internal (im);
2040 if (!cmsig || !imsig) {
2041 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2042 return FALSE;
2045 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2046 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2047 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2048 TRACE_INTERFACE_VTABLE (printf ("]"));
2049 return FALSE;
2051 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2052 if (mono_security_core_clr_enabled ())
2053 mono_security_core_clr_check_override (klass, cm, im);
2055 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2056 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2057 char *body_name = mono_method_full_name (cm, TRUE);
2058 char *decl_name = mono_method_full_name (im, TRUE);
2059 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2060 g_free (body_name);
2061 g_free (decl_name);
2062 return FALSE;
2065 return TRUE;
2066 } else {
2067 MonoClass *ic = im->klass;
2068 const char *ic_name_space = ic->name_space;
2069 const char *ic_name = ic->name;
2070 char *subname;
2072 if (! require_newslot) {
2073 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2074 return FALSE;
2076 if (cm->klass->rank == 0) {
2077 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2078 return FALSE;
2080 cmsig = mono_method_signature_internal (cm);
2081 imsig = mono_method_signature_internal (im);
2082 if (!cmsig || !imsig) {
2083 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
2084 return FALSE;
2087 if (! mono_metadata_signature_equal (cmsig, imsig)) {
2088 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2089 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
2090 TRACE_INTERFACE_VTABLE (printf ("]"));
2091 return FALSE;
2093 if (mono_class_get_image (ic) != mono_defaults.corlib) {
2094 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2095 return FALSE;
2097 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
2098 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2099 return FALSE;
2101 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))) {
2102 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2103 return FALSE;
2106 subname = (char*)strstr (cm->name, ic_name_space);
2107 if (subname != cm->name) {
2108 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2109 return FALSE;
2111 subname += strlen (ic_name_space);
2112 if (subname [0] != '.') {
2113 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2114 return FALSE;
2116 subname ++;
2117 if (strstr (subname, ic_name) != subname) {
2118 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2119 return FALSE;
2121 subname += strlen (ic_name);
2122 if (subname [0] != '.') {
2123 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2124 return FALSE;
2126 subname ++;
2127 if (strcmp (subname, im->name) != 0) {
2128 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2129 return FALSE;
2132 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2133 if (mono_security_core_clr_enabled ())
2134 mono_security_core_clr_check_override (klass, cm, im);
2136 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2137 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
2138 char *body_name = mono_method_full_name (cm, TRUE);
2139 char *decl_name = mono_method_full_name (im, TRUE);
2140 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2141 g_free (body_name);
2142 g_free (decl_name);
2143 return FALSE;
2146 return TRUE;
2150 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2151 static void
2152 foreach_override (gpointer key, gpointer value, gpointer user_data) {
2153 MonoMethod *method = key;
2154 MonoMethod *override = value;
2155 MonoClass *method_class = mono_method_get_class (method);
2156 MonoClass *override_class = mono_method_get_class (override);
2158 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
2159 m_class_get_name_space (method_class), m_class_get_name (method_class), mono_method_get_name (method),
2160 m_class_get_name_space (override_class), m_class_get_name (override_class), mono_method_get_name (override));
2162 static void
2163 print_overrides (GHashTable *override_map, const char *message) {
2164 if (override_map) {
2165 printf ("Override map \"%s\" START:\n", message);
2166 g_hash_table_foreach (override_map, foreach_override, NULL);
2167 printf ("Override map \"%s\" END.\n", message);
2168 } else {
2169 printf ("Override map \"%s\" EMPTY.\n", message);
2172 static void
2173 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
2174 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2175 int i;
2176 int parent_size;
2178 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
2180 if (print_interfaces) {
2181 print_implemented_interfaces (klass);
2182 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
2185 if (klass->parent) {
2186 parent_size = klass->parent->vtable_size;
2187 } else {
2188 parent_size = 0;
2190 for (i = 0; i < size; ++i) {
2191 MonoMethod *cm = vtable [i];
2192 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
2193 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
2195 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
2196 g_free (cm_name);
2199 g_free (full_name);
2201 #endif
2203 #if VERIFY_INTERFACE_VTABLE_CODE
2204 static int
2205 mono_method_try_get_vtable_index (MonoMethod *method)
2207 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2208 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
2209 if (imethod->declaring->is_generic)
2210 return imethod->declaring->slot;
2212 return method->slot;
2215 static void
2216 mono_class_verify_vtable (MonoClass *klass)
2218 int i, count;
2219 char *full_name = mono_type_full_name (m_class_get_byval_arg (klass));
2221 printf ("*** Verifying VTable of class '%s' \n", full_name);
2222 g_free (full_name);
2223 full_name = NULL;
2225 if (!klass->methods)
2226 return;
2228 count = mono_class_get_method_count (klass);
2229 for (i = 0; i < count; ++i) {
2230 MonoMethod *cm = klass->methods [i];
2231 int slot;
2233 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
2234 continue;
2236 g_free (full_name);
2237 full_name = mono_method_full_name (cm, TRUE);
2239 slot = mono_method_try_get_vtable_index (cm);
2240 if (slot >= 0) {
2241 if (slot >= klass->vtable_size) {
2242 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
2243 continue;
2246 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
2247 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
2248 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
2249 g_free (other_name);
2251 } else
2252 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
2254 g_free (full_name);
2256 #endif
2258 static MonoMethod*
2259 mono_method_get_method_definition (MonoMethod *method)
2261 while (method->is_inflated)
2262 method = ((MonoMethodInflated*)method)->declaring;
2263 return method;
2266 static gboolean
2267 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
2269 int i;
2271 for (i = 0; i < onum; ++i) {
2272 MonoMethod *decl = overrides [i * 2];
2273 MonoMethod *body = overrides [i * 2 + 1];
2275 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
2276 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
2277 return FALSE;
2280 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
2281 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2282 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
2283 else
2284 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
2285 return FALSE;
2288 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
2289 if (body->flags & METHOD_ATTRIBUTE_STATIC)
2290 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
2291 else
2292 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
2293 return FALSE;
2296 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
2297 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
2298 return FALSE;
2301 body = mono_method_get_method_definition (body);
2302 decl = mono_method_get_method_definition (decl);
2304 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
2305 char *body_name = mono_method_full_name (body, TRUE);
2306 char *decl_name = mono_method_full_name (decl, TRUE);
2307 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
2308 g_free (body_name);
2309 g_free (decl_name);
2310 return FALSE;
2313 return TRUE;
2316 /*Checks if @klass has @parent as one of it's parents type gtd
2318 * For example:
2319 * Foo<T>
2320 * Bar<T> : Foo<Bar<Bar<T>>>
2323 static gboolean
2324 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
2326 klass = mono_class_get_generic_type_definition (klass);
2327 parent = mono_class_get_generic_type_definition (parent);
2328 mono_class_setup_supertypes (klass);
2329 mono_class_setup_supertypes (parent);
2331 return klass->idepth >= parent->idepth &&
2332 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
2335 gboolean
2336 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
2338 MonoGenericInst *ginst;
2339 int i;
2341 if (!mono_class_is_ginst (klass)) {
2342 mono_class_setup_vtable_full (klass, in_setup);
2343 return !mono_class_has_failure (klass);
2346 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
2347 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
2348 return FALSE;
2350 ginst = mono_class_get_generic_class (klass)->context.class_inst;
2351 for (i = 0; i < ginst->type_argc; ++i) {
2352 MonoClass *arg;
2353 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
2354 continue;
2355 arg = mono_class_from_mono_type_internal (ginst->type_argv [i]);
2356 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2357 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
2358 continue;
2359 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
2360 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
2361 return FALSE;
2364 return TRUE;
2368 * mono_class_setup_vtable:
2370 * Creates the generic vtable of CLASS.
2371 * Initializes the following fields in MonoClass:
2372 * - vtable
2373 * - vtable_size
2374 * Plus all the fields initialized by setup_interface_offsets ().
2375 * If there is an error during vtable construction, klass->has_failure
2376 * is set and details are stored in a MonoErrorBoxed.
2378 * LOCKING: Acquires the loader lock.
2380 void
2381 mono_class_setup_vtable (MonoClass *klass)
2383 mono_class_setup_vtable_full (klass, NULL);
2386 static void
2387 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
2389 ERROR_DECL (error);
2390 MonoMethod **overrides = NULL;
2391 MonoGenericContext *context;
2392 guint32 type_token;
2393 int onum = 0;
2395 if (klass->vtable)
2396 return;
2398 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
2399 /* This sets method->slot for all methods if this is an interface */
2400 mono_class_setup_methods (klass);
2401 return;
2404 if (mono_class_has_failure (klass))
2405 return;
2407 if (g_list_find (in_setup, klass))
2408 return;
2410 mono_loader_lock ();
2412 if (klass->vtable) {
2413 mono_loader_unlock ();
2414 return;
2417 UnlockedIncrement (&mono_stats.generic_vtable_count);
2418 in_setup = g_list_prepend (in_setup, klass);
2420 if (mono_class_is_ginst (klass)) {
2421 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
2422 mono_loader_unlock ();
2423 g_list_remove (in_setup, klass);
2424 return;
2427 context = mono_class_get_context (klass);
2428 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
2429 } else {
2430 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
2431 type_token = klass->type_token;
2434 if (image_is_dynamic (klass->image)) {
2435 /* Generic instances can have zero method overrides without causing any harm.
2436 * This is true since we don't do layout all over again for them, we simply inflate
2437 * the layout of the parent.
2439 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, error);
2440 if (!is_ok (error)) {
2441 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2442 goto done;
2444 } else {
2445 /* The following call fails if there are missing methods in the type */
2446 /* FIXME it's probably a good idea to avoid this for generic instances. */
2447 mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context, error);
2448 if (!is_ok (error)) {
2449 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (error));
2450 goto done;
2454 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
2456 done:
2457 g_free (overrides);
2458 mono_error_cleanup (error);
2460 mono_loader_unlock ();
2461 g_list_remove (in_setup, klass);
2463 return;
2466 static gboolean
2467 mono_class_need_stelemref_method (MonoClass *klass)
2469 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass)));
2472 static int
2473 apply_override (MonoClass *klass, MonoClass *override_class, MonoMethod **vtable, MonoMethod *decl, MonoMethod *override,
2474 GHashTable **override_map, GHashTable **override_class_map, GHashTable **conflict_map)
2476 int dslot;
2477 dslot = mono_method_get_vtable_slot (decl);
2478 if (dslot == -1) {
2479 mono_class_set_type_load_failure (klass, "");
2480 return FALSE;
2483 dslot += mono_class_interface_offset (klass, decl->klass);
2484 vtable [dslot] = override;
2485 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override->klass)) {
2487 * If override from an interface, then it is an override of a default interface method,
2488 * don't override its slot.
2490 vtable [dslot]->slot = dslot;
2493 if (!*override_map) {
2494 *override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2495 *override_class_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2497 GHashTable *map = *override_map;
2498 GHashTable *class_map = *override_class_map;
2500 MonoMethod *prev_override = (MonoMethod*)g_hash_table_lookup (map, decl);
2501 MonoClass *prev_override_class = (MonoClass*)g_hash_table_lookup (class_map, decl);
2503 g_hash_table_insert (map, decl, override);
2504 g_hash_table_insert (class_map, decl, override_class);
2506 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2507 if (prev_override) {
2508 ERROR_DECL (error);
2511 * The override methods are part of the generic definition, need to inflate them so their
2512 * parent class becomes the actual interface/class containing the override, i.e.
2513 * IFace<T> in:
2514 * class Foo<T> : IFace<T>
2515 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2516 * conflict resolution work.
2518 if (mono_class_is_ginst (override_class)) {
2519 override = mono_class_inflate_generic_method_checked (override, &mono_class_get_generic_class (override_class)->context, error);
2520 mono_error_assert_ok (error);
2523 if (mono_class_is_ginst (prev_override_class)) {
2524 prev_override = mono_class_inflate_generic_method_checked (prev_override, &mono_class_get_generic_class (prev_override_class)->context, error);
2525 mono_error_assert_ok (error);
2528 if (!*conflict_map)
2529 *conflict_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
2530 GHashTable *cmap = *conflict_map;
2531 GSList *entries = (GSList*)g_hash_table_lookup (cmap, decl);
2532 if (!(decl->flags & METHOD_ATTRIBUTE_ABSTRACT))
2533 entries = g_slist_prepend (entries, decl);
2534 entries = g_slist_prepend (entries, prev_override);
2535 entries = g_slist_prepend (entries, override);
2537 g_hash_table_insert (cmap, decl, entries);
2540 return TRUE;
2543 static void
2544 handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflict_map)
2546 GHashTableIter iter;
2547 MonoMethod *decl;
2548 GSList *entries, *l, *l2;
2549 GSList *dim_conflicts = NULL;
2551 g_hash_table_iter_init (&iter, conflict_map);
2552 while (g_hash_table_iter_next (&iter, (gpointer*)&decl, (gpointer*)&entries)) {
2554 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2555 * class of another one.
2557 /* This is O(n^2), but that shouldn't be a problem in practice */
2558 for (l = entries; l; l = l->next) {
2559 for (l2 = entries; l2; l2 = l2->next) {
2560 MonoMethod *m1 = (MonoMethod*)l->data;
2561 MonoMethod *m2 = (MonoMethod*)l2->data;
2562 if (!m1 || !m2 || m1 == m2)
2563 continue;
2564 if (mono_class_is_assignable_from_internal (m1->klass, m2->klass))
2565 l->data = NULL;
2566 else if (mono_class_is_assignable_from_internal (m2->klass, m1->klass))
2567 l2->data = NULL;
2570 int nentries = 0;
2571 MonoMethod *impl = NULL;
2572 for (l = entries; l; l = l->next) {
2573 if (l->data) {
2574 nentries ++;
2575 impl = (MonoMethod*)l->data;
2578 if (nentries > 1) {
2579 /* If more than one method is left, we have a conflict */
2580 if (decl->is_inflated)
2581 decl = ((MonoMethodInflated*)decl)->declaring;
2582 dim_conflicts = g_slist_prepend (dim_conflicts, decl);
2584 for (l = entries; l; l = l->next) {
2585 if (l->data)
2586 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2589 } else {
2591 * Use the implementing method computed above instead of the already
2592 * computed one, which depends on interface ordering.
2594 int ic_offset = mono_class_interface_offset (klass, decl->klass);
2595 int im_slot = ic_offset + decl->slot;
2596 vtable [im_slot] = impl;
2598 g_slist_free (entries);
2600 if (dim_conflicts) {
2601 mono_loader_lock ();
2602 klass->has_dim_conflicts = 1;
2603 mono_loader_unlock ();
2606 * Exceptions are thrown at method call time and only for the methods which have
2607 * conflicts, so just save them in the class.
2610 /* Make a copy of the list from the class mempool */
2611 GSList *conflicts = (GSList*)mono_class_alloc0 (klass, g_slist_length (dim_conflicts) * sizeof (GSList));
2612 int i = 0;
2613 for (l = dim_conflicts; l; l = l->next) {
2614 conflicts [i].data = l->data;
2615 conflicts [i].next = &conflicts [i + 1];
2616 i ++;
2618 conflicts [i - 1].next = NULL;
2620 mono_class_set_dim_conflicts (klass, conflicts);
2621 g_slist_free (dim_conflicts);
2625 static void
2626 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
2628 int index, mcount;
2629 char *method_signature;
2630 char *type_name;
2632 for (index = 0; index < onum; ++index) {
2633 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name,
2634 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
2636 method_signature = mono_signature_get_desc (mono_method_signature_internal (im), FALSE);
2637 type_name = mono_type_full_name (m_class_get_byval_arg (klass));
2638 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s",
2639 mono_type_get_name (m_class_get_byval_arg (ic)), im->name, method_signature, type_name);
2640 g_free (method_signature);
2641 g_free (type_name);
2642 mono_class_setup_methods (klass);
2643 if (mono_class_has_failure (klass)) {
2644 char *name = mono_type_get_full_name (klass);
2645 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name);
2646 g_free (name);
2647 return;
2649 mcount = mono_class_get_method_count (klass);
2650 for (index = 0; index < mcount; ++index) {
2651 MonoMethod *cm = klass->methods [index];
2652 method_signature = mono_signature_get_desc (mono_method_signature_internal (cm), TRUE);
2654 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature);
2655 g_free (method_signature);
2660 * mono_class_get_virtual_methods:
2662 * Iterate over the virtual methods of KLASS.
2664 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2666 static MonoMethod*
2667 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
2669 gboolean static_iter = FALSE;
2671 if (!iter)
2672 return NULL;
2675 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2676 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2677 * klass->methods.
2679 if ((gsize)(*iter) & 1)
2680 static_iter = TRUE;
2681 /* Use the static metadata only if klass->methods is not yet initialized */
2682 if (!static_iter && !(klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)))
2683 static_iter = TRUE;
2685 if (!static_iter) {
2686 MonoMethod** methodptr;
2688 if (!*iter) {
2689 mono_class_setup_methods (klass);
2691 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2692 * FIXME we should better report this error to the caller
2694 if (!klass->methods)
2695 return NULL;
2696 /* start from the first */
2697 methodptr = &klass->methods [0];
2698 } else {
2699 methodptr = (MonoMethod **)*iter;
2700 methodptr++;
2702 if (*iter)
2703 g_assert ((guint64)(*iter) > 0x100);
2704 int mcount = mono_class_get_method_count (klass);
2705 while (methodptr < &klass->methods [mcount]) {
2706 if (*methodptr && ((*methodptr)->flags & METHOD_ATTRIBUTE_VIRTUAL))
2707 break;
2708 methodptr ++;
2710 if (methodptr < &klass->methods [mcount]) {
2711 *iter = methodptr;
2712 return *methodptr;
2713 } else {
2714 return NULL;
2716 } else {
2717 /* Search directly in metadata to avoid calling setup_methods () */
2718 MonoMethod *res = NULL;
2719 int i, start_index;
2721 if (!*iter) {
2722 start_index = 0;
2723 } else {
2724 start_index = GPOINTER_TO_UINT (*iter) >> 1;
2727 int first_idx = mono_class_get_first_method_idx (klass);
2728 int mcount = mono_class_get_method_count (klass);
2729 for (i = start_index; i < mcount; ++i) {
2730 guint32 flags;
2732 /* first_idx points into the methodptr table */
2733 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
2735 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
2736 break;
2739 if (i < mcount) {
2740 ERROR_DECL (error);
2741 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, error);
2742 mono_error_cleanup (error); /* FIXME don't swallow the error */
2744 /* Add 1 here so the if (*iter) check fails */
2745 *iter = GUINT_TO_POINTER (((i + 1) << 1) | 1);
2746 return res;
2747 } else {
2748 return NULL;
2753 static void
2754 print_vtable_layout_result (MonoClass *klass, MonoMethod **vtable, int cur_slot)
2756 int i, icount = 0;
2758 print_implemented_interfaces (klass);
2760 for (i = 0; i <= klass->max_interface_id; i++)
2761 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
2762 icount++;
2764 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass)),
2765 klass->vtable_size, icount);
2767 for (i = 0; i < cur_slot; ++i) {
2768 MonoMethod *cm;
2770 cm = vtable [i];
2771 if (cm) {
2772 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
2773 mono_method_full_name (cm, TRUE));
2774 } else {
2775 printf (" slot assigned: %03d, <null>\n", i);
2780 if (icount) {
2781 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
2782 klass->name, klass->max_interface_id);
2784 for (i = 0; i < klass->interface_count; i++) {
2785 MonoClass *ic = klass->interfaces [i];
2786 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2787 mono_class_interface_offset (klass, ic),
2788 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2791 for (MonoClass *k = klass->parent; k ; k = k->parent) {
2792 for (i = 0; i < k->interface_count; i++) {
2793 MonoClass *ic = k->interfaces [i];
2794 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2795 mono_class_interface_offset (klass, ic),
2796 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (m_class_get_byval_arg (ic)));
2803 * LOCKING: this is supposed to be called with the loader lock held.
2805 void
2806 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
2808 ERROR_DECL (error);
2809 MonoClass *k, *ic;
2810 MonoMethod **vtable = NULL;
2811 int i, max_vtsize = 0, cur_slot = 0;
2812 GPtrArray *ifaces = NULL;
2813 GHashTable *override_map = NULL;
2814 GHashTable *override_class_map = NULL;
2815 GHashTable *conflict_map = NULL;
2816 MonoMethod *cm;
2817 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2818 int first_non_interface_slot;
2819 #endif
2820 GSList *virt_methods = NULL, *l;
2821 int stelemref_slot = 0;
2823 error_init (error);
2825 if (klass->vtable)
2826 return;
2828 if (overrides && !verify_class_overrides (klass, overrides, onum))
2829 return;
2831 ifaces = mono_class_get_implemented_interfaces (klass, error);
2832 if (!mono_error_ok (error)) {
2833 char *name = mono_type_get_full_name (klass);
2834 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (error));
2835 g_free (name);
2836 mono_error_cleanup (error);
2837 return;
2838 } else if (ifaces) {
2839 for (i = 0; i < ifaces->len; i++) {
2840 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2841 max_vtsize += mono_class_get_method_count (ic);
2843 g_ptr_array_free (ifaces, TRUE);
2844 ifaces = NULL;
2847 if (klass->parent) {
2848 mono_class_init (klass->parent);
2849 mono_class_setup_vtable_full (klass->parent, in_setup);
2851 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
2852 return;
2854 max_vtsize += klass->parent->vtable_size;
2855 cur_slot = klass->parent->vtable_size;
2858 max_vtsize += mono_class_get_method_count (klass);
2860 /*Array have a slot for stelemref*/
2861 if (mono_class_need_stelemref_method (klass)) {
2862 stelemref_slot = cur_slot;
2863 ++max_vtsize;
2864 ++cur_slot;
2867 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
2869 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
2870 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
2871 return;
2873 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
2875 /* Optimized version for generic instances */
2876 if (mono_class_is_ginst (klass)) {
2877 ERROR_DECL (error);
2878 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2879 MonoMethod **tmp;
2881 mono_class_setup_vtable_full (gklass, in_setup);
2882 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
2883 return;
2885 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
2886 klass->vtable_size = gklass->vtable_size;
2887 for (i = 0; i < gklass->vtable_size; ++i)
2888 if (gklass->vtable [i]) {
2889 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), error);
2890 goto_if_nok (error, fail);
2891 tmp [i] = inflated;
2892 tmp [i]->slot = gklass->vtable [i]->slot;
2894 mono_memory_barrier ();
2895 klass->vtable = tmp;
2897 mono_loader_lock ();
2898 klass->has_dim_conflicts = gklass->has_dim_conflicts;
2899 mono_loader_unlock ();
2901 /* Have to set method->slot for abstract virtual methods */
2902 if (klass->methods && gklass->methods) {
2903 int mcount = mono_class_get_method_count (klass);
2904 for (i = 0; i < mcount; ++i)
2905 if (klass->methods [i]->slot == -1)
2906 klass->methods [i]->slot = gklass->methods [i]->slot;
2909 if (mono_print_vtable)
2910 print_vtable_layout_result (klass, klass->vtable, gklass->vtable_size);
2912 return;
2915 vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize);
2917 if (klass->parent && klass->parent->vtable_size) {
2918 MonoClass *parent = klass->parent;
2919 int i;
2921 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
2923 // Also inherit parent interface vtables, just as a starting point.
2924 // This is needed otherwise bug-77127.exe fails when the property methods
2925 // have different names in the iterface and the class, because for child
2926 // classes the ".override" information is not used anymore.
2927 for (i = 0; i < parent->interface_offsets_count; i++) {
2928 MonoClass *parent_interface = parent->interfaces_packed [i];
2929 int interface_offset = mono_class_interface_offset (klass, parent_interface);
2930 /*FIXME this is now dead code as this condition will never hold true.
2931 Since interface offsets are inherited then the offset of an interface implemented
2932 by a parent will never be the out of it's vtable boundary.
2934 if (interface_offset >= parent->vtable_size) {
2935 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
2936 int j;
2938 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
2939 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
2940 int mcount = mono_class_get_method_count (parent_interface);
2941 for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
2942 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
2943 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
2944 parent_interface_offset + j, parent_interface_offset, j,
2945 interface_offset + j, interface_offset, j));
2952 /*Array have a slot for stelemref*/
2953 if (mono_class_need_stelemref_method (klass)) {
2954 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
2955 if (!method->slot)
2956 method->slot = stelemref_slot;
2957 else
2958 g_assert (method->slot == stelemref_slot);
2960 vtable [stelemref_slot] = method;
2963 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
2965 /* Process overrides from interface default methods */
2966 // FIXME: Ordering between interfaces
2967 for (int ifindex = 0; ifindex < klass->interface_offsets_count; ifindex++) {
2968 ic = klass->interfaces_packed [ifindex];
2970 mono_class_setup_methods (ic);
2971 if (mono_class_has_failure (ic))
2972 goto fail;
2974 MonoMethod **iface_overrides;
2975 int iface_onum;
2976 mono_class_get_overrides_full (ic->image, ic->type_token, &iface_overrides, &iface_onum, mono_class_get_context (ic), error);
2977 goto_if_nok (error, fail);
2978 for (int i = 0; i < iface_onum; i++) {
2979 MonoMethod *decl = iface_overrides [i*2];
2980 MonoMethod *override = iface_overrides [i*2 + 1];
2981 if (!apply_override (klass, ic, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
2982 goto fail;
2984 g_free (iface_overrides);
2987 /* override interface methods */
2988 for (i = 0; i < onum; i++) {
2989 MonoMethod *decl = overrides [i*2];
2990 MonoMethod *override = overrides [i*2 + 1];
2991 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
2992 if (!apply_override (klass, klass, vtable, decl, override, &override_map, &override_class_map, &conflict_map))
2993 goto fail;
2997 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
2998 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
3001 * Create a list of virtual methods to avoid calling
3002 * mono_class_get_virtual_methods () which is slow because of the metadata
3003 * optimization.
3006 gpointer iter = NULL;
3007 MonoMethod *cm;
3009 virt_methods = NULL;
3010 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
3011 virt_methods = g_slist_prepend (virt_methods, cm);
3013 if (mono_class_has_failure (klass))
3014 goto fail;
3017 // Loop on all implemented interfaces...
3018 for (i = 0; i < klass->interface_offsets_count; i++) {
3019 MonoClass *parent = klass->parent;
3020 int ic_offset;
3021 gboolean interface_is_explicitly_implemented_by_class;
3022 int im_index;
3024 ic = klass->interfaces_packed [i];
3025 ic_offset = mono_class_interface_offset (klass, ic);
3027 mono_class_setup_methods (ic);
3028 if (mono_class_has_failure (ic))
3029 goto fail;
3031 // Check if this interface is explicitly implemented (instead of just inherited)
3032 if (parent != NULL) {
3033 int implemented_interfaces_index;
3034 interface_is_explicitly_implemented_by_class = FALSE;
3035 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
3036 if (ic == klass->interfaces [implemented_interfaces_index]) {
3037 interface_is_explicitly_implemented_by_class = TRUE;
3038 break;
3041 } else {
3042 interface_is_explicitly_implemented_by_class = TRUE;
3045 // Loop on all interface methods...
3046 int mcount = mono_class_get_method_count (ic);
3047 for (im_index = 0; im_index < mcount; im_index++) {
3048 MonoMethod *im = ic->methods [im_index];
3049 int im_slot = ic_offset + im->slot;
3050 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
3052 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3053 continue;
3055 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
3057 // If there is an explicit implementation, just use it right away,
3058 // otherwise look for a matching method
3059 if (override_im == NULL) {
3060 int cm_index;
3061 MonoMethod *cm;
3063 // First look for a suitable method among the class methods
3064 for (l = virt_methods; l; l = l->next) {
3065 cm = (MonoMethod *)l->data;
3066 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)));
3067 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
3068 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3069 vtable [im_slot] = cm;
3070 /* Why do we need this? */
3071 if (cm->slot < 0) {
3072 cm->slot = im_slot;
3075 TRACE_INTERFACE_VTABLE (printf ("\n"));
3076 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3077 goto fail;
3080 // If the slot is still empty, look in all the inherited virtual methods...
3081 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
3082 MonoClass *parent = klass->parent;
3083 // Reverse order, so that last added methods are preferred
3084 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
3085 MonoMethod *cm = parent->vtable [cm_index];
3087 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));
3088 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
3089 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3090 vtable [im_slot] = cm;
3091 /* Why do we need this? */
3092 if (cm->slot < 0) {
3093 cm->slot = im_slot;
3095 break;
3097 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
3098 goto fail;
3099 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
3103 if (vtable [im_slot] == NULL) {
3104 if (!(im->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
3105 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im, 1)));
3106 vtable [im_slot] = im;
3109 } else {
3110 g_assert (vtable [im_slot] == override_im);
3115 // If the class is not abstract, check that all its interface slots are full.
3116 // The check is done here and not directly at the end of the loop above because
3117 // it can happen (for injected generic array interfaces) that the same slot is
3118 // processed multiple times (those interfaces have overlapping slots), and it
3119 // will not always be the first pass the one that fills the slot.
3120 if (!mono_class_is_abstract (klass)) {
3121 for (i = 0; i < klass->interface_offsets_count; i++) {
3122 int ic_offset;
3123 int im_index;
3125 ic = klass->interfaces_packed [i];
3126 ic_offset = mono_class_interface_offset (klass, ic);
3128 int mcount = mono_class_get_method_count (ic);
3129 for (im_index = 0; im_index < mcount; im_index++) {
3130 MonoMethod *im = ic->methods [im_index];
3131 int im_slot = ic_offset + im->slot;
3133 if (im->flags & METHOD_ATTRIBUTE_STATIC)
3134 continue;
3136 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3137 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
3138 if (vtable [im_slot] == NULL) {
3139 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
3140 goto fail;
3146 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
3147 for (l = virt_methods; l; l = l->next) {
3148 cm = (MonoMethod *)l->data;
3150 * If the method is REUSE_SLOT, we must check in the
3151 * base class for a method to override.
3153 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3154 int slot = -1;
3155 for (k = klass->parent; k ; k = k->parent) {
3156 gpointer k_iter;
3157 MonoMethod *m1;
3159 k_iter = NULL;
3160 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
3161 MonoMethodSignature *cmsig, *m1sig;
3163 cmsig = mono_method_signature_internal (cm);
3164 m1sig = mono_method_signature_internal (m1);
3166 if (!cmsig || !m1sig) /* FIXME proper error message, use signature_checked? */
3167 goto fail;
3169 if (!strcmp(cm->name, m1->name) &&
3170 mono_metadata_signature_equal (cmsig, m1sig)) {
3172 if (mono_security_core_clr_enabled ())
3173 mono_security_core_clr_check_override (klass, cm, m1);
3175 slot = mono_method_get_vtable_slot (m1);
3176 if (slot == -1)
3177 goto fail;
3179 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
3180 char *body_name = mono_method_full_name (cm, TRUE);
3181 char *decl_name = mono_method_full_name (m1, TRUE);
3182 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3183 g_free (body_name);
3184 g_free (decl_name);
3185 goto fail;
3188 g_assert (cm->slot < max_vtsize);
3189 if (!override_map)
3190 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3191 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3192 mono_method_full_name (m1, 1), m1,
3193 mono_method_full_name (cm, 1), cm));
3194 g_hash_table_insert (override_map, m1, cm);
3195 break;
3198 if (mono_class_has_failure (k))
3199 goto fail;
3201 if (slot >= 0)
3202 break;
3204 if (slot >= 0)
3205 cm->slot = slot;
3208 /*Non final newslot methods must be given a non-interface vtable slot*/
3209 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
3210 cm->slot = -1;
3212 if (cm->slot < 0)
3213 cm->slot = cur_slot++;
3215 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
3216 vtable [cm->slot] = cm;
3219 /* override non interface methods */
3220 for (i = 0; i < onum; i++) {
3221 MonoMethod *decl = overrides [i*2];
3222 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl->klass)) {
3223 g_assert (decl->slot != -1);
3224 vtable [decl->slot] = overrides [i*2 + 1];
3225 overrides [i * 2 + 1]->slot = decl->slot;
3226 if (!override_map)
3227 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
3228 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3229 mono_method_full_name (decl, 1), decl,
3230 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
3231 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
3233 if (mono_security_core_clr_enabled ())
3234 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
3239 * If a method occupies more than one place in the vtable, and it is
3240 * overriden, then change the other occurances too.
3242 if (override_map) {
3243 MonoMethod *cm;
3245 for (i = 0; i < max_vtsize; ++i)
3246 if (vtable [i]) {
3247 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
3249 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
3250 if (cm)
3251 vtable [i] = cm;
3254 g_hash_table_destroy (override_map);
3255 override_map = NULL;
3258 if (override_class_map)
3259 g_hash_table_destroy (override_class_map);
3261 if (conflict_map) {
3262 handle_dim_conflicts (vtable, klass, conflict_map);
3263 g_hash_table_destroy (conflict_map);
3266 g_slist_free (virt_methods);
3267 virt_methods = NULL;
3269 g_assert (cur_slot <= max_vtsize);
3271 /* Ensure that all vtable slots are filled with concrete instance methods */
3272 if (!mono_class_is_abstract (klass)) {
3273 for (i = 0; i < cur_slot; ++i) {
3274 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
3275 char *type_name = mono_type_get_full_name (klass);
3276 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
3277 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
3278 g_free (type_name);
3279 g_free (method_name);
3281 if (mono_print_vtable)
3282 print_vtable_layout_result (klass, vtable, cur_slot);
3284 g_free (vtable);
3285 return;
3290 if (mono_class_is_ginst (klass)) {
3291 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
3293 mono_class_init (gklass);
3295 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
3296 } else {
3297 /* Check that the vtable_size value computed in mono_class_init () is correct */
3298 if (klass->vtable_size)
3299 g_assert (cur_slot == klass->vtable_size);
3300 klass->vtable_size = cur_slot;
3303 /* Try to share the vtable with our parent. */
3304 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
3305 mono_memory_barrier ();
3306 klass->vtable = klass->parent->vtable;
3307 } else {
3308 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
3309 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
3310 mono_memory_barrier ();
3311 klass->vtable = tmp;
3314 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
3315 if (mono_print_vtable)
3316 print_vtable_layout_result (klass, vtable, cur_slot);
3318 g_free (vtable);
3320 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
3321 return;
3323 fail:
3325 char *name = mono_type_get_full_name (klass);
3326 if (!is_ok (error))
3327 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed due to: %s", name, mono_error_get_message (error));
3328 else
3329 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
3330 mono_error_cleanup (error);
3331 g_free (name);
3332 if (mono_print_vtable)
3333 print_vtable_layout_result (klass, vtable, cur_slot);
3336 g_free (vtable);
3337 if (override_map)
3338 g_hash_table_destroy (override_map);
3339 if (virt_methods)
3340 g_slist_free (virt_methods);
3344 static char*
3345 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
3347 int null_length = strlen ("(null)");
3348 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
3349 char *s = (char *)mono_image_alloc (image, len);
3350 int result;
3352 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
3353 g_assert (result == len - 1);
3355 return s;
3359 static void
3360 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
3362 if (cached_info) {
3363 mono_loader_lock ();
3364 klass->instance_size = cached_info->instance_size;
3365 klass->sizes.class_size = cached_info->class_size;
3366 klass->packing_size = cached_info->packing_size;
3367 klass->min_align = cached_info->min_align;
3368 klass->blittable = cached_info->blittable;
3369 klass->has_references = cached_info->has_references;
3370 klass->has_static_refs = cached_info->has_static_refs;
3371 klass->no_special_static_fields = cached_info->no_special_static_fields;
3372 klass->has_weak_fields = cached_info->has_weak_fields;
3373 mono_loader_unlock ();
3375 else {
3376 if (!klass->size_inited)
3377 mono_class_setup_fields (klass);
3382 * mono_class_init_sizes:
3384 * Initializes the size related fields of @klass without loading all field data if possible.
3385 * Sets the following fields in @klass:
3386 * - instance_size
3387 * - sizes.class_size
3388 * - packing_size
3389 * - min_align
3390 * - blittable
3391 * - has_references
3392 * - has_static_refs
3393 * - size_inited
3394 * Can fail the class.
3396 * LOCKING: Acquires the loader lock.
3398 void
3399 mono_class_init_sizes (MonoClass *klass)
3401 MonoCachedClassInfo cached_info;
3402 gboolean has_cached_info;
3404 if (klass->size_inited)
3405 return;
3407 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
3409 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
3413 static gboolean
3414 class_has_references (MonoClass *klass)
3416 mono_class_init_sizes (klass);
3419 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3420 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3421 * embed themselves.
3423 return klass->has_references;
3426 static gboolean
3427 type_has_references (MonoClass *klass, MonoType *ftype)
3429 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)))))
3430 return TRUE;
3431 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
3432 MonoGenericParam *gparam = ftype->data.generic_param;
3434 if (gparam->gshared_constraint)
3435 return class_has_references (mono_class_from_mono_type_internal (gparam->gshared_constraint));
3437 return FALSE;
3441 * mono_class_layout_fields:
3442 * @class: a class
3443 * @base_instance_size: base instance size
3444 * @packing_size:
3446 * This contains the common code for computing the layout of classes and sizes.
3447 * This should only be called from mono_class_setup_fields () and
3448 * typebuilder_setup_fields ().
3450 * LOCKING: Acquires the loader lock
3452 void
3453 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, int explicit_size, gboolean sre)
3455 int i;
3456 const int top = mono_class_get_field_count (klass);
3457 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
3458 guint32 pass, passes, real_size;
3459 gboolean gc_aware_layout = FALSE;
3460 gboolean has_static_fields = FALSE;
3461 gboolean has_references = FALSE;
3462 gboolean has_static_refs = FALSE;
3463 MonoClassField *field;
3464 gboolean blittable;
3465 int instance_size = base_instance_size;
3466 int element_size = -1;
3467 int class_size, min_align;
3468 int *field_offsets;
3469 gboolean *fields_has_references;
3472 * We want to avoid doing complicated work inside locks, so we compute all the required
3473 * information and write it to @klass inside a lock.
3475 if (klass->fields_inited)
3476 return;
3478 if ((packing_size & 0xffffff00) != 0) {
3479 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
3480 return;
3483 if (klass->parent) {
3484 min_align = klass->parent->min_align;
3485 /* we use | since it may have been set already */
3486 has_references = klass->has_references | klass->parent->has_references;
3487 } else {
3488 min_align = 1;
3490 /* We can't really enable 16 bytes alignment until the GC supports it.
3491 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3492 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3493 Bug #506144 is an example of this issue.
3495 if (klass->simd_type)
3496 min_align = 16;
3500 * When we do generic sharing we need to have layout
3501 * information for open generic classes (either with a generic
3502 * context containing type variables or with a generic
3503 * container), so we don't return in that case anymore.
3506 if (klass->enumtype) {
3507 for (i = 0; i < top; i++) {
3508 field = &klass->fields [i];
3509 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3510 klass->cast_class = klass->element_class = mono_class_from_mono_type_internal (field->type);
3511 break;
3515 if (!mono_class_enum_basetype_internal (klass)) {
3516 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
3517 return;
3522 * Enable GC aware auto layout: in this mode, reference
3523 * fields are grouped together inside objects, increasing collector
3524 * performance.
3525 * Requires that all classes whose layout is known to native code be annotated
3526 * with [StructLayout (LayoutKind.Sequential)]
3527 * Value types have gc_aware_layout disabled by default, as per
3528 * what the default is for other runtimes.
3530 /* corlib is missing [StructLayout] directives in many places */
3531 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
3532 if (!klass->valuetype)
3533 gc_aware_layout = TRUE;
3536 /* Compute klass->blittable */
3537 blittable = TRUE;
3538 if (klass->parent)
3539 blittable = klass->parent->blittable;
3540 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
3541 blittable = FALSE;
3542 for (i = 0; i < top; i++) {
3543 field = &klass->fields [i];
3545 if (mono_field_is_deleted (field))
3546 continue;
3547 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3548 continue;
3549 if (blittable) {
3550 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
3551 blittable = FALSE;
3552 } else {
3553 MonoClass *field_class = mono_class_from_mono_type_internal (field->type);
3554 if (field_class) {
3555 mono_class_setup_fields (field_class);
3556 if (mono_class_has_failure (field_class)) {
3557 ERROR_DECL_VALUE (field_error);
3558 error_init (&field_error);
3559 mono_error_set_for_class_failure (&field_error, field_class);
3560 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
3561 mono_error_cleanup (&field_error);
3562 break;
3565 if (!field_class || !field_class->blittable)
3566 blittable = FALSE;
3569 if (klass->enumtype)
3570 blittable = klass->element_class->blittable;
3572 if (mono_class_has_failure (klass))
3573 return;
3574 if (klass == mono_defaults.string_class)
3575 blittable = FALSE;
3577 /* Compute klass->has_references */
3579 * Process non-static fields first, since static fields might recursively
3580 * refer to the class itself.
3582 for (i = 0; i < top; i++) {
3583 MonoType *ftype;
3585 field = &klass->fields [i];
3587 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3588 ftype = mono_type_get_underlying_type (field->type);
3589 ftype = mono_type_get_basic_type_from_generic (ftype);
3590 if (type_has_references (klass, ftype))
3591 has_references = TRUE;
3596 * Compute field layout and total size (not considering static fields)
3598 field_offsets = g_new0 (int, top);
3599 fields_has_references = g_new0 (gboolean, top);
3600 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
3601 switch (layout) {
3602 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
3603 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
3604 if (gc_aware_layout)
3605 passes = 2;
3606 else
3607 passes = 1;
3609 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
3610 passes = 1;
3612 if (klass->parent) {
3613 mono_class_setup_fields (klass->parent);
3614 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
3615 return;
3616 real_size = klass->parent->instance_size;
3617 } else {
3618 real_size = MONO_ABI_SIZEOF (MonoObject);
3621 for (pass = 0; pass < passes; ++pass) {
3622 for (i = 0; i < top; i++){
3623 gint32 align;
3624 guint32 size;
3625 MonoType *ftype;
3627 field = &klass->fields [i];
3629 if (mono_field_is_deleted (field))
3630 continue;
3631 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3632 continue;
3634 ftype = mono_type_get_underlying_type (field->type);
3635 ftype = mono_type_get_basic_type_from_generic (ftype);
3636 if (gc_aware_layout) {
3637 fields_has_references [i] = type_has_references (klass, ftype);
3638 if (fields_has_references [i]) {
3639 if (pass == 1)
3640 continue;
3641 } else {
3642 if (pass == 0)
3643 continue;
3647 if ((top == 1) && (instance_size == MONO_ABI_SIZEOF (MonoObject)) &&
3648 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
3649 /* This field is a hack inserted by MCS to empty structures */
3650 continue;
3653 size = mono_type_size (field->type, &align);
3655 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3656 align = packing_size ? MIN (packing_size, align): align;
3657 /* if the field has managed references, we need to force-align it
3658 * see bug #77788
3660 if (type_has_references (klass, ftype))
3661 align = MAX (align, TARGET_SIZEOF_VOID_P);
3663 min_align = MAX (align, min_align);
3664 field_offsets [i] = real_size;
3665 if (align) {
3666 field_offsets [i] += align - 1;
3667 field_offsets [i] &= ~(align - 1);
3669 /*TypeBuilders produce all sort of weird things*/
3670 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
3671 real_size = field_offsets [i] + size;
3674 instance_size = MAX (real_size, instance_size);
3676 if (instance_size & (min_align - 1)) {
3677 instance_size += min_align - 1;
3678 instance_size &= ~(min_align - 1);
3681 break;
3682 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
3683 guint8 *ref_bitmap;
3685 real_size = 0;
3686 for (i = 0; i < top; i++) {
3687 gint32 align;
3688 guint32 size;
3689 MonoType *ftype;
3691 field = &klass->fields [i];
3694 * There must be info about all the fields in a type if it
3695 * uses explicit layout.
3697 if (mono_field_is_deleted (field))
3698 continue;
3699 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3700 continue;
3702 size = mono_type_size (field->type, &align);
3703 align = packing_size ? MIN (packing_size, align): align;
3704 min_align = MAX (align, min_align);
3706 if (sre) {
3707 /* Already set by typebuilder_setup_fields () */
3708 field_offsets [i] = field->offset + MONO_ABI_SIZEOF (MonoObject);
3709 } else {
3710 int idx = first_field_idx + i;
3711 guint32 offset;
3712 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
3713 field_offsets [i] = offset + MONO_ABI_SIZEOF (MonoObject);
3715 ftype = mono_type_get_underlying_type (field->type);
3716 ftype = mono_type_get_basic_type_from_generic (ftype);
3717 if (type_has_references (klass, ftype)) {
3718 if (field_offsets [i] % TARGET_SIZEOF_VOID_P) {
3719 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
3724 * Calc max size.
3726 real_size = MAX (real_size, size + field_offsets [i]);
3729 if (klass->has_references) {
3730 ref_bitmap = g_new0 (guint8, real_size / TARGET_SIZEOF_VOID_P);
3732 /* Check for overlapping reference and non-reference fields */
3733 for (i = 0; i < top; i++) {
3734 MonoType *ftype;
3736 field = &klass->fields [i];
3738 if (mono_field_is_deleted (field))
3739 continue;
3740 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3741 continue;
3742 ftype = mono_type_get_underlying_type (field->type);
3743 if (MONO_TYPE_IS_REFERENCE (ftype))
3744 ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P] = 1;
3746 for (i = 0; i < top; i++) {
3747 field = &klass->fields [i];
3749 if (mono_field_is_deleted (field))
3750 continue;
3751 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3752 continue;
3754 // FIXME: Too much code does this
3755 #if 0
3756 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / TARGET_SIZEOF_VOID_P]) {
3757 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]);
3759 #endif
3761 g_free (ref_bitmap);
3764 instance_size = MAX (real_size, instance_size);
3765 if (!((layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && explicit_size)) {
3766 if (instance_size & (min_align - 1)) {
3767 instance_size += min_align - 1;
3768 instance_size &= ~(min_align - 1);
3771 break;
3775 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
3777 * This leads to all kinds of problems with nested structs, so only
3778 * enable it when a MONO_DEBUG property is set.
3780 * For small structs, set min_align to at least the struct size to improve
3781 * performance, and since the JIT memset/memcpy code assumes this and generates
3782 * unaligned accesses otherwise. See #78990 for a testcase.
3784 if (mono_align_small_structs && top) {
3785 if (instance_size <= MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer))
3786 min_align = MAX (min_align, instance_size - MONO_ABI_SIZEOF (MonoObject));
3790 MonoType *klass_byval_arg = m_class_get_byval_arg (klass);
3791 if (klass_byval_arg->type == MONO_TYPE_VAR || klass_byval_arg->type == MONO_TYPE_MVAR)
3792 instance_size = MONO_ABI_SIZEOF (MonoObject) + mono_type_stack_size_internal (klass_byval_arg, NULL, TRUE);
3793 else if (klass_byval_arg->type == MONO_TYPE_PTR)
3794 instance_size = MONO_ABI_SIZEOF (MonoObject) + MONO_ABI_SIZEOF (gpointer);
3796 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3797 element_size = mono_class_array_element_size (klass->element_class);
3799 /* Publish the data */
3800 mono_loader_lock ();
3801 if (klass->instance_size && !klass->image->dynamic) {
3802 /* Might be already set using cached info */
3803 if (klass->instance_size != instance_size) {
3804 /* Emit info to help debugging */
3805 g_print ("%s\n", mono_class_full_name (klass));
3806 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
3807 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
3808 g_print ("%d %d\n", klass->min_align, min_align);
3809 for (i = 0; i < top; ++i) {
3810 field = &klass->fields [i];
3811 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3812 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
3815 g_assert (klass->instance_size == instance_size);
3816 } else {
3817 klass->instance_size = instance_size;
3819 klass->blittable = blittable;
3820 klass->has_references = has_references;
3821 klass->packing_size = packing_size;
3822 klass->min_align = min_align;
3823 for (i = 0; i < top; ++i) {
3824 field = &klass->fields [i];
3825 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
3826 klass->fields [i].offset = field_offsets [i];
3829 if (klass_byval_arg->type == MONO_TYPE_SZARRAY || klass_byval_arg->type == MONO_TYPE_ARRAY)
3830 klass->sizes.element_size = element_size;
3832 mono_memory_barrier ();
3833 klass->size_inited = 1;
3834 mono_loader_unlock ();
3837 * Compute static field layout and size
3838 * Static fields can reference the class itself, so this has to be
3839 * done after instance_size etc. are initialized.
3841 class_size = 0;
3842 for (i = 0; i < top; i++) {
3843 gint32 align;
3844 guint32 size;
3846 field = &klass->fields [i];
3848 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3849 continue;
3850 if (mono_field_is_deleted (field))
3851 continue;
3853 if (mono_type_has_exceptions (field->type)) {
3854 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
3855 break;
3858 has_static_fields = TRUE;
3860 size = mono_type_size (field->type, &align);
3861 field_offsets [i] = class_size;
3862 /*align is always non-zero here*/
3863 field_offsets [i] += align - 1;
3864 field_offsets [i] &= ~(align - 1);
3865 class_size = field_offsets [i] + size;
3868 if (has_static_fields && class_size == 0)
3869 /* Simplify code which depends on class_size != 0 if the class has static fields */
3870 class_size = 8;
3872 /* Compute klass->has_static_refs */
3873 has_static_refs = FALSE;
3874 for (i = 0; i < top; i++) {
3875 MonoType *ftype;
3877 field = &klass->fields [i];
3879 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3880 ftype = mono_type_get_underlying_type (field->type);
3881 ftype = mono_type_get_basic_type_from_generic (ftype);
3882 if (type_has_references (klass, ftype))
3883 has_static_refs = TRUE;
3887 /*valuetypes can't be neither bigger than 1Mb or empty. */
3888 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + MONO_ABI_SIZEOF (MonoObject)))) {
3889 /* Special case compiler generated types */
3890 /* Hard to check for [CompilerGenerated] here */
3891 if (!strstr (klass->name, "StaticArrayInitTypeSize") && !strstr (klass->name, "$ArrayType"))
3892 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
3895 // Weak field support
3897 // FIXME:
3898 // - generic instances
3899 // - Disallow on structs/static fields/nonref fields
3900 gboolean has_weak_fields = FALSE;
3902 if (mono_class_has_static_metadata (klass)) {
3903 for (MonoClass *p = klass; p != NULL; p = p->parent) {
3904 gpointer iter = NULL;
3905 guint32 first_field_idx = mono_class_get_first_field_idx (p);
3907 while ((field = mono_class_get_fields_internal (p, &iter))) {
3908 guint32 field_idx = first_field_idx + (field - p->fields);
3909 if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
3910 has_weak_fields = TRUE;
3911 mono_trace_message (MONO_TRACE_TYPE, "Field %s:%s at offset %x is weak.", field->parent->name, field->name, field->offset);
3918 * Check that any fields of IsByRefLike type are instance
3919 * fields and only inside other IsByRefLike structs.
3921 * (Has to be done late because we call
3922 * mono_class_from_mono_type_internal which may recursively
3923 * refer to the current class)
3925 gboolean allow_isbyreflike_fields = m_class_is_byreflike (klass);
3926 for (i = 0; i < top; i++) {
3927 field = &klass->fields [i];
3929 if (mono_field_is_deleted (field))
3930 continue;
3931 if ((field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
3932 continue;
3933 MonoClass *field_class = NULL;
3934 /* have to be careful not to recursively invoke mono_class_init on a static field.
3935 * for example - if the field is an array of a subclass of klass, we can loop.
3937 switch (field->type->type) {
3938 case MONO_TYPE_TYPEDBYREF:
3939 case MONO_TYPE_VALUETYPE:
3940 case MONO_TYPE_GENERICINST:
3941 field_class = mono_class_from_mono_type_internal (field->type);
3942 break;
3943 default:
3944 break;
3946 if (!field_class || !m_class_is_byreflike (field_class))
3947 continue;
3948 if ((field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
3949 mono_class_set_type_load_failure (klass, "Static ByRefLike field '%s' is not allowed", field->name);
3950 return;
3951 } else {
3952 /* instance field */
3953 if (allow_isbyreflike_fields)
3954 continue;
3955 mono_class_set_type_load_failure (klass, "Instance ByRefLike field '%s' not in a ref struct", field->name);
3956 return;
3960 /* Publish the data */
3961 mono_loader_lock ();
3962 if (!klass->rank)
3963 klass->sizes.class_size = class_size;
3964 klass->has_static_refs = has_static_refs;
3965 klass->has_weak_fields = has_weak_fields;
3966 for (i = 0; i < top; ++i) {
3967 field = &klass->fields [i];
3969 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3970 field->offset = field_offsets [i];
3972 mono_memory_barrier ();
3973 klass->fields_inited = 1;
3974 mono_loader_unlock ();
3976 g_free (field_offsets);
3977 g_free (fields_has_references);
3980 static MonoMethod *default_ghc = NULL;
3981 static MonoMethod *default_finalize = NULL;
3982 static int finalize_slot = -1;
3983 static int ghc_slot = -1;
3985 static void
3986 initialize_object_slots (MonoClass *klass)
3988 int i;
3989 if (default_ghc)
3990 return;
3991 if (klass == mono_defaults.object_class) {
3992 mono_class_setup_vtable (klass);
3993 for (i = 0; i < klass->vtable_size; ++i) {
3994 MonoMethod *cm = klass->vtable [i];
3996 if (!strcmp (cm->name, "GetHashCode"))
3997 ghc_slot = i;
3998 else if (!strcmp (cm->name, "Finalize"))
3999 finalize_slot = i;
4002 g_assert (ghc_slot > 0);
4003 default_ghc = klass->vtable [ghc_slot];
4005 g_assert (finalize_slot > 0);
4006 default_finalize = klass->vtable [finalize_slot];
4011 mono_class_get_object_finalize_slot ()
4013 return finalize_slot;
4016 MonoMethod *
4017 mono_class_get_default_finalize_method ()
4019 return default_finalize;
4022 typedef struct {
4023 MonoMethod *array_method;
4024 char *name;
4025 } GenericArrayMethodInfo;
4027 static int generic_array_method_num = 0;
4028 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4030 static void
4031 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos, GHashTable *cache)
4033 MonoGenericContext tmp_context;
4034 int i;
4036 tmp_context.class_inst = NULL;
4037 tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
4038 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4040 for (i = 0; i < generic_array_method_num; i++) {
4041 ERROR_DECL (error);
4042 MonoMethod *m = generic_array_method_info [i].array_method;
4043 MonoMethod *inflated, *helper;
4045 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, error);
4046 mono_error_assert_ok (error);
4047 helper = (MonoMethod*)g_hash_table_lookup (cache, inflated);
4048 if (!helper) {
4049 helper = mono_marshal_get_generic_array_helper (klass, generic_array_method_info [i].name, inflated);
4050 g_hash_table_insert (cache, inflated, helper);
4052 methods [pos ++] = helper;
4056 static int
4057 generic_array_methods (MonoClass *klass)
4059 int i, count_generic = 0, mcount;
4060 GList *list = NULL, *tmp;
4061 if (generic_array_method_num)
4062 return generic_array_method_num;
4063 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4064 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4065 mcount = mono_class_get_method_count (klass->parent);
4066 for (i = 0; i < mcount; i++) {
4067 MonoMethod *m = klass->parent->methods [i];
4068 if (!strncmp (m->name, "InternalArray__", 15)) {
4069 count_generic++;
4070 list = g_list_prepend (list, m);
4073 list = g_list_reverse (list);
4074 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4075 i = 0;
4076 for (tmp = list; tmp; tmp = tmp->next) {
4077 const char *mname, *iname;
4078 gchar *name;
4079 MonoMethod *m = (MonoMethod *)tmp->data;
4080 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4081 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4083 generic_array_method_info [i].array_method = m;
4084 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4085 iname = "System.Collections.Generic.ICollection`1.";
4086 mname = m->name + 27;
4087 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4088 iname = "System.Collections.Generic.IEnumerable`1.";
4089 mname = m->name + 27;
4090 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4091 iname = "System.Collections.Generic.IReadOnlyList`1.";
4092 mname = m->name + strlen (ireadonlylist_prefix);
4093 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4094 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4095 mname = m->name + strlen (ireadonlycollection_prefix);
4096 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4097 iname = "System.Collections.Generic.IList`1.";
4098 mname = m->name + 15;
4099 } else {
4100 g_assert_not_reached ();
4103 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4104 strcpy (name, iname);
4105 strcpy (name + strlen (iname), mname);
4106 generic_array_method_info [i].name = name;
4107 i++;
4109 /*g_print ("array generic methods: %d\n", count_generic);*/
4111 generic_array_method_num = count_generic;
4112 g_list_free (list);
4113 return generic_array_method_num;
4117 * Global pool of interface IDs, represented as a bitset.
4118 * LOCKING: Protected by the classes lock.
4120 static MonoBitSet *global_interface_bitset = NULL;
4123 * mono_unload_interface_ids:
4124 * @bitset: bit set of interface IDs
4126 * When an image is unloaded, the interface IDs associated with
4127 * the image are put back in the global pool of IDs so the numbers
4128 * can be reused.
4130 void
4131 mono_unload_interface_ids (MonoBitSet *bitset)
4133 classes_lock ();
4134 mono_bitset_sub (global_interface_bitset, bitset);
4135 classes_unlock ();
4138 void
4139 mono_unload_interface_id (MonoClass *klass)
4141 if (global_interface_bitset && klass->interface_id) {
4142 classes_lock ();
4143 mono_bitset_clear (global_interface_bitset, klass->interface_id);
4144 classes_unlock ();
4149 * mono_get_unique_iid:
4150 * \param klass interface
4152 * Assign a unique integer ID to the interface represented by \p klass.
4153 * The ID will positive and as small as possible.
4154 * LOCKING: Acquires the classes lock.
4155 * \returns The new ID.
4157 static guint32
4158 mono_get_unique_iid (MonoClass *klass)
4160 int iid;
4162 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
4164 classes_lock ();
4166 if (!global_interface_bitset) {
4167 global_interface_bitset = mono_bitset_new (128, 0);
4170 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
4171 if (iid < 0) {
4172 int old_size = mono_bitset_size (global_interface_bitset);
4173 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
4174 mono_bitset_free (global_interface_bitset);
4175 global_interface_bitset = new_set;
4176 iid = old_size;
4178 mono_bitset_set (global_interface_bitset, iid);
4179 /* set the bit also in the per-image set */
4180 if (!mono_class_is_ginst (klass)) {
4181 if (klass->image->interface_bitset) {
4182 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
4183 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
4184 mono_bitset_free (klass->image->interface_bitset);
4185 klass->image->interface_bitset = new_set;
4187 } else {
4188 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
4190 mono_bitset_set (klass->image->interface_bitset, iid);
4193 classes_unlock ();
4195 #ifndef MONO_SMALL_CONFIG
4196 if (mono_print_vtable) {
4197 int generic_id;
4198 char *type_name = mono_type_full_name (m_class_get_byval_arg (klass));
4199 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
4200 if (gklass && !gklass->context.class_inst->is_open) {
4201 generic_id = gklass->context.class_inst->id;
4202 g_assert (generic_id != 0);
4203 } else {
4204 generic_id = 0;
4206 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->assembly_name, type_name, generic_id);
4207 g_free (type_name);
4209 #endif
4211 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4212 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4213 g_assert (iid < INT_MAX);
4214 return iid;
4218 * mono_class_init:
4219 * \param klass the class to initialize
4221 * Compute the \c instance_size, \c class_size and other infos that cannot be
4222 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4223 * Initializes the following fields in \p klass:
4224 * - all the fields initialized by \c mono_class_init_sizes
4225 * - has_cctor
4226 * - ghcimpl
4227 * - inited
4229 * LOCKING: Acquires the loader lock.
4231 * \returns TRUE on success or FALSE if there was a problem in loading
4232 * the type (incorrect assemblies, missing assemblies, methods, etc).
4234 gboolean
4235 mono_class_init (MonoClass *klass)
4237 int i, vtable_size = 0, array_method_count = 0;
4238 MonoCachedClassInfo cached_info;
4239 gboolean has_cached_info;
4240 gboolean locked = FALSE;
4241 gboolean ghcimpl = FALSE;
4242 gboolean has_cctor = FALSE;
4243 int first_iface_slot = 0;
4245 g_assert (klass);
4247 /* Double-checking locking pattern */
4248 if (klass->inited || mono_class_has_failure (klass))
4249 return !mono_class_has_failure (klass);
4251 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4254 * This function can recursively call itself.
4256 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
4257 if (g_slist_find (init_list, klass)) {
4258 mono_class_set_type_load_failure (klass, "Recursive type definition detected %s.%s", klass->name_space, klass->name);
4259 goto leave_no_init_pending;
4261 init_list = g_slist_prepend (init_list, klass);
4262 mono_native_tls_set_value (init_pending_tls_id, init_list);
4265 * We want to avoid doing complicated work inside locks, so we compute all the required
4266 * information and write it to @klass inside a lock.
4269 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
4270 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
4271 goto leave;
4274 MonoType *klass_byval_arg;
4275 klass_byval_arg = m_class_get_byval_arg (klass);
4276 if (klass_byval_arg->type == MONO_TYPE_ARRAY || klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4277 MonoClass *element_class = klass->element_class;
4278 MonoClass *cast_class = klass->cast_class;
4280 if (!element_class->inited)
4281 mono_class_init (element_class);
4282 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
4283 goto leave;
4284 if (!cast_class->inited)
4285 mono_class_init (cast_class);
4286 if (mono_class_set_type_load_failure_causedby_class (klass, cast_class, "Could not load array cast class"))
4287 goto leave;
4290 UnlockedIncrement (&mono_stats.initialized_class_count);
4292 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
4293 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4295 mono_class_init (gklass);
4296 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
4297 goto leave;
4299 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass))
4300 mono_class_setup_interface_id (klass);
4303 if (klass->parent && !klass->parent->inited)
4304 mono_class_init (klass->parent);
4306 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
4308 /* Compute instance size etc. */
4309 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
4310 if (mono_class_has_failure (klass))
4311 goto leave;
4313 mono_class_setup_supertypes (klass);
4315 if (!default_ghc)
4316 initialize_object_slots (klass);
4319 * Initialize the rest of the data without creating a generic vtable if possible.
4320 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4321 * also avoid computing a generic vtable.
4323 if (has_cached_info) {
4324 /* AOT case */
4325 vtable_size = cached_info.vtable_size;
4326 ghcimpl = cached_info.ghcimpl;
4327 has_cctor = cached_info.has_cctor;
4328 } else if (klass->rank == 1 && klass_byval_arg->type == MONO_TYPE_SZARRAY) {
4329 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4330 * The first slot if for array with.
4332 static int szarray_vtable_size[3] = { 0 };
4334 int slot;
4336 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass))))
4337 slot = 0;
4338 else if (klass->element_class->enumtype)
4339 slot = 1;
4340 else
4341 slot = 2;
4343 /* SZARRAY case */
4344 if (!szarray_vtable_size [slot]) {
4345 mono_class_setup_vtable (klass);
4346 szarray_vtable_size [slot] = klass->vtable_size;
4347 vtable_size = klass->vtable_size;
4348 } else {
4349 vtable_size = szarray_vtable_size[slot];
4351 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4352 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4354 /* Generic instance case */
4355 ghcimpl = gklass->ghcimpl;
4356 has_cctor = gklass->has_cctor;
4358 mono_class_setup_vtable (gklass);
4359 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
4360 goto leave;
4362 vtable_size = gklass->vtable_size;
4363 } else {
4364 /* General case */
4366 /* ghcimpl is not currently used
4367 klass->ghcimpl = 1;
4368 if (klass->parent) {
4369 MonoMethod *cmethod = klass->vtable [ghc_slot];
4370 if (cmethod->is_inflated)
4371 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
4372 if (cmethod == default_ghc) {
4373 klass->ghcimpl = 0;
4378 /* C# doesn't allow interfaces to have cctors */
4379 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || klass->image != mono_defaults.corlib) {
4380 MonoMethod *cmethod = NULL;
4382 if (mono_class_is_ginst (klass)) {
4383 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4385 /* Generic instance case */
4386 ghcimpl = gklass->ghcimpl;
4387 has_cctor = gklass->has_cctor;
4388 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
4389 cmethod = mono_find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
4390 /* The find_method function ignores the 'flags' argument */
4391 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
4392 has_cctor = 1;
4393 } else {
4394 mono_class_setup_methods (klass);
4395 if (mono_class_has_failure (klass))
4396 goto leave;
4398 int mcount = mono_class_get_method_count (klass);
4399 for (i = 0; i < mcount; ++i) {
4400 MonoMethod *method = klass->methods [i];
4401 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
4402 (strcmp (".cctor", method->name) == 0)) {
4403 has_cctor = 1;
4404 break;
4411 if (klass->rank) {
4412 array_method_count = 3 + (klass->rank > 1? 2: 1);
4414 if (klass->interface_count) {
4415 int count_generic = generic_array_methods (klass);
4416 array_method_count += klass->interface_count * count_generic;
4420 if (klass->parent) {
4421 if (!klass->parent->vtable_size)
4422 mono_class_setup_vtable (klass->parent);
4423 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
4424 goto leave;
4425 g_assert (klass->parent->vtable_size);
4426 first_iface_slot = klass->parent->vtable_size;
4427 if (mono_class_need_stelemref_method (klass))
4428 ++first_iface_slot;
4432 * Do the actual changes to @klass inside the loader lock
4434 mono_loader_lock ();
4435 locked = TRUE;
4437 if (klass->inited || mono_class_has_failure (klass)) {
4438 mono_loader_unlock ();
4439 /* Somebody might have gotten in before us */
4440 return !mono_class_has_failure (klass);
4443 UnlockedIncrement (&mono_stats.initialized_class_count);
4445 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
4446 UnlockedIncrement (&mono_stats.generic_class_count);
4448 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
4449 klass->nested_classes_inited = TRUE;
4450 klass->ghcimpl = ghcimpl;
4451 klass->has_cctor = has_cctor;
4452 if (vtable_size)
4453 klass->vtable_size = vtable_size;
4454 if (has_cached_info) {
4455 klass->has_finalize = cached_info.has_finalize;
4456 klass->has_finalize_inited = TRUE;
4458 if (klass->rank)
4459 mono_class_set_method_count (klass, array_method_count);
4461 mono_loader_unlock ();
4462 locked = FALSE;
4464 setup_interface_offsets (klass, first_iface_slot, TRUE);
4466 if (mono_security_core_clr_enabled ())
4467 mono_security_core_clr_check_inheritance (klass);
4469 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
4470 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
4472 goto leave;
4474 leave:
4475 init_list = (GSList*)mono_native_tls_get_value (init_pending_tls_id);
4476 init_list = g_slist_remove (init_list, klass);
4477 mono_native_tls_set_value (init_pending_tls_id, init_list);
4479 leave_no_init_pending:
4480 if (locked)
4481 mono_loader_unlock ();
4483 /* Leave this for last */
4484 mono_loader_lock ();
4485 klass->inited = 1;
4486 mono_loader_unlock ();
4488 return !mono_class_has_failure (klass);
4491 gboolean
4492 mono_class_init_checked (MonoClass *klass, MonoError *error)
4494 error_init (error);
4496 gboolean const success = mono_class_init (klass);
4498 if (!success)
4499 mono_error_set_for_class_failure (error, klass);
4501 return success;
4504 #ifndef DISABLE_COM
4506 * COM initialization is delayed until needed.
4507 * However when a [ComImport] attribute is present on a type it will trigger
4508 * the initialization. This is not a problem unless the BCL being executed
4509 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4511 static void
4512 init_com_from_comimport (MonoClass *klass)
4514 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4515 if (mono_security_core_clr_enabled ()) {
4516 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4517 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
4518 /* but it can not be made available for application (i.e. user code) since all COM calls
4519 * are considered native calls. In this case we fail with a TypeLoadException (just like
4520 * Silverlight 2 does */
4521 mono_class_set_type_load_failure (klass, "");
4522 return;
4526 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4528 #endif /*DISABLE_COM*/
4531 * LOCKING: this assumes the loader lock is held
4533 void
4534 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
4536 gboolean system_namespace;
4537 gboolean is_corlib = mono_is_corlib_image (klass->image);
4539 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
4541 /* if root of the hierarchy */
4542 if (system_namespace && !strcmp (klass->name, "Object")) {
4543 klass->parent = NULL;
4544 klass->instance_size = MONO_ABI_SIZEOF (MonoObject);
4545 return;
4547 if (!strcmp (klass->name, "<Module>")) {
4548 klass->parent = NULL;
4549 klass->instance_size = 0;
4550 return;
4553 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4554 /* Imported COM Objects always derive from __ComObject. */
4555 #ifndef DISABLE_COM
4556 if (MONO_CLASS_IS_IMPORT (klass)) {
4557 init_com_from_comimport (klass);
4558 if (parent == mono_defaults.object_class)
4559 parent = mono_class_get_com_object_class ();
4561 #endif
4562 if (!parent) {
4563 /* set the parent to something useful and safe, but mark the type as broken */
4564 parent = mono_defaults.object_class;
4565 mono_class_set_type_load_failure (klass, "");
4566 g_assert (parent);
4569 klass->parent = parent;
4571 if (mono_class_is_ginst (parent) && !parent->name) {
4573 * If the parent is a generic instance, we may get
4574 * called before it is fully initialized, especially
4575 * before it has its name.
4577 return;
4580 #ifndef DISABLE_REMOTING
4581 klass->marshalbyref = parent->marshalbyref;
4582 klass->contextbound = parent->contextbound;
4583 #endif
4585 klass->delegate = parent->delegate;
4587 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
4588 mono_class_set_is_com_object (klass);
4590 if (system_namespace) {
4591 #ifndef DISABLE_REMOTING
4592 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
4593 klass->marshalbyref = 1;
4595 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
4596 klass->contextbound = 1;
4597 #endif
4598 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
4599 klass->delegate = 1;
4602 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
4603 (strcmp (klass->parent->name_space, "System") == 0)))
4604 klass->valuetype = 1;
4605 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
4606 klass->valuetype = klass->enumtype = 1;
4608 /*klass->enumtype = klass->parent->enumtype; */
4609 } else {
4610 /* initialize com types if COM interfaces are present */
4611 #ifndef DISABLE_COM
4612 if (MONO_CLASS_IS_IMPORT (klass))
4613 init_com_from_comimport (klass);
4614 #endif
4615 klass->parent = NULL;
4621 * LOCKING: this assumes the loader lock is held
4623 void
4624 mono_class_setup_mono_type (MonoClass *klass)
4626 const char *name = klass->name;
4627 const char *nspace = klass->name_space;
4628 gboolean is_corlib = mono_is_corlib_image (klass->image);
4630 klass->this_arg.byref = 1;
4631 klass->this_arg.data.klass = klass;
4632 klass->this_arg.type = MONO_TYPE_CLASS;
4633 klass->_byval_arg.data.klass = klass;
4634 klass->_byval_arg.type = MONO_TYPE_CLASS;
4636 if (is_corlib && !strcmp (nspace, "System")) {
4637 if (!strcmp (name, "ValueType")) {
4639 * do not set the valuetype bit for System.ValueType.
4640 * klass->valuetype = 1;
4642 klass->blittable = TRUE;
4643 } else if (!strcmp (name, "Enum")) {
4645 * do not set the valuetype bit for System.Enum.
4646 * klass->valuetype = 1;
4648 klass->valuetype = 0;
4649 klass->enumtype = 0;
4650 } else if (!strcmp (name, "Object")) {
4651 klass->_byval_arg.type = MONO_TYPE_OBJECT;
4652 klass->this_arg.type = MONO_TYPE_OBJECT;
4653 } else if (!strcmp (name, "String")) {
4654 klass->_byval_arg.type = MONO_TYPE_STRING;
4655 klass->this_arg.type = MONO_TYPE_STRING;
4656 } else if (!strcmp (name, "TypedReference")) {
4657 klass->_byval_arg.type = MONO_TYPE_TYPEDBYREF;
4658 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
4662 if (klass->valuetype) {
4663 int t = MONO_TYPE_VALUETYPE;
4665 if (is_corlib && !strcmp (nspace, "System")) {
4666 switch (*name) {
4667 case 'B':
4668 if (!strcmp (name, "Boolean")) {
4669 t = MONO_TYPE_BOOLEAN;
4670 } else if (!strcmp(name, "Byte")) {
4671 t = MONO_TYPE_U1;
4672 klass->blittable = TRUE;
4674 break;
4675 case 'C':
4676 if (!strcmp (name, "Char")) {
4677 t = MONO_TYPE_CHAR;
4679 break;
4680 case 'D':
4681 if (!strcmp (name, "Double")) {
4682 t = MONO_TYPE_R8;
4683 klass->blittable = TRUE;
4685 break;
4686 case 'I':
4687 if (!strcmp (name, "Int32")) {
4688 t = MONO_TYPE_I4;
4689 klass->blittable = TRUE;
4690 } else if (!strcmp(name, "Int16")) {
4691 t = MONO_TYPE_I2;
4692 klass->blittable = TRUE;
4693 } else if (!strcmp(name, "Int64")) {
4694 t = MONO_TYPE_I8;
4695 klass->blittable = TRUE;
4696 } else if (!strcmp(name, "IntPtr")) {
4697 t = MONO_TYPE_I;
4698 klass->blittable = TRUE;
4700 break;
4701 case 'S':
4702 if (!strcmp (name, "Single")) {
4703 t = MONO_TYPE_R4;
4704 klass->blittable = TRUE;
4705 } else if (!strcmp(name, "SByte")) {
4706 t = MONO_TYPE_I1;
4707 klass->blittable = TRUE;
4709 break;
4710 case 'U':
4711 if (!strcmp (name, "UInt32")) {
4712 t = MONO_TYPE_U4;
4713 klass->blittable = TRUE;
4714 } else if (!strcmp(name, "UInt16")) {
4715 t = MONO_TYPE_U2;
4716 klass->blittable = TRUE;
4717 } else if (!strcmp(name, "UInt64")) {
4718 t = MONO_TYPE_U8;
4719 klass->blittable = TRUE;
4720 } else if (!strcmp(name, "UIntPtr")) {
4721 t = MONO_TYPE_U;
4722 klass->blittable = TRUE;
4724 break;
4725 case 'T':
4726 if (!strcmp (name, "TypedReference")) {
4727 t = MONO_TYPE_TYPEDBYREF;
4728 klass->blittable = TRUE;
4730 break;
4731 case 'V':
4732 if (!strcmp (name, "Void")) {
4733 t = MONO_TYPE_VOID;
4735 break;
4736 default:
4737 break;
4740 klass->_byval_arg.type = (MonoTypeEnum)t;
4741 klass->this_arg.type = (MonoTypeEnum)t;
4744 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4745 klass->interface_id = mono_get_unique_iid (klass);
4747 if (is_corlib && !strcmp (nspace, "System.Collections.Generic")) {
4748 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4749 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4750 * MS returns diferrent types based on which instance is called. For example:
4751 * object obj = new byte[10][];
4752 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4753 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4754 * a != b ==> true
4756 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
4757 klass->is_array_special_interface = 1;
4762 static MonoMethod*
4763 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
4765 MonoMethod *method;
4767 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
4768 method->klass = klass;
4769 method->flags = METHOD_ATTRIBUTE_PUBLIC;
4770 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
4771 method->signature = sig;
4772 method->name = name;
4773 method->slot = -1;
4774 /* .ctor */
4775 if (name [0] == '.') {
4776 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
4777 } else {
4778 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
4780 return method;
4784 * mono_class_setup_methods:
4785 * @class: a class
4787 * Initializes the 'methods' array in CLASS.
4788 * Calling this method should be avoided if possible since it allocates a lot
4789 * of long-living MonoMethod structures.
4790 * Methods belonging to an interface are assigned a sequential slot starting
4791 * from 0.
4793 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4795 void
4796 mono_class_setup_methods (MonoClass *klass)
4798 int i, count;
4799 MonoMethod **methods;
4801 if (klass->methods)
4802 return;
4804 if (mono_class_is_ginst (klass)) {
4805 ERROR_DECL (error);
4806 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4808 mono_class_init (gklass);
4809 if (!mono_class_has_failure (gklass))
4810 mono_class_setup_methods (gklass);
4811 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
4812 return;
4814 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4815 count = mono_class_get_method_count (gklass);
4816 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
4818 for (i = 0; i < count; i++) {
4819 methods [i] = mono_class_inflate_generic_method_full_checked (
4820 gklass->methods [i], klass, mono_class_get_context (klass), error);
4821 if (!mono_error_ok (error)) {
4822 char *method = mono_method_full_name (gklass->methods [i], TRUE);
4823 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (error));
4825 g_free (method);
4826 mono_error_cleanup (error);
4827 return;
4830 } else if (klass->rank) {
4831 ERROR_DECL (error);
4832 MonoMethod *amethod;
4833 MonoMethodSignature *sig;
4834 int count_generic = 0, first_generic = 0;
4835 int method_num = 0;
4836 gboolean jagged_ctor = FALSE;
4838 count = 3 + (klass->rank > 1? 2: 1);
4840 mono_class_setup_interfaces (klass, error);
4841 g_assert (mono_error_ok (error)); /*FIXME can this fail for array types?*/
4843 if (klass->rank == 1 && klass->element_class->rank) {
4844 jagged_ctor = TRUE;
4845 count ++;
4848 if (klass->interface_count) {
4849 count_generic = generic_array_methods (klass);
4850 first_generic = count;
4851 count += klass->interface_count * count_generic;
4854 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
4856 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4857 sig->ret = mono_get_void_type ();
4858 sig->pinvoke = TRUE;
4859 sig->hasthis = TRUE;
4860 for (i = 0; i < klass->rank; ++i)
4861 sig->params [i] = mono_get_int32_type ();
4863 amethod = create_array_method (klass, ".ctor", sig);
4864 methods [method_num++] = amethod;
4865 if (klass->rank > 1) {
4866 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
4867 sig->ret = mono_get_void_type ();
4868 sig->pinvoke = TRUE;
4869 sig->hasthis = TRUE;
4870 for (i = 0; i < klass->rank * 2; ++i)
4871 sig->params [i] = mono_get_int32_type ();
4873 amethod = create_array_method (klass, ".ctor", sig);
4874 methods [method_num++] = amethod;
4877 if (jagged_ctor) {
4878 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4879 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4880 sig->ret = mono_get_void_type ();
4881 sig->pinvoke = TRUE;
4882 sig->hasthis = TRUE;
4883 for (i = 0; i < klass->rank + 1; ++i)
4884 sig->params [i] = mono_get_int32_type ();
4885 amethod = create_array_method (klass, ".ctor", sig);
4886 methods [method_num++] = amethod;
4889 /* element Get (idx11, [idx2, ...]) */
4890 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4891 sig->ret = m_class_get_byval_arg (m_class_get_element_class (klass));
4892 sig->pinvoke = TRUE;
4893 sig->hasthis = TRUE;
4894 for (i = 0; i < klass->rank; ++i)
4895 sig->params [i] = mono_get_int32_type ();
4896 amethod = create_array_method (klass, "Get", sig);
4897 methods [method_num++] = amethod;
4898 /* element& Address (idx11, [idx2, ...]) */
4899 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
4900 sig->ret = &klass->element_class->this_arg;
4901 sig->pinvoke = TRUE;
4902 sig->hasthis = TRUE;
4903 for (i = 0; i < klass->rank; ++i)
4904 sig->params [i] = mono_get_int32_type ();
4905 amethod = create_array_method (klass, "Address", sig);
4906 methods [method_num++] = amethod;
4907 /* void Set (idx11, [idx2, ...], element) */
4908 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
4909 sig->ret = mono_get_void_type ();
4910 sig->pinvoke = TRUE;
4911 sig->hasthis = TRUE;
4912 for (i = 0; i < klass->rank; ++i)
4913 sig->params [i] = mono_get_int32_type ();
4914 sig->params [i] = m_class_get_byval_arg (m_class_get_element_class (klass));
4915 amethod = create_array_method (klass, "Set", sig);
4916 methods [method_num++] = amethod;
4918 GHashTable *cache = g_hash_table_new (NULL, NULL);
4919 for (i = 0; i < klass->interface_count; i++)
4920 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic, cache);
4921 g_hash_table_destroy (cache);
4922 } else if (mono_class_has_static_metadata (klass)) {
4923 ERROR_DECL (error);
4924 int first_idx = mono_class_get_first_method_idx (klass);
4926 count = mono_class_get_method_count (klass);
4927 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
4928 for (i = 0; i < count; ++i) {
4929 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
4930 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, error);
4931 if (!methods [i]) {
4932 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (error));
4933 mono_error_cleanup (error);
4936 } else {
4937 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
4938 count = 0;
4941 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass)) {
4942 int slot = 0;
4943 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
4944 for (i = 0; i < count; ++i) {
4945 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
4946 methods [i]->slot = slot++;
4950 mono_image_lock (klass->image);
4952 if (!klass->methods) {
4953 mono_class_set_method_count (klass, count);
4955 /* Needed because of the double-checking locking pattern */
4956 mono_memory_barrier ();
4958 klass->methods = methods;
4961 mono_image_unlock (klass->image);
4965 * mono_class_setup_properties:
4967 * Initialize klass->ext.property and klass->ext.properties.
4969 * This method can fail the class.
4971 void
4972 mono_class_setup_properties (MonoClass *klass)
4974 guint startm, endm, i, j;
4975 guint32 cols [MONO_PROPERTY_SIZE];
4976 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
4977 MonoProperty *properties;
4978 guint32 last;
4979 int first, count;
4980 MonoClassPropertyInfo *info;
4982 info = mono_class_get_property_info (klass);
4983 if (info)
4984 return;
4986 if (mono_class_is_ginst (klass)) {
4987 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4989 mono_class_init (gklass);
4990 mono_class_setup_properties (gklass);
4991 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
4992 return;
4994 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
4995 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
4997 for (i = 0; i < ginfo->count; i++) {
4998 ERROR_DECL (error);
4999 MonoProperty *prop = &properties [i];
5001 *prop = ginfo->properties [i];
5003 if (prop->get)
5004 prop->get = mono_class_inflate_generic_method_full_checked (
5005 prop->get, klass, mono_class_get_context (klass), error);
5006 if (prop->set)
5007 prop->set = mono_class_inflate_generic_method_full_checked (
5008 prop->set, klass, mono_class_get_context (klass), error);
5010 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5011 prop->parent = klass;
5014 first = ginfo->first;
5015 count = ginfo->count;
5016 } else {
5017 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5018 count = last - first;
5020 if (count) {
5021 mono_class_setup_methods (klass);
5022 if (mono_class_has_failure (klass))
5023 return;
5026 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
5027 for (i = first; i < last; ++i) {
5028 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
5029 properties [i - first].parent = klass;
5030 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
5031 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
5033 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
5034 int first_idx = mono_class_get_first_method_idx (klass);
5035 for (j = startm; j < endm; ++j) {
5036 MonoMethod *method;
5038 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5040 if (klass->image->uncompressed_metadata) {
5041 ERROR_DECL (error);
5042 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5043 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5044 mono_error_cleanup (error); /* FIXME don't swallow this error */
5045 } else {
5046 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5049 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5050 case METHOD_SEMANTIC_SETTER:
5051 properties [i - first].set = method;
5052 break;
5053 case METHOD_SEMANTIC_GETTER:
5054 properties [i - first].get = method;
5055 break;
5056 default:
5057 break;
5063 info = (MonoClassPropertyInfo*)mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
5064 info->first = first;
5065 info->count = count;
5066 info->properties = properties;
5067 mono_memory_barrier ();
5069 /* This might leak 'info' which was allocated from the image mempool */
5070 mono_class_set_property_info (klass, info);
5073 static MonoMethod**
5074 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
5076 MonoMethod **om, **retval;
5077 int count;
5079 for (om = methods, count = 0; *om; ++om, ++count)
5082 retval = g_new0 (MonoMethod*, count + 1);
5083 count = 0;
5084 for (om = methods, count = 0; *om; ++om, ++count) {
5085 ERROR_DECL (error);
5086 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, error);
5087 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5090 return retval;
5093 /*This method can fail the class.*/
5094 void
5095 mono_class_setup_events (MonoClass *klass)
5097 int first, count;
5098 guint startm, endm, i, j;
5099 guint32 cols [MONO_EVENT_SIZE];
5100 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
5101 guint32 last;
5102 MonoEvent *events;
5104 MonoClassEventInfo *info = mono_class_get_event_info (klass);
5105 if (info)
5106 return;
5108 if (mono_class_is_ginst (klass)) {
5109 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5110 MonoGenericContext *context = NULL;
5112 mono_class_setup_events (gklass);
5113 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
5114 return;
5116 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
5117 first = ginfo->first;
5118 count = ginfo->count;
5120 events = mono_class_new0 (klass, MonoEvent, count);
5122 if (count)
5123 context = mono_class_get_context (klass);
5125 for (i = 0; i < count; i++) {
5126 ERROR_DECL (error);
5127 MonoEvent *event = &events [i];
5128 MonoEvent *gevent = &ginfo->events [i];
5130 error_init (error); //since we do conditional calls, we must ensure the default value is ok
5132 event->parent = klass;
5133 event->name = gevent->name;
5134 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, error) : NULL;
5135 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5136 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, error) : NULL;
5137 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5138 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, error) : NULL;
5139 g_assert (mono_error_ok (error)); /*FIXME proper error handling*/
5141 #ifndef MONO_SMALL_CONFIG
5142 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
5143 #endif
5144 event->attrs = gevent->attrs;
5146 } else {
5147 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
5148 count = last - first;
5150 if (count) {
5151 mono_class_setup_methods (klass);
5152 if (mono_class_has_failure (klass)) {
5153 return;
5157 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
5158 for (i = first; i < last; ++i) {
5159 MonoEvent *event = &events [i - first];
5161 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
5162 event->parent = klass;
5163 event->attrs = cols [MONO_EVENT_FLAGS];
5164 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
5166 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
5167 int first_idx = mono_class_get_first_method_idx (klass);
5168 for (j = startm; j < endm; ++j) {
5169 MonoMethod *method;
5171 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
5173 if (klass->image->uncompressed_metadata) {
5174 ERROR_DECL (error);
5175 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5176 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, error);
5177 mono_error_cleanup (error); /* FIXME don't swallow this error */
5178 } else {
5179 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
5182 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
5183 case METHOD_SEMANTIC_ADD_ON:
5184 event->add = method;
5185 break;
5186 case METHOD_SEMANTIC_REMOVE_ON:
5187 event->remove = method;
5188 break;
5189 case METHOD_SEMANTIC_FIRE:
5190 event->raise = method;
5191 break;
5192 case METHOD_SEMANTIC_OTHER: {
5193 #ifndef MONO_SMALL_CONFIG
5194 int n = 0;
5196 if (event->other == NULL) {
5197 event->other = g_new0 (MonoMethod*, 2);
5198 } else {
5199 while (event->other [n])
5200 n++;
5201 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
5203 event->other [n] = method;
5204 /* NULL terminated */
5205 event->other [n + 1] = NULL;
5206 #endif
5207 break;
5209 default:
5210 break;
5216 info = (MonoClassEventInfo*)mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
5217 info->events = events;
5218 info->first = first;
5219 info->count = count;
5221 mono_memory_barrier ();
5223 mono_class_set_event_info (klass, info);
5228 * mono_class_setup_interface_id:
5230 * Initializes MonoClass::interface_id if required.
5232 * LOCKING: Acquires the loader lock.
5234 void
5235 mono_class_setup_interface_id (MonoClass *klass)
5237 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass));
5238 mono_loader_lock ();
5239 if (!klass->interface_id)
5240 klass->interface_id = mono_get_unique_iid (klass);
5241 mono_loader_unlock ();
5245 * mono_class_setup_interfaces:
5247 * Initialize klass->interfaces/interfaces_count.
5248 * LOCKING: Acquires the loader lock.
5249 * This function can fail the type.
5251 void
5252 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
5254 int i, interface_count;
5255 MonoClass **interfaces;
5257 error_init (error);
5259 if (klass->interfaces_inited)
5260 return;
5262 if (klass->rank == 1 && m_class_get_byval_arg (klass)->type != MONO_TYPE_ARRAY) {
5263 MonoType *args [1];
5265 /* IList and IReadOnlyList -> 2x if enum*/
5266 interface_count = klass->element_class->enumtype ? 4 : 2;
5267 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
5269 args [0] = m_class_get_byval_arg (m_class_get_element_class (klass));
5270 interfaces [0] = mono_class_bind_generic_parameters (
5271 mono_defaults.generic_ilist_class, 1, args, FALSE);
5272 interfaces [1] = mono_class_bind_generic_parameters (
5273 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5274 if (klass->element_class->enumtype) {
5275 args [0] = mono_class_enum_basetype_internal (klass->element_class);
5276 interfaces [2] = mono_class_bind_generic_parameters (
5277 mono_defaults.generic_ilist_class, 1, args, FALSE);
5278 interfaces [3] = mono_class_bind_generic_parameters (
5279 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
5281 } else if (mono_class_is_ginst (klass)) {
5282 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5284 mono_class_setup_interfaces (gklass, error);
5285 if (!mono_error_ok (error)) {
5286 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5287 return;
5290 interface_count = gklass->interface_count;
5291 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
5292 for (i = 0; i < interface_count; i++) {
5293 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
5294 if (!mono_error_ok (error)) {
5295 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
5296 return;
5299 } else {
5300 interface_count = 0;
5301 interfaces = NULL;
5304 mono_loader_lock ();
5305 if (!klass->interfaces_inited) {
5306 klass->interface_count = interface_count;
5307 klass->interfaces = interfaces;
5309 mono_memory_barrier ();
5311 klass->interfaces_inited = TRUE;
5313 mono_loader_unlock ();
5318 * mono_class_setup_has_finalizer:
5320 * Initialize klass->has_finalizer if it isn't already initialized.
5322 * LOCKING: Acquires the loader lock.
5324 void
5325 mono_class_setup_has_finalizer (MonoClass *klass)
5327 gboolean has_finalize = FALSE;
5329 if (m_class_is_has_finalize_inited (klass))
5330 return;
5332 /* Interfaces and valuetypes are not supposed to have finalizers */
5333 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass) || m_class_is_valuetype (klass))) {
5334 MonoMethod *cmethod = NULL;
5336 if (m_class_get_rank (klass) == 1 && m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
5337 } else if (mono_class_is_ginst (klass)) {
5338 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5340 has_finalize = mono_class_has_finalizer (gklass);
5341 } else if (m_class_get_parent (klass) && m_class_has_finalize (m_class_get_parent (klass))) {
5342 has_finalize = TRUE;
5343 } else {
5344 if (m_class_get_parent (klass)) {
5346 * Can't search in metadata for a method named Finalize, because that
5347 * ignores overrides.
5349 mono_class_setup_vtable (klass);
5350 if (mono_class_has_failure (klass))
5351 cmethod = NULL;
5352 else
5353 cmethod = m_class_get_vtable (klass) [mono_class_get_object_finalize_slot ()];
5356 if (cmethod) {
5357 g_assert (m_class_get_vtable_size (klass) > mono_class_get_object_finalize_slot ());
5359 if (m_class_get_parent (klass)) {
5360 if (cmethod->is_inflated)
5361 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5362 if (cmethod != mono_class_get_default_finalize_method ())
5363 has_finalize = TRUE;
5369 mono_loader_lock ();
5370 if (!m_class_is_has_finalize_inited (klass)) {
5371 klass->has_finalize = has_finalize ? 1 : 0;
5373 mono_memory_barrier ();
5374 klass->has_finalize_inited = TRUE;
5376 mono_loader_unlock ();
5380 * mono_class_setup_supertypes:
5381 * @class: a class
5383 * Build the data structure needed to make fast type checks work.
5384 * This currently sets two fields in @class:
5385 * - idepth: distance between @class and System.Object in the type
5386 * hierarchy + 1
5387 * - supertypes: array of classes: each element has a class in the hierarchy
5388 * starting from @class up to System.Object
5390 * LOCKING: Acquires the loader lock.
5392 void
5393 mono_class_setup_supertypes (MonoClass *klass)
5395 int ms, idepth;
5396 MonoClass **supertypes;
5398 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5399 if (supertypes)
5400 return;
5402 if (klass->parent && !klass->parent->supertypes)
5403 mono_class_setup_supertypes (klass->parent);
5404 if (klass->parent)
5405 idepth = klass->parent->idepth + 1;
5406 else
5407 idepth = 1;
5409 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5410 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5412 if (klass->parent) {
5413 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5415 int supertype_idx;
5416 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5417 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5418 } else {
5419 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5422 mono_memory_barrier ();
5424 mono_loader_lock ();
5425 klass->idepth = idepth;
5426 /* Needed so idepth is visible before supertypes is set */
5427 mono_memory_barrier ();
5428 klass->supertypes = supertypes;
5429 mono_loader_unlock ();
5432 /* mono_class_setup_nested_types:
5434 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5436 * LOCKING: Acquires the loader lock.
5438 void
5439 mono_class_setup_nested_types (MonoClass *klass)
5441 ERROR_DECL (error);
5442 GList *classes, *nested_classes, *l;
5443 int i;
5445 if (klass->nested_classes_inited)
5446 return;
5448 if (!klass->type_token) {
5449 mono_loader_lock ();
5450 klass->nested_classes_inited = TRUE;
5451 mono_loader_unlock ();
5452 return;
5455 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
5456 classes = NULL;
5457 while (i) {
5458 MonoClass* nclass;
5459 guint32 cols [MONO_NESTED_CLASS_SIZE];
5460 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
5461 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], error);
5462 if (!mono_error_ok (error)) {
5463 /*FIXME don't swallow the error message*/
5464 mono_error_cleanup (error);
5466 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5467 continue;
5470 classes = g_list_prepend (classes, nclass);
5472 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
5475 nested_classes = NULL;
5476 for (l = classes; l; l = l->next)
5477 nested_classes = mono_g_list_prepend_image (klass->image, nested_classes, l->data);
5478 g_list_free (classes);
5480 mono_loader_lock ();
5481 if (!klass->nested_classes_inited) {
5482 mono_class_set_nested_classes_property (klass, nested_classes);
5483 mono_memory_barrier ();
5484 klass->nested_classes_inited = TRUE;
5486 mono_loader_unlock ();
5490 * mono_class_setup_runtime_info:
5491 * \param klass the class to setup
5492 * \param domain the domain of the \p vtable
5493 * \param vtable
5495 * Store \p vtable in \c klass->runtime_info.
5497 * Sets the following field in MonoClass:
5498 * - runtime_info
5500 * LOCKING: domain lock and loaderlock must be held.
5502 void
5503 mono_class_setup_runtime_info (MonoClass *klass, MonoDomain *domain, MonoVTable *vtable)
5505 MonoClassRuntimeInfo *old_info = m_class_get_runtime_info (klass);
5506 if (old_info && old_info->max_domain >= domain->domain_id) {
5507 /* someone already created a large enough runtime info */
5508 old_info->domain_vtables [domain->domain_id] = vtable;
5509 } else {
5510 int new_size = domain->domain_id;
5511 if (old_info)
5512 new_size = MAX (new_size, old_info->max_domain);
5513 new_size++;
5514 /* make the new size a power of two */
5515 int i = 2;
5516 while (new_size > i)
5517 i <<= 1;
5518 new_size = i;
5519 /* this is a bounded memory retention issue: may want to
5520 * handle it differently when we'll have a rcu-like system.
5522 MonoClassRuntimeInfo *runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (m_class_get_image (klass), MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
5523 runtime_info->max_domain = new_size - 1;
5524 /* copy the stuff from the older info */
5525 if (old_info) {
5526 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
5528 runtime_info->domain_vtables [domain->domain_id] = vtable;
5529 /* keep this last*/
5530 mono_memory_barrier ();
5531 klass->runtime_info = runtime_info;
5536 * mono_class_create_array_fill_type:
5538 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5540 MonoClass *
5541 mono_class_create_array_fill_type (void)
5543 static MonoClass klass;
5544 static gboolean inited = FALSE;
5546 if (!inited) {
5547 klass.element_class = mono_defaults.int64_class;
5548 klass.rank = 1;
5549 klass.instance_size = MONO_SIZEOF_MONO_ARRAY;
5550 klass.sizes.element_size = 8;
5551 klass.size_inited = 1;
5552 klass.name = "array_filler_type";
5554 inited = TRUE;
5556 return &klass;
5560 * mono_classes_init:
5562 * Initialize the resources used by this module.
5563 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5565 MONO_NO_SANITIZE_THREAD
5566 void
5567 mono_classes_init (void)
5569 mono_os_mutex_init (&classes_mutex);
5571 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
5572 mono_native_tls_alloc (&init_pending_tls_id, NULL);
5574 mono_counters_register ("MonoClassDef count",
5575 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
5576 mono_counters_register ("MonoClassGtd count",
5577 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
5578 mono_counters_register ("MonoClassGenericInst count",
5579 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
5580 mono_counters_register ("MonoClassGenericParam count",
5581 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
5582 mono_counters_register ("MonoClassArray count",
5583 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
5584 mono_counters_register ("MonoClassPointer count",
5585 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
5586 mono_counters_register ("Inflated methods size",
5587 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &mono_inflated_methods_size);
5588 mono_counters_register ("Inflated classes size",
5589 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
5590 mono_counters_register ("MonoClass size",
5591 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
5595 * mono_classes_cleanup:
5597 * Free the resources used by this module.
5599 void
5600 mono_classes_cleanup (void)
5602 mono_native_tls_free (setup_fields_tls_id);
5603 mono_native_tls_free (init_pending_tls_id);
5605 if (global_interface_bitset)
5606 mono_bitset_free (global_interface_bitset);
5607 global_interface_bitset = NULL;
5608 mono_os_mutex_destroy (&classes_mutex);