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.
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
37 gboolean mono_print_vtable
= FALSE
;
38 gboolean mono_align_small_structs
= FALSE
;
41 gint32 mono_simd_register_size
;
45 static gint32 classes_size
;
46 static gint32 inflated_classes_size
;
47 gint32 mono_inflated_methods_size
;
48 static gint32 class_def_count
, class_gtd_count
, class_ginst_count
, class_gparam_count
, class_array_count
, class_pointer_count
;
50 /* Low level lock which protects data structures in this module */
51 static mono_mutex_t classes_mutex
;
53 static gboolean
class_kind_may_contain_generic_instances (MonoTypeKind kind
);
54 static int setup_interface_offsets (MonoClass
*klass
, int cur_slot
, gboolean overwrite
);
55 static void mono_class_setup_vtable_full (MonoClass
*klass
, GList
*in_setup
);
56 static void mono_generic_class_setup_parent (MonoClass
*klass
, MonoClass
*gtd
);
57 static int generic_array_methods (MonoClass
*klass
);
58 static void setup_generic_array_ifaces (MonoClass
*klass
, MonoClass
*iface
, MonoMethod
**methods
, int pos
, GHashTable
*cache
);
59 static gboolean
class_has_isbyreflike_attribute (MonoClass
*klass
);
60 static void mono_class_setup_interface_id_internal (MonoClass
*klass
);
62 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
63 static MonoNativeTlsKey setup_fields_tls_id
;
65 static MonoNativeTlsKey init_pending_tls_id
;
70 mono_locks_os_acquire (&classes_mutex
, ClassesLock
);
76 mono_locks_os_release (&classes_mutex
, ClassesLock
);
80 We use gclass recording to allow recursive system f types to be referenced by a parent.
82 Given the following type hierarchy:
84 class TextBox : TextBoxBase<TextBox> {}
85 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
86 class TextInput<T> : Input<T> where T: TextInput<T> {}
89 The runtime tries to load TextBoxBase<>.
90 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
91 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
92 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
94 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
95 at this point, iow, both are registered in the type map and both and a NULL parent. This means
96 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
98 To fix that what we do is to record all generic instantes created while resolving the parent of
99 any generic type definition and, after resolved, correct the parent field if needed.
102 static int record_gclass_instantiation
;
103 static GSList
*gclass_recorded_list
;
104 typedef gboolean (*gclass_record_func
) (MonoClass
*, void*);
107 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
110 enable_gclass_recording (void)
112 ++record_gclass_instantiation
;
116 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
119 disable_gclass_recording (gclass_record_func func
, void *user_data
)
121 GSList
**head
= &gclass_recorded_list
;
123 g_assert (record_gclass_instantiation
> 0);
124 --record_gclass_instantiation
;
127 GSList
*node
= *head
;
128 if (func ((MonoClass
*)node
->data
, user_data
)) {
130 g_slist_free_1 (node
);
136 /* We automatically discard all recorded gclasses when disabled. */
137 if (!record_gclass_instantiation
&& gclass_recorded_list
) {
138 g_slist_free (gclass_recorded_list
);
139 gclass_recorded_list
= NULL
;
143 #define mono_class_new0(klass,struct_type, n_structs) \
144 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
147 * mono_class_setup_basic_field_info:
148 * \param class The class to initialize
150 * Initializes the following fields in MonoClass:
151 * * klass->fields (only field->parent and field->name)
152 * * klass->field.count
153 * * klass->first_field_idx
154 * LOCKING: Acquires the loader lock
157 mono_class_setup_basic_field_info (MonoClass
*klass
)
159 MonoGenericClass
*gklass
;
160 MonoClassField
*field
;
161 MonoClassField
*fields
;
169 gklass
= mono_class_try_get_generic_class (klass
);
170 gtd
= gklass
? mono_class_get_generic_type_definition (klass
) : NULL
;
171 image
= klass
->image
;
174 if (gklass
&& image_is_dynamic (gklass
->container_class
->image
) && !gklass
->container_class
->wastypebuilder
) {
176 * This happens when a generic instance of an unfinished generic typebuilder
177 * is used as an element type for creating an array type. We can't initialize
178 * the fields of this class using the fields of gklass, since gklass is not
179 * finished yet, fields could be added to it later.
185 mono_class_setup_basic_field_info (gtd
);
188 mono_class_set_field_count (klass
, mono_class_get_field_count (gtd
));
189 mono_loader_unlock ();
192 top
= mono_class_get_field_count (klass
);
194 fields
= (MonoClassField
*)mono_class_alloc0 (klass
, sizeof (MonoClassField
) * top
);
197 * Fetch all the field information.
199 int first_field_idx
= mono_class_has_static_metadata (klass
) ? mono_class_get_first_field_idx (klass
) : 0;
200 for (i
= 0; i
< top
; i
++) {
202 field
->parent
= klass
;
205 field
->name
= mono_field_get_name (>d
->fields
[i
]);
207 int idx
= first_field_idx
+ i
;
208 /* first_field_idx and idx points into the fieldptr table */
209 guint32 name_idx
= mono_metadata_decode_table_row_col (image
, MONO_TABLE_FIELD
, idx
, MONO_FIELD_NAME
);
210 /* The name is needed for fieldrefs */
211 field
->name
= mono_metadata_string_heap (image
, name_idx
);
215 mono_memory_barrier ();
219 klass
->fields
= fields
;
220 mono_loader_unlock ();
224 * mono_class_setup_fields:
225 * \p klass The class to initialize
227 * Initializes klass->fields, computes class layout and sizes.
228 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
229 * Sets the following fields in \p klass:
230 * - all the fields initialized by mono_class_init_sizes ()
231 * - element_class/cast_class (for enums)
232 * - sizes:element_size (for arrays)
233 * - field->type/offset for all fields
236 * LOCKING: Acquires the loader lock.
239 mono_class_setup_fields (MonoClass
*klass
)
242 MonoImage
*m
= klass
->image
;
244 guint32 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
246 guint32 real_size
= 0;
247 guint32 packing_size
= 0;
249 gboolean explicit_size
;
250 MonoClassField
*field
;
251 MonoGenericClass
*gklass
= mono_class_try_get_generic_class (klass
);
252 MonoClass
*gtd
= gklass
? mono_class_get_generic_type_definition (klass
) : NULL
;
254 if (klass
->fields_inited
)
257 if (gklass
&& image_is_dynamic (gklass
->container_class
->image
) && !gklass
->container_class
->wastypebuilder
) {
259 * This happens when a generic instance of an unfinished generic typebuilder
260 * is used as an element type for creating an array type. We can't initialize
261 * the fields of this class using the fields of gklass, since gklass is not
262 * finished yet, fields could be added to it later.
267 mono_class_setup_basic_field_info (klass
);
268 top
= mono_class_get_field_count (klass
);
271 mono_class_setup_fields (gtd
);
272 if (mono_class_set_type_load_failure_causedby_class (klass
, gtd
, "Generic type definition failed"))
278 /* For generic instances, klass->parent might not have been initialized */
279 mono_class_init_internal (klass
->parent
);
280 mono_class_setup_fields (klass
->parent
);
281 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Could not set up parent class"))
283 instance_size
= klass
->parent
->instance_size
;
285 instance_size
= MONO_ABI_SIZEOF (MonoObject
);
288 /* Get the real size */
289 explicit_size
= mono_metadata_packing_from_typedef (klass
->image
, klass
->type_token
, &packing_size
, &real_size
);
291 instance_size
+= real_size
;
293 #ifdef ENABLE_NETCORE
294 if (mono_is_corlib_image (klass
->image
) && !strcmp (klass
->name_space
, "System.Numerics") && !strcmp (klass
->name
, "Register")) {
295 if (mono_simd_register_size
)
296 instance_size
+= mono_simd_register_size
;
301 * This function can recursively call itself.
302 * Prevent infinite recursion by using a list in TLS.
304 GSList
*init_list
= (GSList
*)mono_native_tls_get_value (setup_fields_tls_id
);
305 if (g_slist_find (init_list
, klass
))
307 init_list
= g_slist_prepend (init_list
, klass
);
308 mono_native_tls_set_value (setup_fields_tls_id
, init_list
);
311 * Fetch all the field information.
313 int first_field_idx
= mono_class_has_static_metadata (klass
) ? mono_class_get_first_field_idx (klass
) : 0;
314 for (i
= 0; i
< top
; i
++) {
315 int idx
= first_field_idx
+ i
;
316 field
= &klass
->fields
[i
];
319 mono_field_resolve_type (field
, error
);
320 if (!is_ok (error
)) {
321 /*mono_field_resolve_type already failed class*/
322 mono_error_cleanup (error
);
326 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass
), field
->name
);
327 g_assert (field
->type
);
330 if (!mono_type_get_underlying_type (field
->type
)) {
331 mono_class_set_type_load_failure (klass
, "Field '%s' is an enum type with a bad underlying type", field
->name
);
335 if (mono_field_is_deleted (field
))
337 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
339 mono_metadata_field_info (m
, idx
, &uoffset
, NULL
, NULL
);
340 int offset
= uoffset
;
342 if (offset
== (guint32
)-1 && !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
343 mono_class_set_type_load_failure (klass
, "Missing field layout info for %s", field
->name
);
346 if (offset
< -1) { /*-1 is used to encode special static fields */
347 mono_class_set_type_load_failure (klass
, "Field '%s' has a negative offset %d", field
->name
, offset
);
350 if (mono_class_is_gtd (klass
)) {
351 mono_class_set_type_load_failure (klass
, "Generic class cannot have explicit layout.");
355 if (mono_type_has_exceptions (field
->type
)) {
356 char *class_name
= mono_type_get_full_name (klass
);
357 char *type_name
= mono_type_full_name (field
->type
);
359 mono_class_set_type_load_failure (klass
, "Invalid type %s for instance field %s:%s", type_name
, class_name
, field
->name
);
364 /* The def_value of fields is compute lazily during vtable creation */
367 if (!mono_class_has_failure (klass
)) {
369 mono_class_layout_fields (klass
, instance_size
, packing_size
, real_size
, FALSE
);
370 mono_loader_unlock ();
373 init_list
= g_slist_remove (init_list
, klass
);
374 mono_native_tls_set_value (setup_fields_tls_id
, init_list
);
378 discard_gclass_due_to_failure (MonoClass
*gclass
, void *user_data
)
380 return mono_class_get_generic_class (gclass
)->container_class
== user_data
;
384 fix_gclass_incomplete_instantiation (MonoClass
*gclass
, void *user_data
)
386 MonoClass
*gtd
= (MonoClass
*)user_data
;
387 /* Only try to fix generic instances of @gtd */
388 if (mono_class_get_generic_class (gclass
)->container_class
!= gtd
)
391 /* Check if the generic instance has no parent. */
392 if (gtd
->parent
&& !gclass
->parent
)
393 mono_generic_class_setup_parent (gclass
, gtd
);
399 mono_class_set_failure_and_error (MonoClass
*klass
, MonoError
*error
, const char *msg
)
401 mono_class_set_type_load_failure (klass
, "%s", msg
);
402 mono_error_set_type_load_class (error
, klass
, "%s", msg
);
406 * mono_class_create_from_typedef:
407 * \param image: image where the token is valid
408 * \param type_token: typedef token
409 * \param error: used to return any error found while creating the type
411 * Create the MonoClass* representing the specified type token.
412 * \p type_token must be a TypeDef token.
414 * FIXME: don't return NULL on failure, just let the caller figure it out.
417 mono_class_create_from_typedef (MonoImage
*image
, guint32 type_token
, MonoError
*error
)
419 MonoTableInfo
*tt
= &image
->tables
[MONO_TABLE_TYPEDEF
];
420 MonoClass
*klass
, *parent
= NULL
;
421 guint32 cols
[MONO_TYPEDEF_SIZE
];
422 guint32 cols_next
[MONO_TYPEDEF_SIZE
];
423 guint tidx
= mono_metadata_token_index (type_token
);
424 MonoGenericContext
*context
= NULL
;
425 const char *name
, *nspace
;
427 MonoClass
**interfaces
;
428 guint32 field_last
, method_last
;
429 guint32 nesting_tokeen
;
433 if (mono_metadata_token_table (type_token
) != MONO_TABLE_TYPEDEF
|| tidx
> tt
->rows
) {
434 mono_error_set_bad_image (error
, image
, "Invalid typedef token %x", type_token
);
440 if ((klass
= (MonoClass
*)mono_internal_hash_table_lookup (&image
->class_cache
, GUINT_TO_POINTER (type_token
)))) {
441 mono_loader_unlock ();
445 mono_metadata_decode_row (tt
, tidx
- 1, cols
, MONO_TYPEDEF_SIZE
);
447 name
= mono_metadata_string_heap (image
, cols
[MONO_TYPEDEF_NAME
]);
448 nspace
= mono_metadata_string_heap (image
, cols
[MONO_TYPEDEF_NAMESPACE
]);
450 if (mono_metadata_has_generic_params (image
, type_token
)) {
451 klass
= (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassGtd
));
452 klass
->class_kind
= MONO_CLASS_GTD
;
453 UnlockedAdd (&classes_size
, sizeof (MonoClassGtd
));
456 klass
= (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassDef
));
457 klass
->class_kind
= MONO_CLASS_DEF
;
458 UnlockedAdd (&classes_size
, sizeof (MonoClassDef
));
463 klass
->name_space
= nspace
;
465 MONO_PROFILER_RAISE (class_loading
, (klass
));
467 klass
->image
= image
;
468 klass
->type_token
= type_token
;
469 mono_class_set_flags (klass
, cols
[MONO_TYPEDEF_FLAGS
]);
471 mono_internal_hash_table_insert (&image
->class_cache
, GUINT_TO_POINTER (type_token
), klass
);
474 * Check whether we're a generic type definition.
476 if (mono_class_is_gtd (klass
)) {
477 MonoGenericContainer
*generic_container
= mono_metadata_load_generic_params (image
, klass
->type_token
, NULL
, klass
);
478 context
= &generic_container
->context
;
479 mono_class_set_generic_container (klass
, generic_container
);
480 MonoType
*canonical_inst
= &((MonoClassGtd
*)klass
)->canonical_inst
;
481 canonical_inst
->type
= MONO_TYPE_GENERICINST
;
482 canonical_inst
->data
.generic_class
= mono_metadata_lookup_generic_class (klass
, context
->class_inst
, FALSE
);
483 enable_gclass_recording ();
486 if (cols
[MONO_TYPEDEF_EXTENDS
]) {
488 guint32 parent_token
= mono_metadata_token_from_dor (cols
[MONO_TYPEDEF_EXTENDS
]);
490 if (mono_metadata_token_table (parent_token
) == MONO_TABLE_TYPESPEC
) {
491 /*WARNING: this must satisfy mono_metadata_type_hash*/
492 klass
->this_arg
.byref
= 1;
493 klass
->this_arg
.data
.klass
= klass
;
494 klass
->this_arg
.type
= MONO_TYPE_CLASS
;
495 klass
->_byval_arg
.data
.klass
= klass
;
496 klass
->_byval_arg
.type
= MONO_TYPE_CLASS
;
498 parent
= mono_class_get_checked (image
, parent_token
, error
);
499 if (parent
&& context
) /* Always inflate */
500 parent
= mono_class_inflate_generic_class_checked (parent
, context
, error
);
502 if (parent
== NULL
) {
503 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
507 for (tmp
= parent
; tmp
; tmp
= tmp
->parent
) {
509 mono_class_set_failure_and_error (klass
, error
, "Cycle found while resolving parent");
512 if (mono_class_is_gtd (klass
) && mono_class_is_ginst (tmp
) && mono_class_get_generic_class (tmp
)->container_class
== klass
) {
513 mono_class_set_failure_and_error (klass
, error
, "Parent extends generic instance of this type");
519 mono_class_setup_parent (klass
, parent
);
521 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
522 mono_class_setup_mono_type (klass
);
524 if (mono_class_is_gtd (klass
))
525 disable_gclass_recording (fix_gclass_incomplete_instantiation
, klass
);
528 * This might access klass->_byval_arg for recursion generated by generic constraints,
529 * so it has to come after setup_mono_type ().
531 if ((nesting_tokeen
= mono_metadata_nested_in_typedef (image
, type_token
))) {
532 klass
->nested_in
= mono_class_create_from_typedef (image
, nesting_tokeen
, error
);
533 if (!is_ok (error
)) {
534 /*FIXME implement a mono_class_set_failure_from_mono_error */
535 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
536 mono_loader_unlock ();
537 MONO_PROFILER_RAISE (class_failed
, (klass
));
542 if ((mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK
) == TYPE_ATTRIBUTE_UNICODE_CLASS
)
546 if ((mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK
) == TYPE_ATTRIBUTE_AUTO_CLASS
)
550 klass
->cast_class
= klass
->element_class
= klass
;
551 if (mono_is_corlib_image (klass
->image
)) {
552 switch (m_class_get_byval_arg (klass
)->type
) {
554 if (mono_defaults
.byte_class
)
555 klass
->cast_class
= mono_defaults
.byte_class
;
558 if (mono_defaults
.sbyte_class
)
559 mono_defaults
.sbyte_class
= klass
;
562 if (mono_defaults
.uint16_class
)
563 mono_defaults
.uint16_class
= klass
;
566 if (mono_defaults
.int16_class
)
567 klass
->cast_class
= mono_defaults
.int16_class
;
570 if (mono_defaults
.uint32_class
)
571 mono_defaults
.uint32_class
= klass
;
574 if (mono_defaults
.int32_class
)
575 klass
->cast_class
= mono_defaults
.int32_class
;
578 if (mono_defaults
.uint64_class
)
579 mono_defaults
.uint64_class
= klass
;
582 if (mono_defaults
.int64_class
)
583 klass
->cast_class
= mono_defaults
.int64_class
;
590 if (!klass
->enumtype
) {
591 if (!mono_metadata_interfaces_from_typedef_full (
592 image
, type_token
, &interfaces
, &icount
, FALSE
, context
, error
)){
594 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
595 mono_loader_unlock ();
596 MONO_PROFILER_RAISE (class_failed
, (klass
));
600 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
601 g_assert(icount
<= 65535);
603 klass
->interfaces
= interfaces
;
604 klass
->interface_count
= icount
;
605 klass
->interfaces_inited
= 1;
608 /*g_print ("Load class %s\n", name);*/
611 * Compute the field and method lists
614 first_field_idx
= cols
[MONO_TYPEDEF_FIELD_LIST
] - 1;
615 mono_class_set_first_field_idx (klass
, first_field_idx
);
616 int first_method_idx
;
617 first_method_idx
= cols
[MONO_TYPEDEF_METHOD_LIST
] - 1;
618 mono_class_set_first_method_idx (klass
, first_method_idx
);
620 if (tt
->rows
> tidx
){
621 mono_metadata_decode_row (tt
, tidx
, cols_next
, MONO_TYPEDEF_SIZE
);
622 field_last
= cols_next
[MONO_TYPEDEF_FIELD_LIST
] - 1;
623 method_last
= cols_next
[MONO_TYPEDEF_METHOD_LIST
] - 1;
625 field_last
= image
->tables
[MONO_TABLE_FIELD
].rows
;
626 method_last
= image
->tables
[MONO_TABLE_METHOD
].rows
;
629 if (cols
[MONO_TYPEDEF_FIELD_LIST
] &&
630 cols
[MONO_TYPEDEF_FIELD_LIST
] <= image
->tables
[MONO_TABLE_FIELD
].rows
)
631 mono_class_set_field_count (klass
, field_last
- first_field_idx
);
632 if (cols
[MONO_TYPEDEF_METHOD_LIST
] <= image
->tables
[MONO_TABLE_METHOD
].rows
)
633 mono_class_set_method_count (klass
, method_last
- first_method_idx
);
635 /* reserve space to store vector pointer in arrays */
636 if (mono_is_corlib_image (image
) && !strcmp (nspace
, "System") && !strcmp (name
, "Array")) {
637 klass
->instance_size
+= 2 * TARGET_SIZEOF_VOID_P
;
638 #ifndef ENABLE_NETCORE
639 g_assert (mono_class_get_field_count (klass
) == 0);
641 /* TODO: check that array has 0 non-const fields */
645 if (klass
->enumtype
) {
646 MonoType
*enum_basetype
= mono_class_find_enum_basetype (klass
, error
);
647 if (!enum_basetype
) {
648 /*set it to a default value as the whole runtime can't handle this to be null*/
649 klass
->cast_class
= klass
->element_class
= mono_defaults
.int32_class
;
650 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
651 mono_loader_unlock ();
652 MONO_PROFILER_RAISE (class_failed
, (klass
));
655 klass
->cast_class
= klass
->element_class
= mono_class_from_mono_type_internal (enum_basetype
);
659 * If we're a generic type definition, load the constraints.
660 * We must do this after the class has been constructed to make certain recursive scenarios
663 if (mono_class_is_gtd (klass
) && !mono_metadata_load_generic_param_constraints_checked (image
, type_token
, mono_class_get_generic_container (klass
), error
)) {
664 mono_class_set_type_load_failure (klass
, "Could not load generic parameter constrains due to %s", mono_error_get_message (error
));
665 mono_loader_unlock ();
666 MONO_PROFILER_RAISE (class_failed
, (klass
));
670 if (klass
->image
->assembly_name
&& !strcmp (klass
->image
->assembly_name
, "Mono.Simd") && !strcmp (nspace
, "Mono.Simd")) {
671 if (!strncmp (name
, "Vector", 6))
672 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");
673 } else if (klass
->image
->assembly_name
&& !strcmp (klass
->image
->assembly_name
, "System.Numerics") && !strcmp (nspace
, "System.Numerics")) {
674 /* The JIT can't handle SIMD types with != 16 size yet */
675 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
676 if (!strcmp (name
, "Vector4"))
677 klass
->simd_type
= 1;
680 // compute is_byreflike
681 if (m_class_is_valuetype (klass
))
682 if (class_has_isbyreflike_attribute (klass
))
683 klass
->is_byreflike
= 1;
685 mono_loader_unlock ();
687 MONO_PROFILER_RAISE (class_loaded
, (klass
));
692 if (mono_class_is_gtd (klass
))
693 disable_gclass_recording (discard_gclass_due_to_failure
, klass
);
695 mono_class_setup_mono_type (klass
);
696 mono_loader_unlock ();
697 MONO_PROFILER_RAISE (class_failed
, (klass
));
703 mono_generic_class_setup_parent (MonoClass
*klass
, MonoClass
*gtd
)
707 MonoGenericClass
*gclass
= mono_class_get_generic_class (klass
);
709 klass
->parent
= mono_class_inflate_generic_class_checked (gtd
->parent
, mono_generic_class_get_context (gclass
), error
);
710 if (!is_ok (error
)) {
711 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
712 klass
->parent
= mono_defaults
.object_class
;
713 mono_class_set_type_load_failure (klass
, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error
));
714 mono_error_cleanup (error
);
719 mono_class_setup_parent (klass
, klass
->parent
);
721 if (klass
->enumtype
) {
722 klass
->cast_class
= gtd
->cast_class
;
723 klass
->element_class
= gtd
->element_class
;
725 mono_loader_unlock ();
728 struct HasIsByrefLikeUD
{
729 gboolean has_isbyreflike
;
733 has_isbyreflike_attribute_func (MonoImage
*image
, guint32 typeref_scope_token
, const char *nspace
, const char *name
, guint32 method_token
, gpointer user_data
)
735 struct HasIsByrefLikeUD
*has_isbyreflike
= (struct HasIsByrefLikeUD
*)user_data
;
736 if (!strcmp (name
, "IsByRefLikeAttribute") && !strcmp (nspace
, "System.Runtime.CompilerServices")) {
737 has_isbyreflike
->has_isbyreflike
= TRUE
;
744 class_has_isbyreflike_attribute (MonoClass
*klass
)
746 struct HasIsByrefLikeUD has_isbyreflike
;
747 has_isbyreflike
.has_isbyreflike
= FALSE
;
748 mono_class_metadata_foreach_custom_attr (klass
, has_isbyreflike_attribute_func
, &has_isbyreflike
);
749 return has_isbyreflike
.has_isbyreflike
;
754 check_valid_generic_inst_arguments (MonoGenericInst
*inst
, MonoError
*error
)
756 for (int i
= 0; i
< inst
->type_argc
; i
++) {
757 if (!mono_type_is_valid_generic_argument (inst
->type_argv
[i
])) {
758 char *type_name
= mono_type_full_name (inst
->type_argv
[i
]);
759 mono_error_set_invalid_program (error
, "generic type cannot be instantiated with type '%s'", type_name
);
768 * Create the `MonoClass' for an instantiation of a generic type.
769 * We only do this if we actually need it.
770 * This will sometimes return a GTD due to checking the cached_class.
773 mono_class_create_generic_inst (MonoGenericClass
*gclass
)
775 MonoClass
*klass
, *gklass
;
777 if (gclass
->cached_class
)
778 return gclass
->cached_class
;
780 klass
= (MonoClass
*)mono_image_set_alloc0 (gclass
->owner
, sizeof (MonoClassGenericInst
));
782 gklass
= gclass
->container_class
;
784 if (gklass
->nested_in
) {
785 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
786 klass
->nested_in
= gklass
->nested_in
;
789 klass
->name
= gklass
->name
;
790 klass
->name_space
= gklass
->name_space
;
792 klass
->image
= gklass
->image
;
793 klass
->type_token
= gklass
->type_token
;
795 klass
->class_kind
= MONO_CLASS_GINST
;
797 ((MonoClassGenericInst
*)klass
)->generic_class
= gclass
;
799 klass
->_byval_arg
.type
= MONO_TYPE_GENERICINST
;
800 klass
->this_arg
.type
= m_class_get_byval_arg (klass
)->type
;
801 klass
->this_arg
.data
.generic_class
= klass
->_byval_arg
.data
.generic_class
= gclass
;
802 klass
->this_arg
.byref
= TRUE
;
803 klass
->enumtype
= gklass
->enumtype
;
804 klass
->valuetype
= gklass
->valuetype
;
807 if (gklass
->image
->assembly_name
&& !strcmp (gklass
->image
->assembly_name
, "System.Numerics.Vectors") && !strcmp (gklass
->name_space
, "System.Numerics") && !strcmp (gklass
->name
, "Vector`1")) {
808 g_assert (gclass
->context
.class_inst
);
809 g_assert (gclass
->context
.class_inst
->type_argc
> 0);
810 if (mono_type_is_primitive (gclass
->context
.class_inst
->type_argv
[0]))
811 klass
->simd_type
= 1;
813 #ifdef ENABLE_NETCORE
814 if (mono_is_corlib_image (gklass
->image
) &&
815 (!strcmp (gklass
->name
, "Vector`1") || !strcmp (gklass
->name
, "Vector128`1") || !strcmp (gklass
->name
, "Vector256`1"))) {
816 MonoType
*etype
= gclass
->context
.class_inst
->type_argv
[0];
817 if (mono_type_is_primitive (etype
) && etype
->type
!= MONO_TYPE_CHAR
&& etype
->type
!= MONO_TYPE_BOOLEAN
)
818 klass
->simd_type
= 1;
822 klass
->is_array_special_interface
= gklass
->is_array_special_interface
;
824 klass
->cast_class
= klass
->element_class
= klass
;
826 if (m_class_is_valuetype (klass
)) {
827 klass
->is_byreflike
= gklass
->is_byreflike
;
830 if (gclass
->is_dynamic
) {
832 * 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.
833 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
834 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
836 if (!gklass
->wastypebuilder
)
839 if (klass
->enumtype
) {
841 * For enums, gklass->fields might not been set, but instance_size etc. is
842 * already set in mono_reflection_create_internal_class (). For non-enums,
843 * these will be computed normally in mono_class_layout_fields ().
845 klass
->instance_size
= gklass
->instance_size
;
846 klass
->sizes
.class_size
= gklass
->sizes
.class_size
;
847 klass
->size_inited
= 1;
852 ERROR_DECL (error_inst
);
853 if (!check_valid_generic_inst_arguments (gclass
->context
.class_inst
, error_inst
)) {
854 char *gklass_name
= mono_type_get_full_name (gklass
);
855 mono_class_set_type_load_failure (klass
, "Could not instantiate %s due to %s", gklass_name
, mono_error_get_message (error_inst
));
856 g_free (gklass_name
);
857 mono_error_cleanup (error_inst
);
863 if (gclass
->cached_class
) {
864 mono_loader_unlock ();
865 return gclass
->cached_class
;
868 if (record_gclass_instantiation
> 0)
869 gclass_recorded_list
= g_slist_append (gclass_recorded_list
, klass
);
871 if (mono_class_is_nullable (klass
))
872 klass
->cast_class
= klass
->element_class
= mono_class_get_nullable_param_internal (klass
);
874 MONO_PROFILER_RAISE (class_loading
, (klass
));
876 mono_generic_class_setup_parent (klass
, gklass
);
878 if (gclass
->is_dynamic
)
879 mono_class_setup_supertypes (klass
);
881 mono_memory_barrier ();
882 gclass
->cached_class
= klass
;
884 MONO_PROFILER_RAISE (class_loaded
, (klass
));
887 inflated_classes_size
+= sizeof (MonoClassGenericInst
);
889 mono_loader_unlock ();
895 class_kind_may_contain_generic_instances (MonoTypeKind kind
)
897 /* classes of type generic inst may contain generic arguments from other images,
898 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
899 return (kind
== MONO_CLASS_GINST
|| kind
== MONO_CLASS_ARRAY
|| kind
== MONO_CLASS_POINTER
);
903 * mono_class_create_bounded_array:
904 * \param element_class element class
905 * \param rank the dimension of the array class
906 * \param bounded whenever the array has non-zero bounds
907 * \returns A class object describing the array with element type \p element_type and
911 mono_class_create_bounded_array (MonoClass
*eclass
, guint32 rank
, gboolean bounded
)
914 MonoClass
*klass
, *cached
, *k
;
915 MonoClass
*parent
= NULL
;
916 GSList
*list
, *rootlist
= NULL
;
919 MonoImageSet
* image_set
;
921 g_assert (rank
<= 255);
924 /* bounded only matters for one-dimensional arrays */
927 image
= eclass
->image
;
928 image_set
= class_kind_may_contain_generic_instances ((MonoTypeKind
)eclass
->class_kind
) ? mono_metadata_get_image_set_for_class (eclass
) : NULL
;
932 if (rank
== 1 && !bounded
) {
934 mono_image_set_lock (image_set
);
935 cached
= (MonoClass
*)g_hash_table_lookup (image_set
->szarray_cache
, eclass
);
936 mono_image_set_unlock (image_set
);
939 * This case is very frequent not just during compilation because of calls
940 * from mono_class_from_mono_type_internal (), mono_array_new (),
941 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
943 mono_os_mutex_lock (&image
->szarray_cache_lock
);
944 if (!image
->szarray_cache
)
945 image
->szarray_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
946 cached
= (MonoClass
*)g_hash_table_lookup (image
->szarray_cache
, eclass
);
947 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
951 mono_image_set_lock (image_set
);
952 rootlist
= (GSList
*)g_hash_table_lookup (image_set
->array_cache
, eclass
);
953 for (list
= rootlist
; list
; list
= list
->next
) {
954 k
= (MonoClass
*)list
->data
;
955 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
960 mono_image_set_unlock (image_set
);
963 if (!image
->array_cache
)
964 image
->array_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
965 rootlist
= (GSList
*)g_hash_table_lookup (image
->array_cache
, eclass
);
966 for (list
= rootlist
; list
; list
= list
->next
) {
967 k
= (MonoClass
*)list
->data
;
968 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
973 mono_loader_unlock ();
979 parent
= mono_defaults
.array_class
;
981 mono_class_init_internal (parent
);
983 klass
= image_set
? (MonoClass
*)mono_image_set_alloc0 (image_set
, sizeof (MonoClassArray
)) : (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassArray
));
985 klass
->image
= image
;
986 klass
->name_space
= eclass
->name_space
;
987 klass
->class_kind
= MONO_CLASS_ARRAY
;
989 nsize
= strlen (eclass
->name
);
990 name
= (char *)g_malloc (nsize
+ 2 + rank
+ 1);
991 memcpy (name
, eclass
->name
, nsize
);
994 memset (name
+ nsize
+ 1, ',', rank
- 1);
996 name
[nsize
+ rank
] = '*';
997 name
[nsize
+ rank
+ bounded
] = ']';
998 name
[nsize
+ rank
+ bounded
+ 1] = 0;
999 klass
->name
= image_set
? mono_image_set_strdup (image_set
, name
) : mono_image_strdup (image
, name
);
1002 klass
->type_token
= 0;
1003 klass
->parent
= parent
;
1004 klass
->instance_size
= mono_class_instance_size (klass
->parent
);
1006 if (m_class_get_byval_arg (eclass
)->type
== MONO_TYPE_TYPEDBYREF
) {
1007 /*Arrays of those two types are invalid.*/
1008 ERROR_DECL (prepared_error
);
1009 mono_error_set_invalid_program (prepared_error
, "Arrays of System.TypedReference types are invalid.");
1010 mono_class_set_failure (klass
, mono_error_box (prepared_error
, klass
->image
));
1011 mono_error_cleanup (prepared_error
);
1012 } else if (m_class_is_byreflike (eclass
)) {
1013 /* .NET Core throws a type load exception: "Could not create array type 'fullname[]'" */
1014 char *full_name
= mono_type_get_full_name (eclass
);
1015 mono_class_set_type_load_failure (klass
, "Could not create array type '%s[]'", full_name
);
1017 } else if (eclass
->enumtype
&& !mono_class_enum_basetype_internal (eclass
)) {
1018 guint32 ref_info_handle
= mono_class_get_ref_info_handle (eclass
);
1019 if (!ref_info_handle
|| eclass
->wastypebuilder
) {
1020 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
1021 g_assert (ref_info_handle
&& !eclass
->wastypebuilder
);
1023 /* element_size -1 is ok as this is not an instantitable type*/
1024 klass
->sizes
.element_size
= -1;
1026 klass
->sizes
.element_size
= -1;
1028 mono_class_setup_supertypes (klass
);
1030 if (mono_class_is_ginst (eclass
))
1031 mono_class_init_internal (eclass
);
1032 if (!eclass
->size_inited
)
1033 mono_class_setup_fields (eclass
);
1034 mono_class_set_type_load_failure_causedby_class (klass
, eclass
, "Could not load array element type");
1035 /*FIXME we fail the array type, but we have to let other fields be set.*/
1037 klass
->has_references
= MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (eclass
)) || m_class_has_references (eclass
)? TRUE
: FALSE
;
1041 if (eclass
->enumtype
)
1042 klass
->cast_class
= eclass
->element_class
;
1044 klass
->cast_class
= eclass
;
1046 switch (m_class_get_byval_arg (m_class_get_cast_class (klass
))->type
) {
1048 klass
->cast_class
= mono_defaults
.byte_class
;
1051 klass
->cast_class
= mono_defaults
.int16_class
;
1054 #if TARGET_SIZEOF_VOID_P == 4
1058 klass
->cast_class
= mono_defaults
.int32_class
;
1061 #if TARGET_SIZEOF_VOID_P == 8
1065 klass
->cast_class
= mono_defaults
.int64_class
;
1071 klass
->element_class
= eclass
;
1073 if ((rank
> 1) || bounded
) {
1074 MonoArrayType
*at
= image_set
? (MonoArrayType
*)mono_image_set_alloc0 (image_set
, sizeof (MonoArrayType
)) : (MonoArrayType
*)mono_image_alloc0 (image
, sizeof (MonoArrayType
));
1075 klass
->_byval_arg
.type
= MONO_TYPE_ARRAY
;
1076 klass
->_byval_arg
.data
.array
= at
;
1077 at
->eklass
= eclass
;
1079 /* FIXME: complete.... */
1081 klass
->_byval_arg
.type
= MONO_TYPE_SZARRAY
;
1082 klass
->_byval_arg
.data
.klass
= eclass
;
1084 klass
->this_arg
= klass
->_byval_arg
;
1085 klass
->this_arg
.byref
= 1;
1088 ERROR_DECL (prepared_error
);
1089 name
= mono_type_get_full_name (klass
);
1090 mono_error_set_type_load_class (prepared_error
, klass
, "%s has too many dimensions.", name
);
1091 mono_class_set_failure (klass
, mono_error_box (prepared_error
, klass
->image
));
1092 mono_error_cleanup (prepared_error
);
1096 mono_loader_lock ();
1098 /* Check cache again */
1100 if (rank
== 1 && !bounded
) {
1102 mono_image_set_lock (image_set
);
1103 cached
= (MonoClass
*)g_hash_table_lookup (image_set
->szarray_cache
, eclass
);
1104 mono_image_set_unlock (image_set
);
1106 mono_os_mutex_lock (&image
->szarray_cache_lock
);
1107 cached
= (MonoClass
*)g_hash_table_lookup (image
->szarray_cache
, eclass
);
1108 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
1112 mono_image_set_lock (image_set
);
1113 rootlist
= (GSList
*)g_hash_table_lookup (image_set
->array_cache
, eclass
);
1114 for (list
= rootlist
; list
; list
= list
->next
) {
1115 k
= (MonoClass
*)list
->data
;
1116 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
1121 mono_image_set_unlock (image_set
);
1123 rootlist
= (GSList
*)g_hash_table_lookup (image
->array_cache
, eclass
);
1124 for (list
= rootlist
; list
; list
= list
->next
) {
1125 k
= (MonoClass
*)list
->data
;
1126 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
1134 mono_loader_unlock ();
1138 MONO_PROFILER_RAISE (class_loading
, (klass
));
1140 UnlockedAdd (&classes_size
, sizeof (MonoClassArray
));
1141 ++class_array_count
;
1143 if (rank
== 1 && !bounded
) {
1145 mono_image_set_lock (image_set
);
1146 g_hash_table_insert (image_set
->szarray_cache
, eclass
, klass
);
1147 mono_image_set_unlock (image_set
);
1149 mono_os_mutex_lock (&image
->szarray_cache_lock
);
1150 g_hash_table_insert (image
->szarray_cache
, eclass
, klass
);
1151 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
1155 mono_image_set_lock (image_set
);
1156 list
= g_slist_append (rootlist
, klass
);
1157 g_hash_table_insert (image_set
->array_cache
, eclass
, list
);
1158 mono_image_set_unlock (image_set
);
1160 list
= g_slist_append (rootlist
, klass
);
1161 g_hash_table_insert (image
->array_cache
, eclass
, list
);
1165 mono_loader_unlock ();
1167 MONO_PROFILER_RAISE (class_loaded
, (klass
));
1173 * mono_class_create_array:
1174 * \param element_class element class
1175 * \param rank the dimension of the array class
1176 * \returns A class object describing the array with element type \p element_type and
1177 * dimension \p rank.
1180 mono_class_create_array (MonoClass
*eclass
, guint32 rank
)
1182 return mono_class_create_bounded_array (eclass
, rank
, FALSE
);
1185 // This is called by mono_class_create_generic_parameter when a new class must be created.
1187 make_generic_param_class (MonoGenericParam
*param
)
1189 MonoClass
*klass
, **ptr
;
1190 int count
, pos
, i
, min_align
;
1191 MonoGenericParamInfo
*pinfo
= mono_generic_param_info (param
);
1192 MonoGenericContainer
*container
= mono_generic_param_owner (param
);
1193 g_assert_checked (container
);
1195 MonoImage
*image
= mono_get_image_for_generic_param (param
);
1196 gboolean is_mvar
= container
->is_method
;
1197 gboolean is_anonymous
= container
->is_anonymous
;
1199 klass
= (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassGenericParam
));
1200 klass
->class_kind
= MONO_CLASS_GPARAM
;
1201 UnlockedAdd (&classes_size
, sizeof (MonoClassGenericParam
));
1202 UnlockedIncrement (&class_gparam_count
);
1204 if (!is_anonymous
) {
1205 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name
, pinfo
->name
);
1207 int n
= mono_generic_param_num (param
);
1208 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->name
, mono_make_generic_name_string (image
, n
) );
1212 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, "" );
1213 } else if (is_mvar
) {
1214 MonoMethod
*omethod
= container
->owner
.method
;
1215 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, (omethod
&& omethod
->klass
) ? omethod
->klass
->name_space
: "" );
1217 MonoClass
*oklass
= container
->owner
.klass
;
1218 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, oklass
? oklass
->name_space
: "" );
1221 MONO_PROFILER_RAISE (class_loading
, (klass
));
1223 // Count non-NULL items in pinfo->constraints
1226 for (ptr
= pinfo
->constraints
; ptr
&& *ptr
; ptr
++, count
++)
1230 if ((count
> 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo
->constraints
[0])) {
1231 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, pinfo
->constraints
[0] );
1233 } else if (pinfo
&& pinfo
->flags
& GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT
) {
1234 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, mono_class_load_from_name (mono_defaults
.corlib
, "System", "ValueType") );
1236 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, mono_defaults
.object_class
);
1239 if (count
- pos
> 0) {
1240 klass
->interface_count
= count
- pos
;
1241 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->interfaces
, (MonoClass
**)mono_image_alloc0 (image
, sizeof (MonoClass
*) * (count
- pos
)) );
1242 klass
->interfaces_inited
= TRUE
;
1243 for (i
= pos
; i
< count
; i
++)
1244 CHECKED_METADATA_WRITE_PTR ( klass
->interfaces
[i
- pos
] , pinfo
->constraints
[i
] );
1247 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->image
, image
);
1249 klass
->inited
= TRUE
;
1250 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->cast_class
, klass
);
1251 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->element_class
, klass
);
1253 MonoTypeEnum t
= is_mvar
? MONO_TYPE_MVAR
: MONO_TYPE_VAR
;
1254 klass
->_byval_arg
.type
= t
;
1255 klass
->this_arg
.type
= t
;
1256 CHECKED_METADATA_WRITE_PTR ( klass
->this_arg
.data
.generic_param
, param
);
1257 CHECKED_METADATA_WRITE_PTR ( klass
->_byval_arg
.data
.generic_param
, param
);
1258 klass
->this_arg
.byref
= TRUE
;
1260 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1261 klass
->sizes
.generic_param_token
= !is_anonymous
? pinfo
->token
: 0;
1263 if (param
->gshared_constraint
) {
1264 MonoClass
*constraint_class
= mono_class_from_mono_type_internal (param
->gshared_constraint
);
1265 mono_class_init_sizes (constraint_class
);
1266 klass
->has_references
= m_class_has_references (constraint_class
);
1269 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1270 * constrained to, the JIT depends on this.
1272 klass
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + mono_type_size (m_class_get_byval_arg (klass
), &min_align
);
1273 klass
->min_align
= min_align
;
1274 mono_memory_barrier ();
1275 klass
->size_inited
= 1;
1277 mono_class_setup_supertypes (klass
);
1279 if (count
- pos
> 0) {
1280 mono_class_setup_vtable (klass
->parent
);
1281 if (mono_class_has_failure (klass
->parent
))
1282 mono_class_set_type_load_failure (klass
, "Failed to setup parent interfaces");
1284 setup_interface_offsets (klass
, klass
->parent
->vtable_size
, TRUE
);
1291 * LOCKING: Acquires the image lock (@image).
1294 mono_class_create_generic_parameter (MonoGenericParam
*param
)
1296 MonoImage
*image
= mono_get_image_for_generic_param (param
);
1297 MonoGenericParamInfo
*pinfo
= mono_generic_param_info (param
);
1298 MonoClass
*klass
, *klass2
;
1300 // If a klass already exists for this object and is cached, return it.
1301 klass
= pinfo
->pklass
;
1306 // Create a new klass
1307 klass
= make_generic_param_class (param
);
1309 // Now we need to cache the klass we created.
1310 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1311 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1312 // and allow our newly-created klass object to just leak.
1313 mono_memory_barrier ();
1315 mono_image_lock (image
);
1317 // Here "klass2" refers to the klass potentially created by the other thread.
1318 klass2
= pinfo
->pklass
;
1323 pinfo
->pklass
= klass
;
1325 mono_image_unlock (image
);
1327 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1329 MONO_PROFILER_RAISE (class_failed
, (klass2
));
1331 MONO_PROFILER_RAISE (class_loaded
, (klass
));
1337 * mono_class_create_ptr:
1340 mono_class_create_ptr (MonoType
*type
)
1343 MonoClass
*el_class
;
1346 MonoImageSet
* image_set
;
1348 el_class
= mono_class_from_mono_type_internal (type
);
1349 image
= el_class
->image
;
1350 image_set
= class_kind_may_contain_generic_instances ((MonoTypeKind
)el_class
->class_kind
) ? mono_metadata_get_image_set_for_class (el_class
) : NULL
;
1353 mono_image_set_lock (image_set
);
1354 if (image_set
->ptr_cache
) {
1355 if ((result
= (MonoClass
*)g_hash_table_lookup (image_set
->ptr_cache
, el_class
))) {
1356 mono_image_set_unlock (image_set
);
1360 mono_image_set_unlock (image_set
);
1362 mono_image_lock (image
);
1363 if (image
->ptr_cache
) {
1364 if ((result
= (MonoClass
*)g_hash_table_lookup (image
->ptr_cache
, el_class
))) {
1365 mono_image_unlock (image
);
1369 mono_image_unlock (image
);
1372 result
= image_set
? (MonoClass
*)mono_image_set_alloc0 (image_set
, sizeof (MonoClassPointer
)) : (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassPointer
));
1374 UnlockedAdd (&classes_size
, sizeof (MonoClassPointer
));
1375 ++class_pointer_count
;
1377 result
->parent
= NULL
; /* no parent for PTR types */
1378 result
->name_space
= el_class
->name_space
;
1379 name
= g_strdup_printf ("%s*", el_class
->name
);
1380 result
->name
= image_set
? mono_image_set_strdup (image_set
, name
) : mono_image_strdup (image
, name
);
1381 result
->class_kind
= MONO_CLASS_POINTER
;
1384 MONO_PROFILER_RAISE (class_loading
, (result
));
1386 result
->image
= el_class
->image
;
1387 result
->inited
= TRUE
;
1388 result
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
1389 result
->min_align
= sizeof (gpointer
);
1390 result
->cast_class
= result
->element_class
= el_class
;
1391 result
->blittable
= TRUE
;
1393 result
->this_arg
.type
= result
->_byval_arg
.type
= MONO_TYPE_PTR
;
1394 result
->this_arg
.data
.type
= result
->_byval_arg
.data
.type
= m_class_get_byval_arg (el_class
);
1395 result
->this_arg
.byref
= TRUE
;
1397 mono_class_setup_supertypes (result
);
1400 mono_image_set_lock (image_set
);
1401 if (image_set
->ptr_cache
) {
1403 if ((result2
= (MonoClass
*)g_hash_table_lookup (image_set
->ptr_cache
, el_class
))) {
1404 mono_image_set_unlock (image_set
);
1405 MONO_PROFILER_RAISE (class_failed
, (result
));
1410 image_set
->ptr_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1412 g_hash_table_insert (image_set
->ptr_cache
, el_class
, result
);
1413 mono_image_set_unlock (image_set
);
1415 mono_image_lock (image
);
1416 if (image
->ptr_cache
) {
1418 if ((result2
= (MonoClass
*)g_hash_table_lookup (image
->ptr_cache
, el_class
))) {
1419 mono_image_unlock (image
);
1420 MONO_PROFILER_RAISE (class_failed
, (result
));
1424 image
->ptr_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1426 g_hash_table_insert (image
->ptr_cache
, el_class
, result
);
1427 mono_image_unlock (image
);
1430 MONO_PROFILER_RAISE (class_loaded
, (result
));
1436 mono_class_create_fnptr (MonoMethodSignature
*sig
)
1438 MonoClass
*result
, *cached
;
1439 static GHashTable
*ptr_hash
= NULL
;
1441 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1443 mono_loader_lock ();
1445 ptr_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1446 cached
= (MonoClass
*)g_hash_table_lookup (ptr_hash
, sig
);
1447 mono_loader_unlock ();
1451 result
= g_new0 (MonoClass
, 1);
1453 result
->parent
= NULL
; /* no parent for PTR types */
1454 result
->name_space
= "System";
1455 result
->name
= "MonoFNPtrFakeClass";
1456 result
->class_kind
= MONO_CLASS_POINTER
;
1458 result
->image
= mono_defaults
.corlib
; /* need to fix... */
1459 result
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
1460 result
->min_align
= sizeof (gpointer
);
1461 result
->cast_class
= result
->element_class
= result
;
1462 result
->this_arg
.type
= result
->_byval_arg
.type
= MONO_TYPE_FNPTR
;
1463 result
->this_arg
.data
.method
= result
->_byval_arg
.data
.method
= sig
;
1464 result
->this_arg
.byref
= TRUE
;
1465 result
->blittable
= TRUE
;
1466 result
->inited
= TRUE
;
1468 mono_class_setup_supertypes (result
);
1470 mono_loader_lock ();
1472 cached
= (MonoClass
*)g_hash_table_lookup (ptr_hash
, sig
);
1475 mono_loader_unlock ();
1479 MONO_PROFILER_RAISE (class_loading
, (result
));
1481 UnlockedAdd (&classes_size
, sizeof (MonoClassPointer
));
1482 ++class_pointer_count
;
1484 g_hash_table_insert (ptr_hash
, sig
, result
);
1486 mono_loader_unlock ();
1488 MONO_PROFILER_RAISE (class_loaded
, (result
));
1495 print_implemented_interfaces (MonoClass
*klass
)
1499 GPtrArray
*ifaces
= NULL
;
1501 int ancestor_level
= 0;
1503 name
= mono_type_get_full_name (klass
);
1504 printf ("Packed interface table for class %s has size %d\n", name
, klass
->interface_offsets_count
);
1507 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
1508 char *ic_name
= mono_type_get_full_name (klass
->interfaces_packed
[i
]);
1509 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i
,
1510 klass
->interfaces_packed
[i
]->interface_id
,
1511 klass
->interface_offsets_packed
[i
],
1512 mono_class_get_method_count (klass
->interfaces_packed
[i
]),
1516 printf ("Interface flags: ");
1517 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
1518 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
1519 printf ("(%d,T)", i
);
1521 printf ("(%d,F)", i
);
1523 printf ("Dump interface flags:");
1524 #ifdef COMPRESSED_INTERFACE_BITMAP
1526 const uint8_t* p
= klass
->interface_bitmap
;
1527 i
= klass
->max_interface_id
;
1529 printf (" %d x 00 %02X", p
[0], p
[1]);
1535 for (i
= 0; i
< ((((klass
->max_interface_id
+ 1) >> 3)) + (((klass
->max_interface_id
+ 1) & 7)? 1 :0)); i
++)
1536 printf (" %02X", klass
->interface_bitmap
[i
]);
1539 while (klass
!= NULL
) {
1540 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level
, klass
->name
);
1541 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
1542 if (!is_ok (error
)) {
1543 printf (" Type failed due to %s\n", mono_error_get_message (error
));
1544 mono_error_cleanup (error
);
1545 } else if (ifaces
) {
1546 for (i
= 0; i
< ifaces
->len
; i
++) {
1547 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1548 printf (" [UIID %d] interface %s\n", ic
->interface_id
, ic
->name
);
1549 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i
,
1551 mono_class_interface_offset (klass
, ic
),
1552 mono_class_get_method_count (ic
),
1556 g_ptr_array_free (ifaces
, TRUE
);
1559 klass
= klass
->parent
;
1564 method_is_reabstracted (guint16 flags
)
1566 if ((flags
& METHOD_ATTRIBUTE_ABSTRACT
&& flags
& METHOD_ATTRIBUTE_FINAL
))
1572 * Return the number of virtual methods.
1573 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1574 * Return -1 on failure.
1575 * FIXME It would be nice if this information could be cached somewhere.
1578 count_virtual_methods (MonoClass
*klass
)
1580 int i
, mcount
, vcount
= 0;
1582 klass
= mono_class_get_generic_type_definition (klass
); /*We can find this information by looking at the GTD*/
1584 if (klass
->methods
|| !MONO_CLASS_HAS_STATIC_METADATA (klass
)) {
1585 mono_class_setup_methods (klass
);
1586 if (mono_class_has_failure (klass
))
1589 mcount
= mono_class_get_method_count (klass
);
1590 for (i
= 0; i
< mcount
; ++i
) {
1591 flags
= klass
->methods
[i
]->flags
;
1592 if ((flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
1593 if (method_is_reabstracted (flags
))
1599 int first_idx
= mono_class_get_first_method_idx (klass
);
1600 mcount
= mono_class_get_method_count (klass
);
1601 for (i
= 0; i
< mcount
; ++i
) {
1602 flags
= mono_metadata_decode_table_row_col (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
, MONO_METHOD_FLAGS
);
1604 if ((flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
1605 if (method_is_reabstracted (flags
))
1615 set_interface_and_offset (int num_ifaces
, MonoClass
**interfaces_full
, int *interface_offsets_full
, MonoClass
*ic
, int offset
, mono_bool force_set
)
1618 for (i
= 0; i
< num_ifaces
; ++i
) {
1619 if (interfaces_full
[i
] && interfaces_full
[i
]->interface_id
== ic
->interface_id
) {
1622 interface_offsets_full
[i
] = offset
;
1625 if (interfaces_full
[i
])
1627 interfaces_full
[i
] = ic
;
1628 interface_offsets_full
[i
] = offset
;
1634 #ifdef COMPRESSED_INTERFACE_BITMAP
1637 * Compressed interface bitmap design.
1639 * Interface bitmaps take a large amount of memory, because their size is
1640 * linear with the maximum interface id assigned in the process (each interface
1641 * is assigned a unique id as it is loaded). The number of interface classes
1642 * is high because of the many implicit interfaces implemented by arrays (we'll
1643 * need to lazy-load them in the future).
1644 * Most classes implement a very small number of interfaces, so the bitmap is
1645 * sparse. This bitmap needs to be checked by interface casts, so access to the
1646 * needed bit must be fast and doable with few jit instructions.
1648 * The current compression format is as follows:
1649 * *) it is a sequence of one or more two-byte elements
1650 * *) the first byte in the element is the count of empty bitmap bytes
1651 * at the current bitmap position
1652 * *) the second byte in the element is an actual bitmap byte at the current
1655 * As an example, the following compressed bitmap bytes:
1656 * 0x07 0x01 0x00 0x7
1657 * correspond to the following bitmap:
1658 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1660 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1661 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1662 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1666 * mono_compress_bitmap:
1667 * \param dest destination buffer
1668 * \param bitmap bitmap buffer
1669 * \param size size of \p bitmap in bytes
1671 * This is a mono internal function.
1672 * The \p bitmap data is compressed into a format that is small but
1673 * still searchable in few instructions by the JIT and runtime.
1674 * The compressed data is stored in the buffer pointed to by the
1675 * \p dest array. Passing a NULL value for \p dest allows to just compute
1676 * the size of the buffer.
1677 * This compression algorithm assumes the bits set in the bitmap are
1678 * few and far between, like in interface bitmaps.
1679 * \returns The size of the compressed bitmap in bytes.
1682 mono_compress_bitmap (uint8_t *dest
, const uint8_t *bitmap
, int size
)
1686 const uint8_t *end
= bitmap
+ size
;
1687 while (bitmap
< end
) {
1688 if (*bitmap
|| numz
== 255) {
1712 * mono_class_interface_match:
1713 * \param bitmap a compressed bitmap buffer
1714 * \param id the index to check in the bitmap
1716 * This is a mono internal function.
1717 * Checks if a bit is set in a compressed interface bitmap. \p id must
1718 * be already checked for being smaller than the maximum id encoded in the
1721 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1725 mono_class_interface_match (const uint8_t *bitmap
, int id
)
1728 id
-= bitmap
[0] * 8;
1732 return bitmap
[1] & (1 << id
);
1741 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1742 * LOCKING: Acquires the loader lock.
1745 setup_interface_offsets (MonoClass
*klass
, int cur_slot
, gboolean overwrite
)
1749 int i
, j
, num_ifaces
;
1751 MonoClass
**interfaces_full
= NULL
;
1752 int *interface_offsets_full
= NULL
;
1754 GPtrArray
**ifaces_array
= NULL
;
1755 int interface_offsets_count
;
1757 num_ifaces
= interface_offsets_count
= 0;
1759 mono_loader_lock ();
1761 mono_class_setup_supertypes (klass
);
1763 if (mono_class_is_ginst (klass
)) {
1764 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
1766 interface_offsets_count
= num_ifaces
= gklass
->interface_offsets_count
;
1767 interfaces_full
= (MonoClass
**)g_malloc (sizeof (MonoClass
*) * num_ifaces
);
1768 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
1771 for (int i
= 0; i
< num_ifaces
; ++i
) {
1772 MonoClass
*gklass_ic
= gklass
->interfaces_packed
[i
];
1773 MonoClass
*inflated
= mono_class_inflate_generic_class_checked (gklass_ic
, mono_class_get_context(klass
), error
);
1774 if (!is_ok (error
)) {
1775 char *name
= mono_type_get_full_name (gklass_ic
);
1776 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1782 mono_class_setup_interface_id_internal (inflated
);
1784 interfaces_full
[i
] = inflated
;
1785 interface_offsets_full
[i
] = gklass
->interface_offsets_packed
[i
];
1787 int count
= count_virtual_methods (inflated
);
1789 char *name
= mono_type_get_full_name (inflated
);
1790 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1796 cur_slot
= MAX (cur_slot
, interface_offsets_full
[i
] + count
);
1797 max_iid
= MAX (max_iid
, inflated
->interface_id
);
1802 /* compute maximum number of slots and maximum interface id */
1804 num_ifaces
= 0; /* this can include duplicated ones */
1805 ifaces_array
= g_new0 (GPtrArray
*, klass
->idepth
);
1806 for (j
= 0; j
< klass
->idepth
; j
++) {
1807 k
= klass
->supertypes
[j
];
1809 num_ifaces
+= k
->interface_count
;
1810 for (i
= 0; i
< k
->interface_count
; i
++) {
1811 ic
= k
->interfaces
[i
];
1813 /* A gparam does not have any interface_id set. */
1814 if (! mono_class_is_gparam (ic
))
1815 mono_class_setup_interface_id_internal (ic
);
1817 if (max_iid
< ic
->interface_id
)
1818 max_iid
= ic
->interface_id
;
1820 ifaces
= mono_class_get_implemented_interfaces (k
, error
);
1821 if (!is_ok (error
)) {
1822 char *name
= mono_type_get_full_name (k
);
1823 mono_class_set_type_load_failure (klass
, "Error getting the interfaces of %s due to %s", name
, mono_error_get_message (error
));
1825 mono_error_cleanup (error
);
1830 num_ifaces
+= ifaces
->len
;
1831 for (i
= 0; i
< ifaces
->len
; ++i
) {
1832 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1833 if (max_iid
< ic
->interface_id
)
1834 max_iid
= ic
->interface_id
;
1836 ifaces_array
[j
] = ifaces
;
1840 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
1842 if (max_iid
< klass
->interface_id
)
1843 max_iid
= klass
->interface_id
;
1846 /* compute vtable offset for interfaces */
1847 interfaces_full
= (MonoClass
**)g_malloc0 (sizeof (MonoClass
*) * num_ifaces
);
1848 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
1850 for (i
= 0; i
< num_ifaces
; i
++)
1851 interface_offsets_full
[i
] = -1;
1853 /* skip the current class */
1854 for (j
= 0; j
< klass
->idepth
- 1; j
++) {
1855 k
= klass
->supertypes
[j
];
1856 ifaces
= ifaces_array
[j
];
1859 for (i
= 0; i
< ifaces
->len
; ++i
) {
1861 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1863 /*Force the sharing of interface offsets between parent and subtypes.*/
1864 io
= mono_class_interface_offset (k
, ic
);
1865 g_assertf (io
>= 0, "class %s parent %s has no offset for iface %s",
1866 mono_type_get_full_name (klass
),
1867 mono_type_get_full_name (k
),
1868 mono_type_get_full_name (ic
));
1870 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, io
, TRUE
);
1875 g_assert (klass
== klass
->supertypes
[klass
->idepth
- 1]);
1876 ifaces
= ifaces_array
[klass
->idepth
- 1];
1878 for (i
= 0; i
< ifaces
->len
; ++i
) {
1880 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1881 if (set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, cur_slot
, FALSE
))
1883 count
= count_virtual_methods (ic
);
1885 char *name
= mono_type_get_full_name (ic
);
1886 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1895 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
))
1896 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, klass
, cur_slot
, TRUE
);
1898 for (interface_offsets_count
= 0, i
= 0; i
< num_ifaces
; i
++) {
1899 if (interface_offsets_full
[i
] != -1)
1900 interface_offsets_count
++;
1904 /* Publish the data */
1905 klass
->max_interface_id
= max_iid
;
1907 * We might get called multiple times:
1908 * - mono_class_init_internal ()
1909 * - mono_class_setup_vtable ().
1910 * - mono_class_setup_interface_offsets ().
1911 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1912 * means we have to overwrite those when called from other places (#4440).
1914 if (klass
->interfaces_packed
) {
1916 g_assert (klass
->interface_offsets_count
== interface_offsets_count
);
1920 klass
->interface_offsets_count
= interface_offsets_count
;
1921 klass
->interfaces_packed
= (MonoClass
**)mono_class_alloc (klass
, sizeof (MonoClass
*) * interface_offsets_count
);
1922 klass
->interface_offsets_packed
= (guint16
*)mono_class_alloc (klass
, sizeof (guint16
) * interface_offsets_count
);
1923 bsize
= (sizeof (guint8
) * ((max_iid
+ 1) >> 3)) + (((max_iid
+ 1) & 7)? 1 :0);
1924 #ifdef COMPRESSED_INTERFACE_BITMAP
1925 bitmap
= g_malloc0 (bsize
);
1927 bitmap
= (uint8_t *)mono_class_alloc0 (klass
, bsize
);
1929 for (i
= 0; i
< interface_offsets_count
; i
++) {
1930 guint32 id
= interfaces_full
[i
]->interface_id
;
1931 bitmap
[id
>> 3] |= (1 << (id
& 7));
1932 klass
->interfaces_packed
[i
] = interfaces_full
[i
];
1933 klass
->interface_offsets_packed
[i
] = interface_offsets_full
[i
];
1935 #ifdef COMPRESSED_INTERFACE_BITMAP
1936 i
= mono_compress_bitmap (NULL
, bitmap
, bsize
);
1937 klass
->interface_bitmap
= mono_class_alloc0 (klass
, i
);
1938 mono_compress_bitmap (klass
->interface_bitmap
, bitmap
, bsize
);
1941 klass
->interface_bitmap
= bitmap
;
1945 mono_loader_unlock ();
1947 g_free (interfaces_full
);
1948 g_free (interface_offsets_full
);
1950 for (i
= 0; i
< klass
->idepth
; i
++) {
1951 ifaces
= ifaces_array
[i
];
1953 g_ptr_array_free (ifaces
, TRUE
);
1955 g_free (ifaces_array
);
1958 //printf ("JUST DONE: ");
1959 //print_implemented_interfaces (klass);
1965 * Setup interface offsets for interfaces.
1967 * - klass->max_interface_id
1968 * - klass->interface_offsets_count
1969 * - klass->interfaces_packed
1970 * - klass->interface_offsets_packed
1971 * - klass->interface_bitmap
1973 * This function can fail @class.
1977 mono_class_setup_interface_offsets (MonoClass
*klass
)
1979 /* NOTE: This function is only correct for interfaces.
1981 * It assumes that klass's interfaces can be assigned offsets starting
1982 * from 0. That assumption is incorrect for classes and valuetypes.
1984 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) && !mono_class_is_ginst (klass
));
1985 setup_interface_offsets (klass
, 0, FALSE
);
1988 #define DEBUG_INTERFACE_VTABLE_CODE 0
1989 #define TRACE_INTERFACE_VTABLE_CODE 0
1990 #define VERIFY_INTERFACE_VTABLE_CODE 0
1991 #define VTABLE_SELECTOR (1)
1993 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
1994 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
1995 if (!(VTABLE_SELECTOR)) break; \
1999 #define DEBUG_INTERFACE_VTABLE(stmt)
2002 #if TRACE_INTERFACE_VTABLE_CODE
2003 #define TRACE_INTERFACE_VTABLE(stmt) do {\
2004 if (!(VTABLE_SELECTOR)) break; \
2008 #define TRACE_INTERFACE_VTABLE(stmt)
2011 #if VERIFY_INTERFACE_VTABLE_CODE
2012 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
2013 if (!(VTABLE_SELECTOR)) break; \
2017 #define VERIFY_INTERFACE_VTABLE(stmt)
2021 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2023 mono_signature_get_full_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
2027 GString
*res
= g_string_new ("");
2029 g_string_append_c (res
, '(');
2030 for (i
= 0; i
< sig
->param_count
; ++i
) {
2032 g_string_append_c (res
, ',');
2033 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
2035 g_string_append (res
, ")=>");
2036 if (sig
->ret
!= NULL
) {
2037 mono_type_get_desc (res
, sig
->ret
, include_namespace
);
2039 g_string_append (res
, "NULL");
2042 g_string_free (res
, FALSE
);
2046 print_method_signatures (MonoMethod
*im
, MonoMethod
*cm
) {
2047 char *im_sig
= mono_signature_get_full_desc (mono_method_signature_internal (im
), TRUE
);
2048 char *cm_sig
= mono_signature_get_full_desc (mono_method_signature_internal (cm
), TRUE
);
2049 printf ("(IM \"%s\", CM \"%s\")", im_sig
, cm_sig
);
2058 is_wcf_hack_disabled (void)
2060 static char disabled
;
2062 disabled
= g_hasenv ("MONO_DISABLE_WCF_HACK") ? 1 : 2;
2063 return disabled
== 1;
2067 check_interface_method_override (MonoClass
*klass
, MonoMethod
*im
, MonoMethod
*cm
, gboolean require_newslot
, gboolean interface_is_explicitly_implemented_by_class
, gboolean slot_is_empty
)
2069 MonoMethodSignature
*cmsig
, *imsig
;
2070 if (strcmp (im
->name
, cm
->name
) == 0) {
2071 if (! (cm
->flags
& METHOD_ATTRIBUTE_PUBLIC
)) {
2072 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2075 if (! slot_is_empty
) {
2076 if (require_newslot
) {
2077 if (! interface_is_explicitly_implemented_by_class
) {
2078 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2081 if (! (cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
2082 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2086 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2089 cmsig
= mono_method_signature_internal (cm
);
2090 imsig
= mono_method_signature_internal (im
);
2091 if (!cmsig
|| !imsig
) {
2092 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
2096 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
2097 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2098 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
2099 TRACE_INTERFACE_VTABLE (printf ("]"));
2102 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2103 if (mono_security_core_clr_enabled ())
2104 mono_security_core_clr_check_override (klass
, cm
, im
);
2106 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2107 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
2108 char *body_name
= mono_method_full_name (cm
, TRUE
);
2109 char *decl_name
= mono_method_full_name (im
, TRUE
);
2110 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2118 MonoClass
*ic
= im
->klass
;
2119 const char *ic_name_space
= ic
->name_space
;
2120 const char *ic_name
= ic
->name
;
2123 if (! require_newslot
) {
2124 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2127 if (cm
->klass
->rank
== 0) {
2128 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2131 cmsig
= mono_method_signature_internal (cm
);
2132 imsig
= mono_method_signature_internal (im
);
2133 if (!cmsig
|| !imsig
) {
2134 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
2138 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
2139 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2140 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
2141 TRACE_INTERFACE_VTABLE (printf ("]"));
2144 if (mono_class_get_image (ic
) != mono_defaults
.corlib
) {
2145 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2148 if ((ic_name_space
== NULL
) || (strcmp (ic_name_space
, "System.Collections.Generic") != 0)) {
2149 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2152 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))) {
2153 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2157 subname
= (char*)strstr (cm
->name
, ic_name_space
);
2158 if (subname
!= cm
->name
) {
2159 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2162 subname
+= strlen (ic_name_space
);
2163 if (subname
[0] != '.') {
2164 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2168 if (strstr (subname
, ic_name
) != subname
) {
2169 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2172 subname
+= strlen (ic_name
);
2173 if (subname
[0] != '.') {
2174 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2178 if (strcmp (subname
, im
->name
) != 0) {
2179 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2183 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2184 if (mono_security_core_clr_enabled ())
2185 mono_security_core_clr_check_override (klass
, cm
, im
);
2187 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2188 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
2189 char *body_name
= mono_method_full_name (cm
, TRUE
);
2190 char *decl_name
= mono_method_full_name (im
, TRUE
);
2191 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2201 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2203 foreach_override (gpointer key
, gpointer value
, gpointer user_data
)
2205 MonoMethod
*method
= key
;
2206 MonoMethod
*override
= value
;
2208 char *method_name
= mono_method_get_full_name (method
);
2209 char *override_name
= mono_method_get_full_name (override
);
2210 printf (" Method '%s' has override '%s'\n", method_name
, override_name
);
2211 g_free (method_name
);
2212 g_free (override_name
);
2216 print_overrides (GHashTable
*override_map
, const char *message
)
2219 printf ("Override map \"%s\" START:\n", message
);
2220 g_hash_table_foreach (override_map
, foreach_override
, NULL
);
2221 printf ("Override map \"%s\" END.\n", message
);
2223 printf ("Override map \"%s\" EMPTY.\n", message
);
2228 print_vtable_full (MonoClass
*klass
, MonoMethod
** vtable
, int size
, int first_non_interface_slot
, const char *message
, gboolean print_interfaces
)
2230 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2234 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name
, message
, size
);
2236 if (print_interfaces
) {
2237 print_implemented_interfaces (klass
);
2238 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name
, size
);
2241 if (klass
->parent
) {
2242 parent_size
= klass
->parent
->vtable_size
;
2246 for (i
= 0; i
< size
; ++i
) {
2247 MonoMethod
*cm
= vtable
[i
];
2248 char *cm_name
= cm
? mono_method_full_name (cm
, TRUE
) : g_strdup ("nil");
2249 char newness
= (i
< parent_size
) ? 'O' : ((i
< first_non_interface_slot
) ? 'I' : 'N');
2251 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness
, i
, cm
? cm
->slot
: - 1, cm_name
, cm
);
2259 #if VERIFY_INTERFACE_VTABLE_CODE
2261 mono_method_try_get_vtable_index (MonoMethod
*method
)
2263 if (method
->is_inflated
&& (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
2264 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
2265 if (imethod
->declaring
->is_generic
)
2266 return imethod
->declaring
->slot
;
2268 return method
->slot
;
2272 mono_class_verify_vtable (MonoClass
*klass
)
2275 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2277 printf ("*** Verifying VTable of class '%s' \n", full_name
);
2281 if (!klass
->methods
)
2284 count
= mono_class_get_method_count (klass
);
2285 for (i
= 0; i
< count
; ++i
) {
2286 MonoMethod
*cm
= klass
->methods
[i
];
2289 if (!(cm
->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2293 full_name
= mono_method_full_name (cm
, TRUE
);
2295 slot
= mono_method_try_get_vtable_index (cm
);
2297 if (slot
>= klass
->vtable_size
) {
2298 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name
, slot
, klass
->vtable_size
);
2302 if (slot
>= 0 && klass
->vtable
[slot
] != cm
&& (klass
->vtable
[slot
])) {
2303 char *other_name
= klass
->vtable
[slot
] ? mono_method_full_name (klass
->vtable
[slot
], TRUE
) : g_strdup ("[null value]");
2304 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name
, slot
, other_name
);
2305 g_free (other_name
);
2308 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name
);
2315 mono_method_get_method_definition (MonoMethod
*method
)
2317 while (method
->is_inflated
)
2318 method
= ((MonoMethodInflated
*)method
)->declaring
;
2323 verify_class_overrides (MonoClass
*klass
, MonoMethod
**overrides
, int onum
)
2327 for (i
= 0; i
< onum
; ++i
) {
2328 MonoMethod
*decl
= overrides
[i
* 2];
2329 MonoMethod
*body
= overrides
[i
* 2 + 1];
2331 if (mono_class_get_generic_type_definition (body
->klass
) != mono_class_get_generic_type_definition (klass
)) {
2332 mono_class_set_type_load_failure (klass
, "Method belongs to a different class than the declared one");
2336 if (!(body
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (body
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2337 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
2338 mono_class_set_type_load_failure (klass
, "Method must not be static to override a base type");
2340 mono_class_set_type_load_failure (klass
, "Method must be virtual to override a base type");
2344 if (!(decl
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (decl
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2345 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
2346 mono_class_set_type_load_failure (klass
, "Cannot override a static method in a base type");
2348 mono_class_set_type_load_failure (klass
, "Cannot override a non virtual method in a base type");
2352 if (!mono_class_is_assignable_from_slow (decl
->klass
, klass
)) {
2353 mono_class_set_type_load_failure (klass
, "Method overrides a class or interface that is not extended or implemented by this type");
2357 body
= mono_method_get_method_definition (body
);
2358 decl
= mono_method_get_method_definition (decl
);
2360 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body
, decl
, NULL
)) {
2361 char *body_name
= mono_method_full_name (body
, TRUE
);
2362 char *decl_name
= mono_method_full_name (decl
, TRUE
);
2363 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2372 /*Checks if @klass has @parent as one of it's parents type gtd
2376 * Bar<T> : Foo<Bar<Bar<T>>>
2380 mono_class_has_gtd_parent (MonoClass
*klass
, MonoClass
*parent
)
2382 klass
= mono_class_get_generic_type_definition (klass
);
2383 parent
= mono_class_get_generic_type_definition (parent
);
2384 mono_class_setup_supertypes (klass
);
2385 mono_class_setup_supertypes (parent
);
2387 return klass
->idepth
>= parent
->idepth
&&
2388 mono_class_get_generic_type_definition (klass
->supertypes
[parent
->idepth
- 1]) == parent
;
2392 mono_class_check_vtable_constraints (MonoClass
*klass
, GList
*in_setup
)
2394 MonoGenericInst
*ginst
;
2397 if (!mono_class_is_ginst (klass
)) {
2398 mono_class_setup_vtable_full (klass
, in_setup
);
2399 return !mono_class_has_failure (klass
);
2402 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass
), in_setup
);
2403 if (mono_class_set_type_load_failure_causedby_class (klass
, mono_class_get_generic_class (klass
)->container_class
, "Failed to load generic definition vtable"))
2406 ginst
= mono_class_get_generic_class (klass
)->context
.class_inst
;
2407 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
2409 if (ginst
->type_argv
[i
]->type
!= MONO_TYPE_GENERICINST
)
2411 arg
= mono_class_from_mono_type_internal (ginst
->type_argv
[i
]);
2412 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2413 if (mono_class_has_gtd_parent (klass
, arg
) || mono_class_has_gtd_parent (arg
, klass
))
2415 if (!mono_class_check_vtable_constraints (arg
, in_setup
)) {
2416 mono_class_set_type_load_failure (klass
, "Failed to load generic parameter %d", i
);
2424 * mono_class_setup_vtable:
2426 * Creates the generic vtable of CLASS.
2427 * Initializes the following fields in MonoClass:
2430 * Plus all the fields initialized by setup_interface_offsets ().
2431 * If there is an error during vtable construction, klass->has_failure
2432 * is set and details are stored in a MonoErrorBoxed.
2434 * LOCKING: Acquires the loader lock.
2437 mono_class_setup_vtable (MonoClass
*klass
)
2439 mono_class_setup_vtable_full (klass
, NULL
);
2443 mono_class_setup_vtable_full (MonoClass
*klass
, GList
*in_setup
)
2446 MonoMethod
**overrides
= NULL
;
2447 MonoGenericContext
*context
;
2454 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
2455 /* This sets method->slot for all methods if this is an interface */
2456 mono_class_setup_methods (klass
);
2460 if (mono_class_has_failure (klass
))
2463 if (g_list_find (in_setup
, klass
))
2466 mono_loader_lock ();
2468 if (klass
->vtable
) {
2469 mono_loader_unlock ();
2473 UnlockedIncrement (&mono_stats
.generic_vtable_count
);
2474 in_setup
= g_list_prepend (in_setup
, klass
);
2476 if (mono_class_is_ginst (klass
)) {
2477 if (!mono_class_check_vtable_constraints (klass
, in_setup
)) {
2478 mono_loader_unlock ();
2479 g_list_remove (in_setup
, klass
);
2483 context
= mono_class_get_context (klass
);
2484 type_token
= mono_class_get_generic_class (klass
)->container_class
->type_token
;
2486 context
= (MonoGenericContext
*) mono_class_try_get_generic_container (klass
); //FIXME is this a case of a try?
2487 type_token
= klass
->type_token
;
2490 if (image_is_dynamic (klass
->image
)) {
2491 /* Generic instances can have zero method overrides without causing any harm.
2492 * This is true since we don't do layout all over again for them, we simply inflate
2493 * the layout of the parent.
2495 mono_reflection_get_dynamic_overrides (klass
, &overrides
, &onum
, error
);
2496 if (!is_ok (error
)) {
2497 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
2501 /* The following call fails if there are missing methods in the type */
2502 /* FIXME it's probably a good idea to avoid this for generic instances. */
2503 mono_class_get_overrides_full (klass
->image
, type_token
, &overrides
, &onum
, context
, error
);
2504 if (!is_ok (error
)) {
2505 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
2510 mono_class_setup_vtable_general (klass
, overrides
, onum
, in_setup
);
2514 mono_error_cleanup (error
);
2516 mono_loader_unlock ();
2517 g_list_remove (in_setup
, klass
);
2523 mono_class_need_stelemref_method (MonoClass
*klass
)
2525 return klass
->rank
== 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass
)));
2529 apply_override (MonoClass
*klass
, MonoClass
*override_class
, MonoMethod
**vtable
, MonoMethod
*decl
, MonoMethod
*override
,
2530 GHashTable
**override_map
, GHashTable
**override_class_map
, GHashTable
**conflict_map
)
2533 dslot
= mono_method_get_vtable_slot (decl
);
2535 mono_class_set_type_load_failure (klass
, "");
2539 dslot
+= mono_class_interface_offset (klass
, decl
->klass
);
2541 //check if the override comes from an interface and the overrided method is from a class, if this is the case it shouldn't be changed
2542 if (vtable
[dslot
] && vtable
[dslot
]->klass
&& MONO_CLASS_IS_INTERFACE_INTERNAL (override
->klass
) && !MONO_CLASS_IS_INTERFACE_INTERNAL (vtable
[dslot
]->klass
))
2545 vtable
[dslot
] = override
;
2546 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override
->klass
)) {
2548 * If override from an interface, then it is an override of a default interface method,
2549 * don't override its slot.
2551 vtable
[dslot
]->slot
= dslot
;
2554 if (!*override_map
) {
2555 *override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2556 *override_class_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2558 GHashTable
*map
= *override_map
;
2559 GHashTable
*class_map
= *override_class_map
;
2561 MonoMethod
*prev_override
= (MonoMethod
*)g_hash_table_lookup (map
, decl
);
2562 MonoClass
*prev_override_class
= (MonoClass
*)g_hash_table_lookup (class_map
, decl
);
2564 g_hash_table_insert (map
, decl
, override
);
2565 g_hash_table_insert (class_map
, decl
, override_class
);
2567 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2568 if (prev_override
) {
2572 * The override methods are part of the generic definition, need to inflate them so their
2573 * parent class becomes the actual interface/class containing the override, i.e.
2575 * class Foo<T> : IFace<T>
2576 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2577 * conflict resolution work.
2579 if (mono_class_is_ginst (override_class
)) {
2580 override
= mono_class_inflate_generic_method_checked (override
, &mono_class_get_generic_class (override_class
)->context
, error
);
2581 mono_error_assert_ok (error
);
2584 if (mono_class_is_ginst (prev_override_class
)) {
2585 prev_override
= mono_class_inflate_generic_method_checked (prev_override
, &mono_class_get_generic_class (prev_override_class
)->context
, error
);
2586 mono_error_assert_ok (error
);
2590 *conflict_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2591 GHashTable
*cmap
= *conflict_map
;
2592 GSList
*entries
= (GSList
*)g_hash_table_lookup (cmap
, decl
);
2593 if (!(decl
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
2594 entries
= g_slist_prepend (entries
, decl
);
2595 entries
= g_slist_prepend (entries
, prev_override
);
2596 entries
= g_slist_prepend (entries
, override
);
2598 g_hash_table_insert (cmap
, decl
, entries
);
2605 handle_dim_conflicts (MonoMethod
**vtable
, MonoClass
*klass
, GHashTable
*conflict_map
)
2607 GHashTableIter iter
;
2609 GSList
*entries
, *l
, *l2
;
2610 GSList
*dim_conflicts
= NULL
;
2612 g_hash_table_iter_init (&iter
, conflict_map
);
2613 while (g_hash_table_iter_next (&iter
, (gpointer
*)&decl
, (gpointer
*)&entries
)) {
2615 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2616 * class of another one.
2618 /* This is O(n^2), but that shouldn't be a problem in practice */
2619 for (l
= entries
; l
; l
= l
->next
) {
2620 for (l2
= entries
; l2
; l2
= l2
->next
) {
2621 MonoMethod
*m1
= (MonoMethod
*)l
->data
;
2622 MonoMethod
*m2
= (MonoMethod
*)l2
->data
;
2623 if (!m1
|| !m2
|| m1
== m2
)
2625 if (mono_class_is_assignable_from_internal (m1
->klass
, m2
->klass
))
2627 else if (mono_class_is_assignable_from_internal (m2
->klass
, m1
->klass
))
2632 MonoMethod
*impl
= NULL
;
2633 for (l
= entries
; l
; l
= l
->next
) {
2636 impl
= (MonoMethod
*)l
->data
;
2640 /* If more than one method is left, we have a conflict */
2641 if (decl
->is_inflated
)
2642 decl
= ((MonoMethodInflated
*)decl
)->declaring
;
2643 dim_conflicts
= g_slist_prepend (dim_conflicts
, decl
);
2645 for (l = entries; l; l = l->next) {
2647 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2652 * Use the implementing method computed above instead of the already
2653 * computed one, which depends on interface ordering.
2655 int ic_offset
= mono_class_interface_offset (klass
, decl
->klass
);
2656 int im_slot
= ic_offset
+ decl
->slot
;
2657 vtable
[im_slot
] = impl
;
2659 g_slist_free (entries
);
2661 if (dim_conflicts
) {
2662 mono_loader_lock ();
2663 klass
->has_dim_conflicts
= 1;
2664 mono_loader_unlock ();
2667 * Exceptions are thrown at method call time and only for the methods which have
2668 * conflicts, so just save them in the class.
2671 /* Make a copy of the list from the class mempool */
2672 GSList
*conflicts
= (GSList
*)mono_class_alloc0 (klass
, g_slist_length (dim_conflicts
) * sizeof (GSList
));
2674 for (l
= dim_conflicts
; l
; l
= l
->next
) {
2675 conflicts
[i
].data
= l
->data
;
2676 conflicts
[i
].next
= &conflicts
[i
+ 1];
2679 conflicts
[i
- 1].next
= NULL
;
2681 mono_class_set_dim_conflicts (klass
, conflicts
);
2682 g_slist_free (dim_conflicts
);
2687 print_unimplemented_interface_method_info (MonoClass
*klass
, MonoClass
*ic
, MonoMethod
*im
, int im_slot
, MonoMethod
**overrides
, int onum
)
2690 char *method_signature
;
2693 for (index
= 0; index
< onum
; ++index
) {
2694 mono_trace_warning (MONO_TRACE_TYPE
, " at slot %d: %s (%d) overrides %s (%d)", im_slot
, overrides
[index
*2+1]->name
,
2695 overrides
[index
*2+1]->slot
, overrides
[index
*2]->name
, overrides
[index
*2]->slot
);
2697 method_signature
= mono_signature_get_desc (mono_method_signature_internal (im
), FALSE
);
2698 type_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2699 mono_trace_warning (MONO_TRACE_TYPE
, "no implementation for interface method %s::%s(%s) in class %s",
2700 mono_type_get_name (m_class_get_byval_arg (ic
)), im
->name
, method_signature
, type_name
);
2701 g_free (method_signature
);
2703 mono_class_setup_methods (klass
);
2704 if (mono_class_has_failure (klass
)) {
2705 char *name
= mono_type_get_full_name (klass
);
2706 mono_trace_warning (MONO_TRACE_TYPE
, "CLASS %s failed to resolve methods", name
);
2710 mcount
= mono_class_get_method_count (klass
);
2711 for (index
= 0; index
< mcount
; ++index
) {
2712 MonoMethod
*cm
= klass
->methods
[index
];
2713 method_signature
= mono_signature_get_desc (mono_method_signature_internal (cm
), TRUE
);
2715 mono_trace_warning (MONO_TRACE_TYPE
, "METHOD %s(%s)", cm
->name
, method_signature
);
2716 g_free (method_signature
);
2721 * mono_class_get_virtual_methods:
2723 * Iterate over the virtual methods of KLASS.
2725 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2728 mono_class_get_virtual_methods (MonoClass
* klass
, gpointer
*iter
)
2730 // FIXME move state to caller
2731 gboolean static_iter
= FALSE
;
2737 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2738 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2741 if ((gsize
)(*iter
) & 1)
2743 /* Use the static metadata only if klass->methods is not yet initialized */
2744 if (!static_iter
&& !(klass
->methods
|| !MONO_CLASS_HAS_STATIC_METADATA (klass
)))
2748 MonoMethod
** methodptr
;
2751 mono_class_setup_methods (klass
);
2753 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2754 * FIXME we should better report this error to the caller
2756 if (!klass
->methods
)
2758 /* start from the first */
2759 methodptr
= &klass
->methods
[0];
2761 methodptr
= (MonoMethod
**)*iter
;
2765 g_assert ((guint64
)(*iter
) > 0x100);
2766 int mcount
= mono_class_get_method_count (klass
);
2767 while (methodptr
< &klass
->methods
[mcount
]) {
2768 if (*methodptr
&& ((*methodptr
)->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2772 if (methodptr
< &klass
->methods
[mcount
]) {
2779 /* Search directly in metadata to avoid calling setup_methods () */
2780 MonoMethod
*res
= NULL
;
2786 start_index
= GPOINTER_TO_UINT (*iter
) >> 1;
2789 int first_idx
= mono_class_get_first_method_idx (klass
);
2790 int mcount
= mono_class_get_method_count (klass
);
2791 for (i
= start_index
; i
< mcount
; ++i
) {
2794 /* first_idx points into the methodptr table */
2795 flags
= mono_metadata_decode_table_row_col (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
, MONO_METHOD_FLAGS
);
2797 if (flags
& METHOD_ATTRIBUTE_VIRTUAL
)
2803 res
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| (first_idx
+ i
+ 1), klass
, NULL
, error
);
2804 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2806 /* Add 1 here so the if (*iter) check fails */
2807 *iter
= GUINT_TO_POINTER (((i
+ 1) << 1) | 1);
2816 print_vtable_layout_result (MonoClass
*klass
, MonoMethod
**vtable
, int cur_slot
)
2820 print_implemented_interfaces (klass
);
2822 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
2823 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
2826 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass
)),
2827 klass
->vtable_size
, icount
);
2829 for (i
= 0; i
< cur_slot
; ++i
) {
2834 printf (" slot assigned: %03d, slot index: %03d %s\n", i
, cm
->slot
,
2835 mono_method_get_full_name (cm
));
2837 printf (" slot assigned: %03d, <null>\n", i
);
2843 printf ("Interfaces %s.%s (max_iid = %d)\n", klass
->name_space
,
2844 klass
->name
, klass
->max_interface_id
);
2846 for (i
= 0; i
< klass
->interface_count
; i
++) {
2847 MonoClass
*ic
= klass
->interfaces
[i
];
2848 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2849 mono_class_interface_offset (klass
, ic
),
2850 count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
2853 for (MonoClass
*k
= klass
->parent
; k
; k
= k
->parent
) {
2854 for (i
= 0; i
< k
->interface_count
; i
++) {
2855 MonoClass
*ic
= k
->interfaces
[i
];
2856 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2857 mono_class_interface_offset (klass
, ic
),
2858 count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
2865 * LOCKING: this is supposed to be called with the loader lock held.
2868 setup_class_vtsize (MonoClass
*klass
, GList
*in_setup
, int *cur_slot
, int *stelemref_slot
, MonoError
*error
)
2870 GPtrArray
*ifaces
= NULL
;
2871 int i
, max_vtsize
= 0;
2872 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
2873 if (!is_ok (error
)) {
2874 char *name
= mono_type_get_full_name (klass
);
2875 mono_class_set_type_load_failure (klass
, "Could not resolve %s interfaces due to %s", name
, mono_error_get_message (error
));
2877 mono_error_cleanup (error
);
2879 } else if (ifaces
) {
2880 for (i
= 0; i
< ifaces
->len
; i
++) {
2881 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2882 max_vtsize
+= mono_class_get_method_count (ic
);
2884 g_ptr_array_free (ifaces
, TRUE
);
2888 if (klass
->parent
) {
2889 mono_class_init_internal (klass
->parent
);
2890 mono_class_setup_vtable_full (klass
->parent
, in_setup
);
2892 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Parent class failed to load"))
2895 max_vtsize
+= klass
->parent
->vtable_size
;
2896 *cur_slot
= klass
->parent
->vtable_size
;
2899 max_vtsize
+= mono_class_get_method_count (klass
);
2901 /*Array have a slot for stelemref*/
2902 if (mono_class_need_stelemref_method (klass
)) {
2903 *stelemref_slot
= *cur_slot
;
2911 * LOCKING: this is supposed to be called with the loader lock held.
2914 mono_class_setup_vtable_ginst (MonoClass
*klass
, GList
*in_setup
)
2918 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
2921 mono_class_setup_vtable_full (gklass
, in_setup
);
2922 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Could not load generic definition"))
2925 tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * gklass
->vtable_size
);
2926 klass
->vtable_size
= gklass
->vtable_size
;
2927 for (i
= 0; i
< gklass
->vtable_size
; ++i
)
2928 if (gklass
->vtable
[i
]) {
2929 MonoMethod
*inflated
= mono_class_inflate_generic_method_full_checked (gklass
->vtable
[i
], klass
, mono_class_get_context (klass
), error
);
2930 if (!is_ok (error
)) {
2931 char *name
= mono_type_get_full_name (klass
);
2932 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed due to: %s", name
, mono_error_get_message (error
));
2933 mono_error_cleanup (error
);
2938 tmp
[i
]->slot
= gklass
->vtable
[i
]->slot
;
2940 mono_memory_barrier ();
2941 klass
->vtable
= tmp
;
2943 mono_loader_lock ();
2944 klass
->has_dim_conflicts
= gklass
->has_dim_conflicts
;
2945 mono_loader_unlock ();
2947 /* Have to set method->slot for abstract virtual methods */
2948 if (klass
->methods
&& gklass
->methods
) {
2949 int mcount
= mono_class_get_method_count (klass
);
2950 for (i
= 0; i
< mcount
; ++i
)
2951 if (klass
->methods
[i
]->slot
== -1)
2952 klass
->methods
[i
]->slot
= gklass
->methods
[i
]->slot
;
2955 if (mono_print_vtable
)
2956 print_vtable_layout_result (klass
, klass
->vtable
, gklass
->vtable_size
);
2961 * LOCKING: this is supposed to be called with the loader lock held.
2964 mono_class_setup_vtable_general (MonoClass
*klass
, MonoMethod
**overrides
, int onum
, GList
*in_setup
)
2968 MonoMethod
**vtable
= NULL
;
2969 int i
, max_vtsize
= 0, cur_slot
= 0;
2970 GHashTable
*override_map
= NULL
;
2971 GHashTable
*override_class_map
= NULL
;
2972 GHashTable
*conflict_map
= NULL
;
2974 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2975 int first_non_interface_slot
;
2977 GSList
*virt_methods
= NULL
, *l
;
2978 int stelemref_slot
= 0;
2983 if (overrides
&& !verify_class_overrides (klass
, overrides
, onum
))
2986 max_vtsize
= setup_class_vtsize (klass
, in_setup
, &cur_slot
, &stelemref_slot
, error
);
2987 if (max_vtsize
== -1)
2990 cur_slot
= setup_interface_offsets (klass
, cur_slot
, TRUE
);
2991 if (cur_slot
== -1) /*setup_interface_offsets fails the type.*/
2994 DEBUG_INTERFACE_VTABLE (first_non_interface_slot
= cur_slot
);
2996 /* Optimized version for generic instances */
2997 if (mono_class_is_ginst (klass
)) {
2998 mono_class_setup_vtable_ginst (klass
, in_setup
);
3002 vtable
= (MonoMethod
**)g_malloc0 (sizeof (gpointer
) * max_vtsize
);
3004 if (klass
->parent
&& klass
->parent
->vtable_size
)
3005 memcpy (vtable
, klass
->parent
->vtable
, sizeof (gpointer
) * klass
->parent
->vtable_size
);
3007 /*Array have a slot for stelemref*/
3008 if (mono_class_need_stelemref_method (klass
)) {
3009 MonoMethod
*method
= mono_marshal_get_virtual_stelemref (klass
);
3011 method
->slot
= stelemref_slot
;
3013 g_assert (method
->slot
== stelemref_slot
);
3015 vtable
[stelemref_slot
] = method
;
3018 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER INHERITING PARENT VTABLE", TRUE
));
3020 /* Process overrides from interface default methods */
3021 // FIXME: Ordering between interfaces
3022 for (int ifindex
= 0; ifindex
< klass
->interface_offsets_count
; ifindex
++) {
3023 ic
= klass
->interfaces_packed
[ifindex
];
3025 mono_class_setup_methods (ic
);
3026 if (mono_class_has_failure (ic
))
3029 MonoMethod
**iface_overrides
;
3031 mono_class_get_overrides_full (ic
->image
, ic
->type_token
, &iface_overrides
, &iface_onum
, mono_class_get_context (ic
), error
);
3032 goto_if_nok (error
, fail
);
3033 for (int i
= 0; i
< iface_onum
; i
++) {
3034 MonoMethod
*decl
= iface_overrides
[i
*2];
3035 MonoMethod
*override
= iface_overrides
[i
*2 + 1];
3036 if (decl
->is_inflated
) {
3037 override
= mono_class_inflate_generic_method_checked (override
, mono_method_get_context (decl
), error
);
3038 mono_error_assert_ok (error
);
3039 } else if (mono_class_is_gtd (override
->klass
)) {
3040 override
= mono_class_inflate_generic_method_full_checked (override
, ic
, mono_class_get_context (ic
), error
);
3042 if (!apply_override (klass
, ic
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
3045 g_free (iface_overrides
);
3048 /* override interface methods */
3049 for (i
= 0; i
< onum
; i
++) {
3050 MonoMethod
*decl
= overrides
[i
*2];
3051 MonoMethod
*override
= overrides
[i
*2 + 1];
3052 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
3053 if (!apply_override (klass
, klass
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
3058 TRACE_INTERFACE_VTABLE (print_overrides (override_map
, "AFTER OVERRIDING INTERFACE METHODS"));
3059 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER OVERRIDING INTERFACE METHODS", FALSE
));
3062 * Create a list of virtual methods to avoid calling
3063 * mono_class_get_virtual_methods () which is slow because of the metadata
3067 gpointer iter
= NULL
;
3070 virt_methods
= NULL
;
3071 while ((cm
= mono_class_get_virtual_methods (klass
, &iter
))) {
3072 virt_methods
= g_slist_prepend (virt_methods
, cm
);
3074 if (mono_class_has_failure (klass
))
3078 // Loop on all implemented interfaces...
3079 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
3080 MonoClass
*parent
= klass
->parent
;
3082 gboolean interface_is_explicitly_implemented_by_class
;
3085 ic
= klass
->interfaces_packed
[i
];
3086 ic_offset
= mono_class_interface_offset (klass
, ic
);
3088 mono_class_setup_methods (ic
);
3089 if (mono_class_has_failure (ic
))
3092 // Check if this interface is explicitly implemented (instead of just inherited)
3093 if (parent
!= NULL
) {
3094 int implemented_interfaces_index
;
3095 interface_is_explicitly_implemented_by_class
= FALSE
;
3096 for (implemented_interfaces_index
= 0; implemented_interfaces_index
< klass
->interface_count
; implemented_interfaces_index
++) {
3097 if (ic
== klass
->interfaces
[implemented_interfaces_index
]) {
3098 interface_is_explicitly_implemented_by_class
= TRUE
;
3103 interface_is_explicitly_implemented_by_class
= TRUE
;
3106 // Loop on all interface methods...
3107 int mcount
= mono_class_get_method_count (ic
);
3108 for (im_index
= 0; im_index
< mcount
; im_index
++) {
3109 MonoMethod
*im
= ic
->methods
[im_index
];
3110 int im_slot
= ic_offset
+ im
->slot
;
3111 MonoMethod
*override_im
= (override_map
!= NULL
) ? (MonoMethod
*)g_hash_table_lookup (override_map
, im
) : NULL
;
3113 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
3116 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im
,1)));
3118 if (override_im
== NULL
|| (override_im
&& MONO_CLASS_IS_INTERFACE_INTERNAL(override_im
->klass
))) {
3122 // First look for a suitable method among the class methods
3123 for (l
= virt_methods
; l
; l
= l
->next
) {
3124 cm
= (MonoMethod
*)l
->data
;
3125 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
)));
3126 if (check_interface_method_override (klass
, im
, cm
, TRUE
, interface_is_explicitly_implemented_by_class
, (vtable
[im_slot
] == NULL
))) {
3127 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3128 vtable
[im_slot
] = cm
;
3129 /* Why do we need this? */
3134 g_hash_table_remove(conflict_map
, im
);
3137 TRACE_INTERFACE_VTABLE (printf ("\n"));
3138 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
3142 // If the slot is still empty, look in all the inherited virtual methods...
3143 if ((vtable
[im_slot
] == NULL
) && klass
->parent
!= NULL
) {
3144 MonoClass
*parent
= klass
->parent
;
3145 // Reverse order, so that last added methods are preferred
3146 for (cm_index
= parent
->vtable_size
- 1; cm_index
>= 0; cm_index
--) {
3147 MonoMethod
*cm
= parent
->vtable
[cm_index
];
3149 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
));
3150 if ((cm
!= NULL
) && check_interface_method_override (klass
, im
, cm
, FALSE
, FALSE
, TRUE
)) {
3151 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3152 vtable
[im_slot
] = cm
;
3153 /* Why do we need this? */
3159 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
3161 TRACE_INTERFACE_VTABLE ((cm
!= NULL
) && printf ("\n"));
3165 if (vtable
[im_slot
] == NULL
) {
3166 if (!(im
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)) {
3167 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im
, 1)));
3168 vtable
[im_slot
] = im
;
3172 g_assert (vtable
[im_slot
] == override_im
);
3177 // If the class is not abstract, check that all its interface slots are full.
3178 // The check is done here and not directly at the end of the loop above because
3179 // it can happen (for injected generic array interfaces) that the same slot is
3180 // processed multiple times (those interfaces have overlapping slots), and it
3181 // will not always be the first pass the one that fills the slot.
3182 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
3183 if (!mono_class_is_abstract (klass
)) {
3184 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
3188 ic
= klass
->interfaces_packed
[i
];
3189 ic_offset
= mono_class_interface_offset (klass
, ic
);
3191 int mcount
= mono_class_get_method_count (ic
);
3192 for (im_index
= 0; im_index
< mcount
; im_index
++) {
3193 MonoMethod
*im
= ic
->methods
[im_index
];
3194 int im_slot
= ic_offset
+ im
->slot
;
3196 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
3198 if (im
->is_reabstracted
== 1)
3201 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3202 im_slot
, ic
->name_space
, ic
->name
, im
->name
, (vtable
[im_slot
] == NULL
)));
3203 if (vtable
[im_slot
] == NULL
) {
3204 print_unimplemented_interface_method_info (klass
, ic
, im
, im_slot
, overrides
, onum
);
3211 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER SETTING UP INTERFACE METHODS", FALSE
));
3212 for (l
= virt_methods
; l
; l
= l
->next
) {
3213 cm
= (MonoMethod
*)l
->data
;
3215 * If the method is REUSE_SLOT, we must check in the
3216 * base class for a method to override.
3218 if (!(cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
3220 for (k
= klass
->parent
; k
; k
= k
->parent
) {
3225 while ((m1
= mono_class_get_virtual_methods (k
, &k_iter
))) {
3226 MonoMethodSignature
*cmsig
, *m1sig
;
3228 cmsig
= mono_method_signature_internal (cm
);
3229 m1sig
= mono_method_signature_internal (m1
);
3231 if (!cmsig
|| !m1sig
) /* FIXME proper error message, use signature_checked? */
3234 if (!strcmp(cm
->name
, m1
->name
) &&
3235 mono_metadata_signature_equal (cmsig
, m1sig
)) {
3237 if (mono_security_core_clr_enabled ())
3238 mono_security_core_clr_check_override (klass
, cm
, m1
);
3240 slot
= mono_method_get_vtable_slot (m1
);
3244 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, m1
, NULL
)) {
3245 char *body_name
= mono_method_full_name (cm
, TRUE
);
3246 char *decl_name
= mono_method_full_name (m1
, TRUE
);
3247 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
3253 g_assert (cm
->slot
< max_vtsize
);
3255 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3256 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3257 mono_method_full_name (m1
, 1), m1
,
3258 mono_method_full_name (cm
, 1), cm
));
3259 g_hash_table_insert (override_map
, m1
, cm
);
3263 if (mono_class_has_failure (k
))
3273 /*Non final newslot methods must be given a non-interface vtable slot*/
3274 if ((cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
) && !(cm
->flags
& METHOD_ATTRIBUTE_FINAL
) && cm
->slot
>= 0)
3278 cm
->slot
= cur_slot
++;
3280 if (!(cm
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
3281 vtable
[cm
->slot
] = cm
;
3284 /* override non interface methods */
3285 for (i
= 0; i
< onum
; i
++) {
3286 MonoMethod
*decl
= overrides
[i
*2];
3287 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
3288 g_assert (decl
->slot
!= -1);
3289 vtable
[decl
->slot
] = overrides
[i
*2 + 1];
3290 overrides
[i
* 2 + 1]->slot
= decl
->slot
;
3292 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3293 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3294 mono_method_full_name (decl
, 1), decl
,
3295 mono_method_full_name (overrides
[i
* 2 + 1], 1), overrides
[i
* 2 + 1]));
3296 g_hash_table_insert (override_map
, decl
, overrides
[i
* 2 + 1]);
3298 if (mono_security_core_clr_enabled ())
3299 mono_security_core_clr_check_override (klass
, vtable
[decl
->slot
], decl
);
3304 * If a method occupies more than one place in the vtable, and it is
3305 * overriden, then change the other occurrences too.
3310 for (i
= 0; i
< max_vtsize
; ++i
)
3312 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i
, mono_method_full_name (vtable
[i
], 1), vtable
[i
]));
3314 cm
= (MonoMethod
*)g_hash_table_lookup (override_map
, vtable
[i
]);
3319 g_hash_table_destroy (override_map
);
3320 override_map
= NULL
;
3323 if (override_class_map
)
3324 g_hash_table_destroy (override_class_map
);
3327 handle_dim_conflicts (vtable
, klass
, conflict_map
);
3328 g_hash_table_destroy (conflict_map
);
3331 g_slist_free (virt_methods
);
3332 virt_methods
= NULL
;
3334 g_assert (cur_slot
<= max_vtsize
);
3336 /* Ensure that all vtable slots are filled with concrete instance methods */
3337 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
3338 if (!mono_class_is_abstract (klass
)) {
3339 for (i
= 0; i
< cur_slot
; ++i
) {
3340 if (vtable
[i
] == NULL
|| (vtable
[i
]->flags
& (METHOD_ATTRIBUTE_ABSTRACT
| METHOD_ATTRIBUTE_STATIC
))) {
3341 if (vtable
[i
] != NULL
&& vtable
[i
]->is_reabstracted
== 1)
3343 char *type_name
= mono_type_get_full_name (klass
);
3344 char *method_name
= vtable
[i
] ? mono_method_full_name (vtable
[i
], TRUE
) : g_strdup ("none");
3345 mono_class_set_type_load_failure (klass
, "Type %s has invalid vtable method slot %d with method %s", type_name
, i
, method_name
);
3347 g_free (method_name
);
3349 if (mono_print_vtable
)
3350 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3358 if (mono_class_is_ginst (klass
)) {
3359 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
3361 mono_class_init_internal (gklass
);
3363 klass
->vtable_size
= MAX (gklass
->vtable_size
, cur_slot
);
3365 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
3366 if (klass
->vtable_size
)
3367 g_assert (cur_slot
== klass
->vtable_size
);
3368 klass
->vtable_size
= cur_slot
;
3371 /* Try to share the vtable with our parent. */
3372 if (klass
->parent
&& (klass
->parent
->vtable_size
== klass
->vtable_size
) && (memcmp (klass
->parent
->vtable
, vtable
, sizeof (gpointer
) * klass
->vtable_size
) == 0)) {
3373 mono_memory_barrier ();
3374 klass
->vtable
= klass
->parent
->vtable
;
3376 MonoMethod
**tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * klass
->vtable_size
);
3377 memcpy (tmp
, vtable
, sizeof (gpointer
) * klass
->vtable_size
);
3378 mono_memory_barrier ();
3379 klass
->vtable
= tmp
;
3382 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass
, klass
->vtable
, klass
->vtable_size
, first_non_interface_slot
, "FINALLY", FALSE
));
3383 if (mono_print_vtable
)
3384 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3388 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass
));
3393 char *name
= mono_type_get_full_name (klass
);
3395 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed due to: %s", name
, mono_error_get_message (error
));
3397 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed", name
);
3398 mono_error_cleanup (error
);
3400 if (mono_print_vtable
)
3401 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3406 g_hash_table_destroy (override_map
);
3408 g_slist_free (virt_methods
);
3413 concat_two_strings_with_zero (MonoImage
*image
, const char *s1
, const char *s2
)
3415 int null_length
= strlen ("(null)");
3416 int len
= (s1
? strlen (s1
) : null_length
) + (s2
? strlen (s2
) : null_length
) + 2;
3417 char *s
= (char *)mono_image_alloc (image
, len
);
3420 result
= g_snprintf (s
, len
, "%s%c%s", s1
? s1
: "(null)", '\0', s2
? s2
: "(null)");
3421 g_assert (result
== len
- 1);
3428 init_sizes_with_info (MonoClass
*klass
, MonoCachedClassInfo
*cached_info
)
3431 mono_loader_lock ();
3432 klass
->instance_size
= cached_info
->instance_size
;
3433 klass
->sizes
.class_size
= cached_info
->class_size
;
3434 klass
->packing_size
= cached_info
->packing_size
;
3435 klass
->min_align
= cached_info
->min_align
;
3436 klass
->blittable
= cached_info
->blittable
;
3437 klass
->has_references
= cached_info
->has_references
;
3438 klass
->has_static_refs
= cached_info
->has_static_refs
;
3439 klass
->no_special_static_fields
= cached_info
->no_special_static_fields
;
3440 klass
->has_weak_fields
= cached_info
->has_weak_fields
;
3441 mono_loader_unlock ();
3444 if (!klass
->size_inited
)
3445 mono_class_setup_fields (klass
);
3450 * mono_class_init_sizes:
3452 * Initializes the size related fields of @klass without loading all field data if possible.
3453 * Sets the following fields in @klass:
3455 * - sizes.class_size
3462 * Can fail the class.
3464 * LOCKING: Acquires the loader lock.
3467 mono_class_init_sizes (MonoClass
*klass
)
3469 MonoCachedClassInfo cached_info
;
3470 gboolean has_cached_info
;
3472 if (klass
->size_inited
)
3475 has_cached_info
= mono_class_get_cached_class_info (klass
, &cached_info
);
3477 init_sizes_with_info (klass
, has_cached_info
? &cached_info
: NULL
);
3482 class_has_references (MonoClass
*klass
)
3484 mono_class_init_sizes (klass
);
3487 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3488 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3491 return klass
->has_references
;
3495 type_has_references (MonoClass
*klass
, MonoType
*ftype
)
3497 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
)))))
3499 if (!ftype
->byref
&& (ftype
->type
== MONO_TYPE_VAR
|| ftype
->type
== MONO_TYPE_MVAR
)) {
3500 MonoGenericParam
*gparam
= ftype
->data
.generic_param
;
3502 if (gparam
->gshared_constraint
)
3503 return class_has_references (mono_class_from_mono_type_internal (gparam
->gshared_constraint
));
3509 * mono_class_is_gparam_with_nonblittable_parent:
3510 * \param klass a generic parameter
3512 * \returns TRUE if \p klass is definitely not blittable.
3514 * A parameter is definitely not blittable if it has the IL 'reference'
3515 * constraint, or if it has a class specified as a parent. If it has an IL
3516 * 'valuetype' constraint or no constraint at all or only interfaces as
3517 * constraints, we return FALSE because the parameter may be instantiated both
3518 * with blittable and non-blittable types.
3520 * If the paramter is a generic sharing parameter, we look at its gshared_constraint->blittable bit.
3523 mono_class_is_gparam_with_nonblittable_parent (MonoClass
*klass
)
3525 MonoType
*type
= m_class_get_byval_arg (klass
);
3526 g_assert (mono_type_is_generic_parameter (type
));
3527 MonoGenericParam
*gparam
= type
->data
.generic_param
;
3528 if ((mono_generic_param_info (gparam
)->flags
& GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT
) != 0)
3530 if ((mono_generic_param_info (gparam
)->flags
& GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT
) != 0)
3533 if (gparam
->gshared_constraint
) {
3534 MonoClass
*constraint_class
= mono_class_from_mono_type_internal (gparam
->gshared_constraint
);
3535 return !m_class_is_blittable (constraint_class
);
3538 if (mono_generic_param_owner (gparam
)->is_anonymous
)
3541 /* We could have: T : U, U : Base. So have to follow the constraints. */
3542 MonoClass
*parent_class
= mono_generic_param_get_base_type (klass
);
3543 g_assert (!MONO_CLASS_IS_INTERFACE_INTERNAL (parent_class
));
3544 /* Parent can only be: System.Object, System.ValueType or some specific base class.
3546 * If the parent_class is ValueType, the valuetype constraint would be set, above, so
3547 * we wouldn't get here.
3549 * If there was a reference constraint, the parent_class would be System.Object,
3550 * but we would have returned early above.
3552 * So if we get here, there is either no base class constraint at all,
3553 * in which case parent_class would be set to System.Object, or there is none at all.
3555 return parent_class
!= mono_defaults
.object_class
;
3559 * mono_class_layout_fields:
3561 * @base_instance_size: base instance size
3564 * This contains the common code for computing the layout of classes and sizes.
3565 * This should only be called from mono_class_setup_fields () and
3566 * typebuilder_setup_fields ().
3568 * LOCKING: Acquires the loader lock
3571 mono_class_layout_fields (MonoClass
*klass
, int base_instance_size
, int packing_size
, int explicit_size
, gboolean sre
)
3574 const int top
= mono_class_get_field_count (klass
);
3575 guint32 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
3576 guint32 pass
, passes
, real_size
;
3577 gboolean gc_aware_layout
= FALSE
;
3578 gboolean has_static_fields
= FALSE
;
3579 gboolean has_references
= FALSE
;
3580 gboolean has_static_refs
= FALSE
;
3581 MonoClassField
*field
;
3583 int instance_size
= base_instance_size
;
3584 int element_size
= -1;
3585 int class_size
, min_align
;
3587 gboolean
*fields_has_references
;
3590 * We want to avoid doing complicated work inside locks, so we compute all the required
3591 * information and write it to @klass inside a lock.
3593 if (klass
->fields_inited
)
3596 if ((packing_size
& 0xffffff00) != 0) {
3597 mono_class_set_type_load_failure (klass
, "Could not load struct '%s' with packing size %d >= 256", klass
->name
, packing_size
);
3601 if (klass
->parent
) {
3602 min_align
= klass
->parent
->min_align
;
3603 /* we use | since it may have been set already */
3604 has_references
= klass
->has_references
| klass
->parent
->has_references
;
3608 /* We can't really enable 16 bytes alignment until the GC supports it.
3609 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3610 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3611 Bug #506144 is an example of this issue.
3613 if (klass->simd_type)
3618 * When we do generic sharing we need to have layout
3619 * information for open generic classes (either with a generic
3620 * context containing type variables or with a generic
3621 * container), so we don't return in that case anymore.
3624 if (klass
->enumtype
) {
3625 for (i
= 0; i
< top
; i
++) {
3626 field
= &klass
->fields
[i
];
3627 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
3628 klass
->cast_class
= klass
->element_class
= mono_class_from_mono_type_internal (field
->type
);
3633 if (!mono_class_enum_basetype_internal (klass
)) {
3634 mono_class_set_type_load_failure (klass
, "The enumeration's base type is invalid.");
3640 * Enable GC aware auto layout: in this mode, reference
3641 * fields are grouped together inside objects, increasing collector
3643 * Requires that all classes whose layout is known to native code be annotated
3644 * with [StructLayout (LayoutKind.Sequential)]
3645 * Value types have gc_aware_layout disabled by default, as per
3646 * what the default is for other runtimes.
3648 /* corlib is missing [StructLayout] directives in many places */
3649 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
3650 if (!klass
->valuetype
)
3651 gc_aware_layout
= TRUE
;
3654 /* Compute klass->blittable */
3657 blittable
= klass
->parent
->blittable
;
3658 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
&& !(mono_is_corlib_image (klass
->image
) && !strcmp (klass
->name_space
, "System") && !strcmp (klass
->name
, "ValueType")) && top
)
3660 for (i
= 0; i
< top
; i
++) {
3661 field
= &klass
->fields
[i
];
3663 if (mono_field_is_deleted (field
))
3665 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3668 if (field
->type
->byref
|| MONO_TYPE_IS_REFERENCE (field
->type
)) {
3670 } else if (mono_type_is_generic_parameter (field
->type
) &&
3671 mono_class_is_gparam_with_nonblittable_parent (mono_class_from_mono_type_internal (field
->type
))) {
3674 MonoClass
*field_class
= mono_class_from_mono_type_internal (field
->type
);
3676 mono_class_setup_fields (field_class
);
3677 if (mono_class_has_failure (field_class
)) {
3678 ERROR_DECL (field_error
);
3679 mono_error_set_for_class_failure (field_error
, field_class
);
3680 mono_class_set_type_load_failure (klass
, "Could not set up field '%s' due to: %s", field
->name
, mono_error_get_message (field_error
));
3681 mono_error_cleanup (field_error
);
3685 if (!field_class
|| !field_class
->blittable
)
3689 if (klass
->enumtype
)
3690 blittable
= klass
->element_class
->blittable
;
3692 if (mono_class_has_failure (klass
))
3694 if (klass
== mono_defaults
.string_class
)
3697 /* Compute klass->has_references */
3699 * Process non-static fields first, since static fields might recursively
3700 * refer to the class itself.
3702 for (i
= 0; i
< top
; i
++) {
3705 field
= &klass
->fields
[i
];
3707 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
3708 ftype
= mono_type_get_underlying_type (field
->type
);
3709 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3710 if (type_has_references (klass
, ftype
))
3711 has_references
= TRUE
;
3716 * Compute field layout and total size (not considering static fields)
3718 field_offsets
= g_new0 (int, top
);
3719 fields_has_references
= g_new0 (gboolean
, top
);
3720 int first_field_idx
= mono_class_has_static_metadata (klass
) ? mono_class_get_first_field_idx (klass
) : 0;
3722 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
3723 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
3724 if (gc_aware_layout
)
3729 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
)
3732 if (klass
->parent
) {
3733 mono_class_setup_fields (klass
->parent
);
3734 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Cannot initialize parent class"))
3736 real_size
= klass
->parent
->instance_size
;
3738 real_size
= MONO_ABI_SIZEOF (MonoObject
);
3741 for (pass
= 0; pass
< passes
; ++pass
) {
3742 for (i
= 0; i
< top
; i
++){
3747 field
= &klass
->fields
[i
];
3749 if (mono_field_is_deleted (field
))
3751 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3754 ftype
= mono_type_get_underlying_type (field
->type
);
3755 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3756 if (gc_aware_layout
) {
3757 fields_has_references
[i
] = type_has_references (klass
, ftype
);
3758 if (fields_has_references
[i
]) {
3767 if ((top
== 1) && (instance_size
== MONO_ABI_SIZEOF (MonoObject
)) &&
3768 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
3769 /* This field is a hack inserted by MCS to empty structures */
3773 size
= mono_type_size (field
->type
, &align
);
3775 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3776 align
= packing_size
? MIN (packing_size
, align
): align
;
3777 /* if the field has managed references, we need to force-align it
3780 if (type_has_references (klass
, ftype
))
3781 align
= MAX (align
, TARGET_SIZEOF_VOID_P
);
3783 min_align
= MAX (align
, min_align
);
3784 field_offsets
[i
] = real_size
;
3786 field_offsets
[i
] += align
- 1;
3787 field_offsets
[i
] &= ~(align
- 1);
3789 /*TypeBuilders produce all sort of weird things*/
3790 g_assert (image_is_dynamic (klass
->image
) || field_offsets
[i
] > 0);
3791 real_size
= field_offsets
[i
] + size
;
3794 instance_size
= MAX (real_size
, instance_size
);
3796 if (instance_size
& (min_align
- 1)) {
3797 instance_size
+= min_align
- 1;
3798 instance_size
&= ~(min_align
- 1);
3802 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
: {
3806 for (i
= 0; i
< top
; i
++) {
3811 field
= &klass
->fields
[i
];
3814 * There must be info about all the fields in a type if it
3815 * uses explicit layout.
3817 if (mono_field_is_deleted (field
))
3819 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3822 size
= mono_type_size (field
->type
, &align
);
3823 align
= packing_size
? MIN (packing_size
, align
): align
;
3824 min_align
= MAX (align
, min_align
);
3827 /* Already set by typebuilder_setup_fields () */
3828 field_offsets
[i
] = field
->offset
+ MONO_ABI_SIZEOF (MonoObject
);
3830 int idx
= first_field_idx
+ i
;
3832 mono_metadata_field_info (klass
->image
, idx
, &offset
, NULL
, NULL
);
3833 field_offsets
[i
] = offset
+ MONO_ABI_SIZEOF (MonoObject
);
3835 ftype
= mono_type_get_underlying_type (field
->type
);
3836 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3837 if (type_has_references (klass
, ftype
)) {
3838 if (field_offsets
[i
] % TARGET_SIZEOF_VOID_P
) {
3839 mono_class_set_type_load_failure (klass
, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field
->name
);
3846 real_size
= MAX (real_size
, size
+ field_offsets
[i
]);
3849 if (klass
->has_references
) {
3850 ref_bitmap
= g_new0 (guint8
, real_size
/ TARGET_SIZEOF_VOID_P
);
3852 /* Check for overlapping reference and non-reference fields */
3853 for (i
= 0; i
< top
; i
++) {
3856 field
= &klass
->fields
[i
];
3858 if (mono_field_is_deleted (field
))
3860 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3862 ftype
= mono_type_get_underlying_type (field
->type
);
3863 if (MONO_TYPE_IS_REFERENCE (ftype
))
3864 ref_bitmap
[field_offsets
[i
] / TARGET_SIZEOF_VOID_P
] = 1;
3866 for (i
= 0; i
< top
; i
++) {
3867 field
= &klass
->fields
[i
];
3869 if (mono_field_is_deleted (field
))
3871 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3874 // FIXME: Too much code does this
3876 if (!MONO_TYPE_IS_REFERENCE (field
->type
) && ref_bitmap
[field_offsets
[i
] / TARGET_SIZEOF_VOID_P
]) {
3877 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
]);
3881 g_free (ref_bitmap
);
3884 instance_size
= MAX (real_size
, instance_size
);
3885 if (!((layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) && explicit_size
)) {
3886 if (instance_size
& (min_align
- 1)) {
3887 instance_size
+= min_align
- 1;
3888 instance_size
&= ~(min_align
- 1);
3895 if (layout
!= TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
3897 * This leads to all kinds of problems with nested structs, so only
3898 * enable it when a MONO_DEBUG property is set.
3900 * For small structs, set min_align to at least the struct size to improve
3901 * performance, and since the JIT memset/memcpy code assumes this and generates
3902 * unaligned accesses otherwise. See #78990 for a testcase.
3904 if (mono_align_small_structs
&& top
) {
3905 if (instance_size
<= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
))
3906 min_align
= MAX (min_align
, instance_size
- MONO_ABI_SIZEOF (MonoObject
));
3910 MonoType
*klass_byval_arg
= m_class_get_byval_arg (klass
);
3911 if (klass_byval_arg
->type
== MONO_TYPE_VAR
|| klass_byval_arg
->type
== MONO_TYPE_MVAR
)
3912 instance_size
= MONO_ABI_SIZEOF (MonoObject
) + mono_type_size (klass_byval_arg
, &min_align
);
3913 else if (klass_byval_arg
->type
== MONO_TYPE_PTR
)
3914 instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
3916 if (klass_byval_arg
->type
== MONO_TYPE_SZARRAY
|| klass_byval_arg
->type
== MONO_TYPE_ARRAY
)
3917 element_size
= mono_class_array_element_size (klass
->element_class
);
3919 /* Publish the data */
3920 mono_loader_lock ();
3921 if (klass
->instance_size
&& !klass
->image
->dynamic
) {
3922 /* Might be already set using cached info */
3923 if (klass
->instance_size
!= instance_size
) {
3924 /* Emit info to help debugging */
3925 g_print ("%s\n", mono_class_full_name (klass
));
3926 g_print ("%d %d %d %d\n", klass
->instance_size
, instance_size
, klass
->blittable
, blittable
);
3927 g_print ("%d %d %d %d\n", klass
->has_references
, has_references
, klass
->packing_size
, packing_size
);
3928 g_print ("%d %d\n", klass
->min_align
, min_align
);
3929 for (i
= 0; i
< top
; ++i
) {
3930 field
= &klass
->fields
[i
];
3931 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3932 printf (" %s %d %d %d\n", klass
->fields
[i
].name
, klass
->fields
[i
].offset
, field_offsets
[i
], fields_has_references
[i
]);
3935 g_assert (klass
->instance_size
== instance_size
);
3937 klass
->instance_size
= instance_size
;
3939 klass
->blittable
= blittable
;
3940 klass
->has_references
= has_references
;
3941 klass
->packing_size
= packing_size
;
3942 klass
->min_align
= min_align
;
3943 for (i
= 0; i
< top
; ++i
) {
3944 field
= &klass
->fields
[i
];
3945 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3946 klass
->fields
[i
].offset
= field_offsets
[i
];
3949 if (klass_byval_arg
->type
== MONO_TYPE_SZARRAY
|| klass_byval_arg
->type
== MONO_TYPE_ARRAY
)
3950 klass
->sizes
.element_size
= element_size
;
3952 mono_memory_barrier ();
3953 klass
->size_inited
= 1;
3954 mono_loader_unlock ();
3957 * Compute static field layout and size
3958 * Static fields can reference the class itself, so this has to be
3959 * done after instance_size etc. are initialized.
3962 for (i
= 0; i
< top
; i
++) {
3966 field
= &klass
->fields
[i
];
3968 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) || field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
3970 if (mono_field_is_deleted (field
))
3973 if (mono_type_has_exceptions (field
->type
)) {
3974 mono_class_set_type_load_failure (klass
, "Field '%s' has an invalid type.", field
->name
);
3978 has_static_fields
= TRUE
;
3980 size
= mono_type_size (field
->type
, &align
);
3981 field_offsets
[i
] = class_size
;
3982 /*align is always non-zero here*/
3983 field_offsets
[i
] += align
- 1;
3984 field_offsets
[i
] &= ~(align
- 1);
3985 class_size
= field_offsets
[i
] + size
;
3988 if (has_static_fields
&& class_size
== 0)
3989 /* Simplify code which depends on class_size != 0 if the class has static fields */
3992 /* Compute klass->has_static_refs */
3993 has_static_refs
= FALSE
;
3994 for (i
= 0; i
< top
; i
++) {
3997 field
= &klass
->fields
[i
];
3999 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
4000 ftype
= mono_type_get_underlying_type (field
->type
);
4001 ftype
= mono_type_get_basic_type_from_generic (ftype
);
4002 if (type_has_references (klass
, ftype
))
4003 has_static_refs
= TRUE
;
4007 /*valuetypes can't be neither bigger than 1Mb or empty. */
4008 if (klass
->valuetype
&& (klass
->instance_size
<= 0 || klass
->instance_size
> (0x100000 + MONO_ABI_SIZEOF (MonoObject
)))) {
4009 /* Special case compiler generated types */
4010 /* Hard to check for [CompilerGenerated] here */
4011 if (!strstr (klass
->name
, "StaticArrayInitTypeSize") && !strstr (klass
->name
, "$ArrayType"))
4012 mono_class_set_type_load_failure (klass
, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass
->instance_size
);
4015 // Weak field support
4018 // - generic instances
4019 // - Disallow on structs/static fields/nonref fields
4020 gboolean has_weak_fields
= FALSE
;
4022 if (mono_class_has_static_metadata (klass
)) {
4023 for (MonoClass
*p
= klass
; p
!= NULL
; p
= p
->parent
) {
4024 gpointer iter
= NULL
;
4025 guint32 first_field_idx
= mono_class_get_first_field_idx (p
);
4027 while ((field
= mono_class_get_fields_internal (p
, &iter
))) {
4028 guint32 field_idx
= first_field_idx
+ (field
- p
->fields
);
4029 if (MONO_TYPE_IS_REFERENCE (field
->type
) && mono_assembly_is_weak_field (p
->image
, field_idx
+ 1)) {
4030 has_weak_fields
= TRUE
;
4031 mono_trace_message (MONO_TRACE_TYPE
, "Field %s:%s at offset %x is weak.", field
->parent
->name
, field
->name
, field
->offset
);
4038 * Check that any fields of IsByRefLike type are instance
4039 * fields and only inside other IsByRefLike structs.
4041 * (Has to be done late because we call
4042 * mono_class_from_mono_type_internal which may recursively
4043 * refer to the current class)
4045 gboolean allow_isbyreflike_fields
= m_class_is_byreflike (klass
);
4046 for (i
= 0; i
< top
; i
++) {
4047 field
= &klass
->fields
[i
];
4049 if (mono_field_is_deleted (field
))
4051 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
4053 MonoClass
*field_class
= NULL
;
4054 /* have to be careful not to recursively invoke mono_class_init on a static field.
4055 * for example - if the field is an array of a subclass of klass, we can loop.
4057 switch (field
->type
->type
) {
4058 case MONO_TYPE_TYPEDBYREF
:
4059 case MONO_TYPE_VALUETYPE
:
4060 case MONO_TYPE_GENERICINST
:
4061 field_class
= mono_class_from_mono_type_internal (field
->type
);
4066 if (!field_class
|| !m_class_is_byreflike (field_class
))
4068 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
4069 mono_class_set_type_load_failure (klass
, "Static ByRefLike field '%s' is not allowed", field
->name
);
4072 /* instance field */
4073 if (allow_isbyreflike_fields
)
4075 mono_class_set_type_load_failure (klass
, "Instance ByRefLike field '%s' not in a ref struct", field
->name
);
4080 /* Publish the data */
4081 mono_loader_lock ();
4083 klass
->sizes
.class_size
= class_size
;
4084 klass
->has_static_refs
= has_static_refs
;
4085 klass
->has_weak_fields
= has_weak_fields
;
4086 for (i
= 0; i
< top
; ++i
) {
4087 field
= &klass
->fields
[i
];
4089 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4090 field
->offset
= field_offsets
[i
];
4092 mono_memory_barrier ();
4093 klass
->fields_inited
= 1;
4094 mono_loader_unlock ();
4096 g_free (field_offsets
);
4097 g_free (fields_has_references
);
4100 static int finalize_slot
= -1;
4103 initialize_object_slots (MonoClass
*klass
)
4107 if (klass
!= mono_defaults
.object_class
|| finalize_slot
>= 0)
4110 mono_class_setup_vtable (klass
);
4112 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
4113 if (!strcmp (klass
->vtable
[i
]->name
, "Finalize")) {
4114 int const j
= finalize_slot
;
4115 g_assert (j
== -1 || j
== i
);
4120 g_assert (finalize_slot
>= 0);
4124 mono_class_get_object_finalize_slot ()
4126 return finalize_slot
;
4130 mono_class_get_default_finalize_method ()
4132 int const i
= finalize_slot
;
4133 return (i
< 0) ? NULL
: mono_defaults
.object_class
->vtable
[i
];
4137 MonoMethod
*array_method
;
4139 } GenericArrayMethodInfo
;
4141 static int generic_array_method_num
= 0;
4142 static GenericArrayMethodInfo
*generic_array_method_info
= NULL
;
4145 setup_generic_array_ifaces (MonoClass
*klass
, MonoClass
*iface
, MonoMethod
**methods
, int pos
, GHashTable
*cache
)
4147 MonoGenericContext tmp_context
;
4148 MonoGenericClass
*gclass
;
4151 // The interface can sometimes be a GTD in cases like IList
4152 // See: https://github.com/mono/mono/issues/7095#issuecomment-470465597
4153 if (mono_class_is_gtd (iface
)) {
4154 MonoType
*ty
= mono_class_gtd_get_canonical_inst (iface
);
4155 g_assert (ty
->type
== MONO_TYPE_GENERICINST
);
4156 gclass
= ty
->data
.generic_class
;
4158 gclass
= mono_class_get_generic_class (iface
);
4160 tmp_context
.class_inst
= NULL
;
4161 tmp_context
.method_inst
= gclass
->context
.class_inst
;
4162 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4164 for (i
= 0; i
< generic_array_method_num
; i
++) {
4166 MonoMethod
*m
= generic_array_method_info
[i
].array_method
;
4167 MonoMethod
*inflated
, *helper
;
4169 inflated
= mono_class_inflate_generic_method_checked (m
, &tmp_context
, error
);
4170 mono_error_assert_ok (error
);
4171 helper
= (MonoMethod
*)g_hash_table_lookup (cache
, inflated
);
4173 helper
= mono_marshal_get_generic_array_helper (klass
, generic_array_method_info
[i
].name
, inflated
);
4174 g_hash_table_insert (cache
, inflated
, helper
);
4176 methods
[pos
++] = helper
;
4181 generic_array_methods (MonoClass
*klass
)
4183 int i
, count_generic
= 0, mcount
;
4184 GList
*list
= NULL
, *tmp
;
4185 if (generic_array_method_num
)
4186 return generic_array_method_num
;
4187 mono_class_setup_methods (klass
->parent
); /*This is setting up System.Array*/
4188 g_assert (!mono_class_has_failure (klass
->parent
)); /*So hitting this assert is a huge problem*/
4189 mcount
= mono_class_get_method_count (klass
->parent
);
4190 for (i
= 0; i
< mcount
; i
++) {
4191 MonoMethod
*m
= klass
->parent
->methods
[i
];
4192 if (!strncmp (m
->name
, "InternalArray__", 15)) {
4194 list
= g_list_prepend (list
, m
);
4197 list
= g_list_reverse (list
);
4198 generic_array_method_info
= (GenericArrayMethodInfo
*)mono_image_alloc (mono_defaults
.corlib
, sizeof (GenericArrayMethodInfo
) * count_generic
);
4200 for (tmp
= list
; tmp
; tmp
= tmp
->next
) {
4201 const char *mname
, *iname
;
4203 MonoMethod
*m
= (MonoMethod
*)tmp
->data
;
4204 const char *ireadonlylist_prefix
= "InternalArray__IReadOnlyList_";
4205 const char *ireadonlycollection_prefix
= "InternalArray__IReadOnlyCollection_";
4207 generic_array_method_info
[i
].array_method
= m
;
4208 if (!strncmp (m
->name
, "InternalArray__ICollection_", 27)) {
4209 iname
= "System.Collections.Generic.ICollection`1.";
4210 mname
= m
->name
+ 27;
4211 } else if (!strncmp (m
->name
, "InternalArray__IEnumerable_", 27)) {
4212 iname
= "System.Collections.Generic.IEnumerable`1.";
4213 mname
= m
->name
+ 27;
4214 } else if (!strncmp (m
->name
, ireadonlylist_prefix
, strlen (ireadonlylist_prefix
))) {
4215 iname
= "System.Collections.Generic.IReadOnlyList`1.";
4216 mname
= m
->name
+ strlen (ireadonlylist_prefix
);
4217 } else if (!strncmp (m
->name
, ireadonlycollection_prefix
, strlen (ireadonlycollection_prefix
))) {
4218 iname
= "System.Collections.Generic.IReadOnlyCollection`1.";
4219 mname
= m
->name
+ strlen (ireadonlycollection_prefix
);
4220 } else if (!strncmp (m
->name
, "InternalArray__", 15)) {
4221 iname
= "System.Collections.Generic.IList`1.";
4222 mname
= m
->name
+ 15;
4224 g_assert_not_reached ();
4227 name
= (gchar
*)mono_image_alloc (mono_defaults
.corlib
, strlen (iname
) + strlen (mname
) + 1);
4228 strcpy (name
, iname
);
4229 strcpy (name
+ strlen (iname
), mname
);
4230 generic_array_method_info
[i
].name
= name
;
4233 /*g_print ("array generic methods: %d\n", count_generic);*/
4235 generic_array_method_num
= count_generic
;
4237 return generic_array_method_num
;
4241 * Global pool of interface IDs, represented as a bitset.
4242 * LOCKING: Protected by the classes lock.
4244 static MonoBitSet
*global_interface_bitset
= NULL
;
4247 * mono_unload_interface_ids:
4248 * @bitset: bit set of interface IDs
4250 * When an image is unloaded, the interface IDs associated with
4251 * the image are put back in the global pool of IDs so the numbers
4255 mono_unload_interface_ids (MonoBitSet
*bitset
)
4258 mono_bitset_sub (global_interface_bitset
, bitset
);
4263 mono_unload_interface_id (MonoClass
*klass
)
4265 if (global_interface_bitset
&& klass
->interface_id
) {
4267 mono_bitset_clear (global_interface_bitset
, klass
->interface_id
);
4273 * mono_get_unique_iid:
4274 * \param klass interface
4276 * Assign a unique integer ID to the interface represented by \p klass.
4277 * The ID will positive and as small as possible.
4278 * LOCKING: Acquires the classes lock.
4279 * \returns The new ID.
4282 mono_get_unique_iid (MonoClass
*klass
)
4286 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
));
4290 if (!global_interface_bitset
) {
4291 global_interface_bitset
= mono_bitset_new (128, 0);
4292 mono_bitset_set (global_interface_bitset
, 0); //don't let 0 be a valid iid
4295 iid
= mono_bitset_find_first_unset (global_interface_bitset
, -1);
4297 int old_size
= mono_bitset_size (global_interface_bitset
);
4298 MonoBitSet
*new_set
= mono_bitset_clone (global_interface_bitset
, old_size
* 2);
4299 mono_bitset_free (global_interface_bitset
);
4300 global_interface_bitset
= new_set
;
4303 mono_bitset_set (global_interface_bitset
, iid
);
4304 /* set the bit also in the per-image set */
4305 if (!mono_class_is_ginst (klass
)) {
4306 if (klass
->image
->interface_bitset
) {
4307 if (iid
>= mono_bitset_size (klass
->image
->interface_bitset
)) {
4308 MonoBitSet
*new_set
= mono_bitset_clone (klass
->image
->interface_bitset
, iid
+ 1);
4309 mono_bitset_free (klass
->image
->interface_bitset
);
4310 klass
->image
->interface_bitset
= new_set
;
4313 klass
->image
->interface_bitset
= mono_bitset_new (iid
+ 1, 0);
4315 mono_bitset_set (klass
->image
->interface_bitset
, iid
);
4320 #ifndef MONO_SMALL_CONFIG
4321 if (mono_print_vtable
) {
4323 char *type_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
4324 MonoGenericClass
*gklass
= mono_class_try_get_generic_class (klass
);
4325 if (gklass
&& !gklass
->context
.class_inst
->is_open
) {
4326 generic_id
= gklass
->context
.class_inst
->id
;
4327 g_assert (generic_id
!= 0);
4331 printf ("Interface: assigned id %d to %s|%s|%d\n", iid
, klass
->image
->assembly_name
, type_name
, generic_id
);
4336 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4337 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4338 g_assert (iid
< INT_MAX
);
4343 * mono_class_init_internal:
4344 * \param klass the class to initialize
4346 * Compute the \c instance_size, \c class_size and other infos that cannot be
4347 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4348 * Initializes the following fields in \p klass:
4349 * - all the fields initialized by \c mono_class_init_sizes
4354 * LOCKING: Acquires the loader lock.
4356 * \returns TRUE on success or FALSE if there was a problem in loading
4357 * the type (incorrect assemblies, missing assemblies, methods, etc).
4360 mono_class_init_internal (MonoClass
*klass
)
4362 int i
, vtable_size
= 0, array_method_count
= 0;
4363 MonoCachedClassInfo cached_info
;
4364 gboolean has_cached_info
;
4365 gboolean locked
= FALSE
;
4366 gboolean ghcimpl
= FALSE
;
4367 gboolean has_cctor
= FALSE
;
4368 int first_iface_slot
= 0;
4372 /* Double-checking locking pattern */
4373 if (klass
->inited
|| mono_class_has_failure (klass
))
4374 return !mono_class_has_failure (klass
);
4376 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4379 * This function can recursively call itself.
4381 GSList
*init_list
= (GSList
*)mono_native_tls_get_value (init_pending_tls_id
);
4382 if (g_slist_find (init_list
, klass
)) {
4383 mono_class_set_type_load_failure (klass
, "Recursive type definition detected %s.%s", klass
->name_space
, klass
->name
);
4384 goto leave_no_init_pending
;
4386 init_list
= g_slist_prepend (init_list
, klass
);
4387 mono_native_tls_set_value (init_pending_tls_id
, init_list
);
4390 * We want to avoid doing complicated work inside locks, so we compute all the required
4391 * information and write it to @klass inside a lock.
4394 if (mono_verifier_is_enabled_for_class (klass
) && !mono_verifier_verify_class (klass
)) {
4395 mono_class_set_type_load_failure (klass
, "%s", concat_two_strings_with_zero (klass
->image
, klass
->name
, klass
->image
->assembly_name
));
4399 MonoType
*klass_byval_arg
;
4400 klass_byval_arg
= m_class_get_byval_arg (klass
);
4401 if (klass_byval_arg
->type
== MONO_TYPE_ARRAY
|| klass_byval_arg
->type
== MONO_TYPE_SZARRAY
) {
4402 MonoClass
*element_class
= klass
->element_class
;
4403 MonoClass
*cast_class
= klass
->cast_class
;
4405 if (!element_class
->inited
)
4406 mono_class_init_internal (element_class
);
4407 if (mono_class_set_type_load_failure_causedby_class (klass
, element_class
, "Could not load array element class"))
4409 if (!cast_class
->inited
)
4410 mono_class_init_internal (cast_class
);
4411 if (mono_class_set_type_load_failure_causedby_class (klass
, cast_class
, "Could not load array cast class"))
4415 UnlockedIncrement (&mono_stats
.initialized_class_count
);
4417 if (mono_class_is_ginst (klass
) && !mono_class_get_generic_class (klass
)->is_dynamic
) {
4418 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4420 mono_class_init_internal (gklass
);
4421 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic Type Definition failed to init"))
4424 mono_loader_lock ();
4425 mono_class_setup_interface_id_internal (klass
);
4426 mono_loader_unlock ();
4429 if (klass
->parent
&& !klass
->parent
->inited
)
4430 mono_class_init_internal (klass
->parent
);
4432 has_cached_info
= mono_class_get_cached_class_info (klass
, &cached_info
);
4434 /* Compute instance size etc. */
4435 init_sizes_with_info (klass
, has_cached_info
? &cached_info
: NULL
);
4436 if (mono_class_has_failure (klass
))
4439 mono_class_setup_supertypes (klass
);
4441 initialize_object_slots (klass
);
4444 * Initialize the rest of the data without creating a generic vtable if possible.
4445 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4446 * also avoid computing a generic vtable.
4448 if (has_cached_info
) {
4450 vtable_size
= cached_info
.vtable_size
;
4451 ghcimpl
= cached_info
.ghcimpl
;
4452 has_cctor
= cached_info
.has_cctor
;
4453 } else if (klass
->rank
== 1 && klass_byval_arg
->type
== MONO_TYPE_SZARRAY
) {
4454 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4455 * The first slot if for array with.
4457 static int szarray_vtable_size
[3] = { 0 };
4461 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass
))))
4463 else if (klass
->element_class
->enumtype
)
4469 if (!szarray_vtable_size
[slot
]) {
4470 mono_class_setup_vtable (klass
);
4471 szarray_vtable_size
[slot
] = klass
->vtable_size
;
4472 vtable_size
= klass
->vtable_size
;
4474 vtable_size
= szarray_vtable_size
[slot
];
4476 } else if (mono_class_is_ginst (klass
) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
4477 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4479 /* Generic instance case */
4480 ghcimpl
= gklass
->ghcimpl
;
4481 has_cctor
= gklass
->has_cctor
;
4483 mono_class_setup_vtable (gklass
);
4484 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to init"))
4487 vtable_size
= gklass
->vtable_size
;
4491 /* C# doesn't allow interfaces to have cctors */
4492 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || klass
->image
!= mono_defaults
.corlib
) {
4493 MonoMethod
*cmethod
= NULL
;
4495 if (mono_class_is_ginst (klass
)) {
4496 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4498 /* Generic instance case */
4499 ghcimpl
= gklass
->ghcimpl
;
4500 has_cctor
= gklass
->has_cctor
;
4501 } else if (klass
->type_token
&& !image_is_dynamic(klass
->image
)) {
4502 cmethod
= mono_find_method_in_metadata (klass
, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME
);
4503 /* The find_method function ignores the 'flags' argument */
4504 if (cmethod
&& (cmethod
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
))
4507 mono_class_setup_methods (klass
);
4508 if (mono_class_has_failure (klass
))
4511 int mcount
= mono_class_get_method_count (klass
);
4512 for (i
= 0; i
< mcount
; ++i
) {
4513 MonoMethod
*method
= klass
->methods
[i
];
4514 if ((method
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) &&
4515 (strcmp (".cctor", method
->name
) == 0)) {
4525 array_method_count
= 3 + (klass
->rank
> 1? 2: 1);
4527 if (klass
->interface_count
) {
4528 int count_generic
= generic_array_methods (klass
);
4529 array_method_count
+= klass
->interface_count
* count_generic
;
4533 if (klass
->parent
) {
4534 if (!klass
->parent
->vtable_size
)
4535 mono_class_setup_vtable (klass
->parent
);
4536 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Parent class vtable failed to initialize"))
4538 g_assert (klass
->parent
->vtable_size
);
4539 first_iface_slot
= klass
->parent
->vtable_size
;
4540 if (mono_class_need_stelemref_method (klass
))
4545 * Do the actual changes to @klass inside the loader lock
4547 mono_loader_lock ();
4550 if (klass
->inited
|| mono_class_has_failure (klass
)) {
4551 /* Somebody might have gotten in before us */
4555 UnlockedIncrement (&mono_stats
.initialized_class_count
);
4557 if (mono_class_is_ginst (klass
) && !mono_class_get_generic_class (klass
)->is_dynamic
)
4558 UnlockedIncrement (&mono_stats
.generic_class_count
);
4560 if (mono_class_is_ginst (klass
) || image_is_dynamic (klass
->image
) || !klass
->type_token
|| (has_cached_info
&& !cached_info
.has_nested_classes
))
4561 klass
->nested_classes_inited
= TRUE
;
4562 klass
->ghcimpl
= ghcimpl
;
4563 klass
->has_cctor
= has_cctor
;
4565 klass
->vtable_size
= vtable_size
;
4566 if (has_cached_info
) {
4567 klass
->has_finalize
= cached_info
.has_finalize
;
4568 klass
->has_finalize_inited
= TRUE
;
4571 mono_class_set_method_count (klass
, array_method_count
);
4573 mono_loader_unlock ();
4576 setup_interface_offsets (klass
, first_iface_slot
, TRUE
);
4578 if (mono_security_core_clr_enabled ())
4579 mono_security_core_clr_check_inheritance (klass
);
4581 if (mono_class_is_ginst (klass
) && !mono_verifier_class_is_valid_generic_instantiation (klass
))
4582 mono_class_set_type_load_failure (klass
, "Invalid generic instantiation");
4587 init_list
= (GSList
*)mono_native_tls_get_value (init_pending_tls_id
);
4588 init_list
= g_slist_remove (init_list
, klass
);
4589 mono_native_tls_set_value (init_pending_tls_id
, init_list
);
4591 leave_no_init_pending
:
4593 mono_loader_unlock ();
4595 /* Leave this for last */
4596 mono_loader_lock ();
4598 mono_loader_unlock ();
4600 return !mono_class_has_failure (klass
);
4604 mono_class_init_checked (MonoClass
*klass
, MonoError
*error
)
4607 gboolean
const success
= mono_class_init_internal (klass
);
4609 mono_error_set_for_class_failure (error
, klass
);
4615 * COM initialization is delayed until needed.
4616 * However when a [ComImport] attribute is present on a type it will trigger
4617 * the initialization. This is not a problem unless the BCL being executed
4618 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4621 init_com_from_comimport (MonoClass
*klass
)
4623 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4624 if (mono_security_core_clr_enabled ()) {
4625 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4626 if (!mono_security_core_clr_determine_platform_image (klass
->image
)) {
4627 /* but it can not be made available for application (i.e. user code) since all COM calls
4628 * are considered native calls. In this case we fail with a TypeLoadException (just like
4629 * Silverlight 2 does */
4630 mono_class_set_type_load_failure (klass
, "");
4635 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4637 #endif /*DISABLE_COM*/
4640 * LOCKING: this assumes the loader lock is held
4643 mono_class_setup_parent (MonoClass
*klass
, MonoClass
*parent
)
4645 gboolean system_namespace
;
4646 gboolean is_corlib
= mono_is_corlib_image (klass
->image
);
4648 system_namespace
= !strcmp (klass
->name_space
, "System") && is_corlib
;
4650 /* if root of the hierarchy */
4651 if (system_namespace
&& !strcmp (klass
->name
, "Object")) {
4652 klass
->parent
= NULL
;
4653 klass
->instance_size
= MONO_ABI_SIZEOF (MonoObject
);
4656 if (!strcmp (klass
->name
, "<Module>")) {
4657 klass
->parent
= NULL
;
4658 klass
->instance_size
= 0;
4662 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
4663 /* Imported COM Objects always derive from __ComObject. */
4665 if (MONO_CLASS_IS_IMPORT (klass
)) {
4666 init_com_from_comimport (klass
);
4667 if (parent
== mono_defaults
.object_class
)
4668 parent
= mono_class_get_com_object_class ();
4672 /* set the parent to something useful and safe, but mark the type as broken */
4673 parent
= mono_defaults
.object_class
;
4674 mono_class_set_type_load_failure (klass
, "");
4678 klass
->parent
= parent
;
4680 if (mono_class_is_ginst (parent
) && !parent
->name
) {
4682 * If the parent is a generic instance, we may get
4683 * called before it is fully initialized, especially
4684 * before it has its name.
4689 #ifndef DISABLE_REMOTING
4690 klass
->marshalbyref
= parent
->marshalbyref
;
4691 klass
->contextbound
= parent
->contextbound
;
4694 klass
->delegate
= parent
->delegate
;
4696 if (MONO_CLASS_IS_IMPORT (klass
) || mono_class_is_com_object (parent
))
4697 mono_class_set_is_com_object (klass
);
4699 if (system_namespace
) {
4700 #ifndef DISABLE_REMOTING
4701 if (klass
->name
[0] == 'M' && !strcmp (klass
->name
, "MarshalByRefObject"))
4702 klass
->marshalbyref
= 1;
4704 if (klass
->name
[0] == 'C' && !strcmp (klass
->name
, "ContextBoundObject"))
4705 klass
->contextbound
= 1;
4707 if (klass
->name
[0] == 'D' && !strcmp (klass
->name
, "Delegate"))
4708 klass
->delegate
= 1;
4711 if (klass
->parent
->enumtype
|| (mono_is_corlib_image (klass
->parent
->image
) && (strcmp (klass
->parent
->name
, "ValueType") == 0) &&
4712 (strcmp (klass
->parent
->name_space
, "System") == 0)))
4713 klass
->valuetype
= 1;
4714 if (mono_is_corlib_image (klass
->parent
->image
) && ((strcmp (klass
->parent
->name
, "Enum") == 0) && (strcmp (klass
->parent
->name_space
, "System") == 0))) {
4715 klass
->valuetype
= klass
->enumtype
= 1;
4717 /*klass->enumtype = klass->parent->enumtype; */
4719 /* initialize com types if COM interfaces are present */
4721 if (MONO_CLASS_IS_IMPORT (klass
))
4722 init_com_from_comimport (klass
);
4724 klass
->parent
= NULL
;
4729 /* Locking: must be called with the loader lock held. */
4731 mono_class_setup_interface_id_internal (MonoClass
*klass
)
4733 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || klass
->interface_id
)
4735 klass
->interface_id
= mono_get_unique_iid (klass
);
4737 if (mono_is_corlib_image (klass
->image
) && !strcmp (m_class_get_name_space (klass
), "System.Collections.Generic")) {
4738 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4739 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4740 * MS returns diferrent types based on which instance is called. For example:
4741 * object obj = new byte[10][];
4742 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4743 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4746 const char *name
= m_class_get_name (klass
);
4747 if (!strcmp (name
, "IList`1") || !strcmp (name
, "ICollection`1") || !strcmp (name
, "IEnumerable`1") || !strcmp (name
, "IEnumerator`1"))
4748 klass
->is_array_special_interface
= 1;
4754 * LOCKING: this assumes the loader lock is held
4757 mono_class_setup_mono_type (MonoClass
*klass
)
4759 const char *name
= klass
->name
;
4760 const char *nspace
= klass
->name_space
;
4761 gboolean is_corlib
= mono_is_corlib_image (klass
->image
);
4763 klass
->this_arg
.byref
= 1;
4764 klass
->this_arg
.data
.klass
= klass
;
4765 klass
->this_arg
.type
= MONO_TYPE_CLASS
;
4766 klass
->_byval_arg
.data
.klass
= klass
;
4767 klass
->_byval_arg
.type
= MONO_TYPE_CLASS
;
4769 if (is_corlib
&& !strcmp (nspace
, "System")) {
4770 if (!strcmp (name
, "ValueType")) {
4772 * do not set the valuetype bit for System.ValueType.
4773 * klass->valuetype = 1;
4775 klass
->blittable
= TRUE
;
4776 } else if (!strcmp (name
, "Enum")) {
4778 * do not set the valuetype bit for System.Enum.
4779 * klass->valuetype = 1;
4781 klass
->valuetype
= 0;
4782 klass
->enumtype
= 0;
4783 } else if (!strcmp (name
, "Object")) {
4784 klass
->_byval_arg
.type
= MONO_TYPE_OBJECT
;
4785 klass
->this_arg
.type
= MONO_TYPE_OBJECT
;
4786 } else if (!strcmp (name
, "String")) {
4787 klass
->_byval_arg
.type
= MONO_TYPE_STRING
;
4788 klass
->this_arg
.type
= MONO_TYPE_STRING
;
4789 } else if (!strcmp (name
, "TypedReference")) {
4790 klass
->_byval_arg
.type
= MONO_TYPE_TYPEDBYREF
;
4791 klass
->this_arg
.type
= MONO_TYPE_TYPEDBYREF
;
4795 if (klass
->valuetype
) {
4796 int t
= MONO_TYPE_VALUETYPE
;
4798 if (is_corlib
&& !strcmp (nspace
, "System")) {
4801 if (!strcmp (name
, "Boolean")) {
4802 t
= MONO_TYPE_BOOLEAN
;
4803 } else if (!strcmp(name
, "Byte")) {
4805 klass
->blittable
= TRUE
;
4809 if (!strcmp (name
, "Char")) {
4814 if (!strcmp (name
, "Double")) {
4816 klass
->blittable
= TRUE
;
4820 if (!strcmp (name
, "Int32")) {
4822 klass
->blittable
= TRUE
;
4823 } else if (!strcmp(name
, "Int16")) {
4825 klass
->blittable
= TRUE
;
4826 } else if (!strcmp(name
, "Int64")) {
4828 klass
->blittable
= TRUE
;
4829 } else if (!strcmp(name
, "IntPtr")) {
4831 klass
->blittable
= TRUE
;
4835 if (!strcmp (name
, "Single")) {
4837 klass
->blittable
= TRUE
;
4838 } else if (!strcmp(name
, "SByte")) {
4840 klass
->blittable
= TRUE
;
4844 if (!strcmp (name
, "UInt32")) {
4846 klass
->blittable
= TRUE
;
4847 } else if (!strcmp(name
, "UInt16")) {
4849 klass
->blittable
= TRUE
;
4850 } else if (!strcmp(name
, "UInt64")) {
4852 klass
->blittable
= TRUE
;
4853 } else if (!strcmp(name
, "UIntPtr")) {
4855 klass
->blittable
= TRUE
;
4859 if (!strcmp (name
, "TypedReference")) {
4860 t
= MONO_TYPE_TYPEDBYREF
;
4861 klass
->blittable
= TRUE
;
4865 if (!strcmp (name
, "Void")) {
4873 klass
->_byval_arg
.type
= (MonoTypeEnum
)t
;
4874 klass
->this_arg
.type
= (MonoTypeEnum
)t
;
4877 mono_class_setup_interface_id_internal (klass
);
4881 create_array_method (MonoClass
*klass
, const char *name
, MonoMethodSignature
*sig
)
4885 method
= (MonoMethod
*) mono_image_alloc0 (klass
->image
, sizeof (MonoMethodPInvoke
));
4886 method
->klass
= klass
;
4887 method
->flags
= METHOD_ATTRIBUTE_PUBLIC
;
4888 method
->iflags
= METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
;
4889 method
->signature
= sig
;
4890 method
->name
= name
;
4893 if (name
[0] == '.') {
4894 method
->flags
|= METHOD_ATTRIBUTE_RT_SPECIAL_NAME
| METHOD_ATTRIBUTE_SPECIAL_NAME
;
4896 method
->iflags
|= METHOD_IMPL_ATTRIBUTE_RUNTIME
;
4902 * mono_class_setup_methods:
4905 * Initializes the 'methods' array in CLASS.
4906 * Calling this method should be avoided if possible since it allocates a lot
4907 * of long-living MonoMethod structures.
4908 * Methods belonging to an interface are assigned a sequential slot starting
4911 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4914 mono_class_setup_methods (MonoClass
*klass
)
4917 MonoMethod
**methods
;
4922 if (mono_class_is_ginst (klass
)) {
4924 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4926 mono_class_init_internal (gklass
);
4927 if (!mono_class_has_failure (gklass
))
4928 mono_class_setup_methods (gklass
);
4929 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
4932 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4933 count
= mono_class_get_method_count (gklass
);
4934 methods
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (MonoMethod
*) * (count
+ 1));
4936 for (i
= 0; i
< count
; i
++) {
4937 methods
[i
] = mono_class_inflate_generic_method_full_checked (
4938 gklass
->methods
[i
], klass
, mono_class_get_context (klass
), error
);
4939 if (!is_ok (error
)) {
4940 char *method
= mono_method_full_name (gklass
->methods
[i
], TRUE
);
4941 mono_class_set_type_load_failure (klass
, "Could not inflate method %s due to %s", method
, mono_error_get_message (error
));
4944 mono_error_cleanup (error
);
4948 } else if (klass
->rank
) {
4950 MonoMethod
*amethod
;
4951 MonoMethodSignature
*sig
;
4952 int count_generic
= 0, first_generic
= 0;
4954 gboolean jagged_ctor
= FALSE
;
4956 count
= 3 + (klass
->rank
> 1? 2: 1);
4958 mono_class_setup_interfaces (klass
, error
);
4959 g_assert (is_ok (error
)); /*FIXME can this fail for array types?*/
4961 if (klass
->rank
== 1 && klass
->element_class
->rank
) {
4966 if (klass
->interface_count
) {
4967 count_generic
= generic_array_methods (klass
);
4968 first_generic
= count
;
4969 count
+= klass
->interface_count
* count_generic
;
4972 methods
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (MonoMethod
*) * count
);
4974 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
4975 sig
->ret
= mono_get_void_type ();
4976 sig
->pinvoke
= TRUE
;
4977 sig
->hasthis
= TRUE
;
4978 for (i
= 0; i
< klass
->rank
; ++i
)
4979 sig
->params
[i
] = mono_get_int32_type ();
4981 amethod
= create_array_method (klass
, ".ctor", sig
);
4982 methods
[method_num
++] = amethod
;
4983 if (klass
->rank
> 1) {
4984 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
* 2);
4985 sig
->ret
= mono_get_void_type ();
4986 sig
->pinvoke
= TRUE
;
4987 sig
->hasthis
= TRUE
;
4988 for (i
= 0; i
< klass
->rank
* 2; ++i
)
4989 sig
->params
[i
] = mono_get_int32_type ();
4991 amethod
= create_array_method (klass
, ".ctor", sig
);
4992 methods
[method_num
++] = amethod
;
4996 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4997 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
+ 1);
4998 sig
->ret
= mono_get_void_type ();
4999 sig
->pinvoke
= TRUE
;
5000 sig
->hasthis
= TRUE
;
5001 for (i
= 0; i
< klass
->rank
+ 1; ++i
)
5002 sig
->params
[i
] = mono_get_int32_type ();
5003 amethod
= create_array_method (klass
, ".ctor", sig
);
5004 methods
[method_num
++] = amethod
;
5007 /* element Get (idx11, [idx2, ...]) */
5008 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
5009 sig
->ret
= m_class_get_byval_arg (m_class_get_element_class (klass
));
5010 sig
->pinvoke
= TRUE
;
5011 sig
->hasthis
= TRUE
;
5012 for (i
= 0; i
< klass
->rank
; ++i
)
5013 sig
->params
[i
] = mono_get_int32_type ();
5014 amethod
= create_array_method (klass
, "Get", sig
);
5015 methods
[method_num
++] = amethod
;
5016 /* element& Address (idx11, [idx2, ...]) */
5017 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
5018 sig
->ret
= &klass
->element_class
->this_arg
;
5019 sig
->pinvoke
= TRUE
;
5020 sig
->hasthis
= TRUE
;
5021 for (i
= 0; i
< klass
->rank
; ++i
)
5022 sig
->params
[i
] = mono_get_int32_type ();
5023 amethod
= create_array_method (klass
, "Address", sig
);
5024 methods
[method_num
++] = amethod
;
5025 /* void Set (idx11, [idx2, ...], element) */
5026 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
+ 1);
5027 sig
->ret
= mono_get_void_type ();
5028 sig
->pinvoke
= TRUE
;
5029 sig
->hasthis
= TRUE
;
5030 for (i
= 0; i
< klass
->rank
; ++i
)
5031 sig
->params
[i
] = mono_get_int32_type ();
5032 sig
->params
[i
] = m_class_get_byval_arg (m_class_get_element_class (klass
));
5033 amethod
= create_array_method (klass
, "Set", sig
);
5034 methods
[method_num
++] = amethod
;
5036 GHashTable
*cache
= g_hash_table_new (NULL
, NULL
);
5037 for (i
= 0; i
< klass
->interface_count
; i
++)
5038 setup_generic_array_ifaces (klass
, klass
->interfaces
[i
], methods
, first_generic
+ i
* count_generic
, cache
);
5039 g_hash_table_destroy (cache
);
5040 } else if (mono_class_has_static_metadata (klass
)) {
5042 int first_idx
= mono_class_get_first_method_idx (klass
);
5044 count
= mono_class_get_method_count (klass
);
5045 methods
= (MonoMethod
**)mono_class_alloc (klass
, sizeof (MonoMethod
*) * count
);
5046 for (i
= 0; i
< count
; ++i
) {
5047 int idx
= mono_metadata_translate_token_index (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
+ 1);
5048 methods
[i
] = mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| idx
, klass
, NULL
, error
);
5050 mono_class_set_type_load_failure (klass
, "Could not load method %d due to %s", i
, mono_error_get_message (error
));
5051 mono_error_cleanup (error
);
5055 methods
= (MonoMethod
**)mono_class_alloc (klass
, sizeof (MonoMethod
*) * 1);
5059 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
5061 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
5062 for (i
= 0; i
< count
; ++i
) {
5063 if (methods
[i
]->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
5065 if (method_is_reabstracted (methods
[i
]->flags
)) {
5066 methods
[i
]->is_reabstracted
= 1;
5069 methods
[i
]->slot
= slot
++;
5074 mono_image_lock (klass
->image
);
5076 if (!klass
->methods
) {
5077 mono_class_set_method_count (klass
, count
);
5079 /* Needed because of the double-checking locking pattern */
5080 mono_memory_barrier ();
5082 klass
->methods
= methods
;
5085 mono_image_unlock (klass
->image
);
5089 * mono_class_setup_properties:
5091 * Initialize klass->ext.property and klass->ext.properties.
5093 * This method can fail the class.
5096 mono_class_setup_properties (MonoClass
*klass
)
5098 guint startm
, endm
, i
, j
;
5099 guint32 cols
[MONO_PROPERTY_SIZE
];
5100 MonoTableInfo
*msemt
= &klass
->image
->tables
[MONO_TABLE_METHODSEMANTICS
];
5101 MonoProperty
*properties
;
5104 MonoClassPropertyInfo
*info
;
5106 info
= mono_class_get_property_info (klass
);
5110 if (mono_class_is_ginst (klass
)) {
5111 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5113 mono_class_init_internal (gklass
);
5114 mono_class_setup_properties (gklass
);
5115 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
5118 MonoClassPropertyInfo
*ginfo
= mono_class_get_property_info (gklass
);
5119 properties
= mono_class_new0 (klass
, MonoProperty
, ginfo
->count
+ 1);
5121 for (i
= 0; i
< ginfo
->count
; i
++) {
5123 MonoProperty
*prop
= &properties
[i
];
5125 *prop
= ginfo
->properties
[i
];
5128 prop
->get
= mono_class_inflate_generic_method_full_checked (
5129 prop
->get
, klass
, mono_class_get_context (klass
), error
);
5131 prop
->set
= mono_class_inflate_generic_method_full_checked (
5132 prop
->set
, klass
, mono_class_get_context (klass
), error
);
5134 g_assert (is_ok (error
)); /*FIXME proper error handling*/
5135 prop
->parent
= klass
;
5138 first
= ginfo
->first
;
5139 count
= ginfo
->count
;
5141 first
= mono_metadata_properties_from_typedef (klass
->image
, mono_metadata_token_index (klass
->type_token
) - 1, &last
);
5142 count
= last
- first
;
5145 mono_class_setup_methods (klass
);
5146 if (mono_class_has_failure (klass
))
5150 properties
= (MonoProperty
*)mono_class_alloc0 (klass
, sizeof (MonoProperty
) * count
);
5151 for (i
= first
; i
< last
; ++i
) {
5152 mono_metadata_decode_table_row (klass
->image
, MONO_TABLE_PROPERTY
, i
, cols
, MONO_PROPERTY_SIZE
);
5153 properties
[i
- first
].parent
= klass
;
5154 properties
[i
- first
].attrs
= cols
[MONO_PROPERTY_FLAGS
];
5155 properties
[i
- first
].name
= mono_metadata_string_heap (klass
->image
, cols
[MONO_PROPERTY_NAME
]);
5157 startm
= mono_metadata_methods_from_property (klass
->image
, i
, &endm
);
5158 int first_idx
= mono_class_get_first_method_idx (klass
);
5159 for (j
= startm
; j
< endm
; ++j
) {
5162 mono_metadata_decode_row (msemt
, j
, cols
, MONO_METHOD_SEMA_SIZE
);
5164 if (klass
->image
->uncompressed_metadata
) {
5166 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5167 method
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| cols
[MONO_METHOD_SEMA_METHOD
], klass
, NULL
, error
);
5168 mono_error_cleanup (error
); /* FIXME don't swallow this error */
5170 method
= klass
->methods
[cols
[MONO_METHOD_SEMA_METHOD
] - 1 - first_idx
];
5173 switch (cols
[MONO_METHOD_SEMA_SEMANTICS
]) {
5174 case METHOD_SEMANTIC_SETTER
:
5175 properties
[i
- first
].set
= method
;
5177 case METHOD_SEMANTIC_GETTER
:
5178 properties
[i
- first
].get
= method
;
5187 info
= (MonoClassPropertyInfo
*)mono_class_alloc0 (klass
, sizeof (MonoClassPropertyInfo
));
5188 info
->first
= first
;
5189 info
->count
= count
;
5190 info
->properties
= properties
;
5191 mono_memory_barrier ();
5193 /* This might leak 'info' which was allocated from the image mempool */
5194 mono_class_set_property_info (klass
, info
);
5198 inflate_method_listz (MonoMethod
**methods
, MonoClass
*klass
, MonoGenericContext
*context
)
5200 MonoMethod
**om
, **retval
;
5203 for (om
= methods
, count
= 0; *om
; ++om
, ++count
)
5206 retval
= g_new0 (MonoMethod
*, count
+ 1);
5208 for (om
= methods
, count
= 0; *om
; ++om
, ++count
) {
5210 retval
[count
] = mono_class_inflate_generic_method_full_checked (*om
, klass
, context
, error
);
5211 g_assert (is_ok (error
)); /*FIXME proper error handling*/
5217 /*This method can fail the class.*/
5219 mono_class_setup_events (MonoClass
*klass
)
5222 guint startm
, endm
, i
, j
;
5223 guint32 cols
[MONO_EVENT_SIZE
];
5224 MonoTableInfo
*msemt
= &klass
->image
->tables
[MONO_TABLE_METHODSEMANTICS
];
5228 MonoClassEventInfo
*info
= mono_class_get_event_info (klass
);
5232 if (mono_class_is_ginst (klass
)) {
5233 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5234 MonoGenericContext
*context
= NULL
;
5236 mono_class_setup_events (gklass
);
5237 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
5240 MonoClassEventInfo
*ginfo
= mono_class_get_event_info (gklass
);
5241 first
= ginfo
->first
;
5242 count
= ginfo
->count
;
5244 events
= mono_class_new0 (klass
, MonoEvent
, count
);
5247 context
= mono_class_get_context (klass
);
5249 for (i
= 0; i
< count
; i
++) {
5251 MonoEvent
*event
= &events
[i
];
5252 MonoEvent
*gevent
= &ginfo
->events
[i
];
5254 event
->parent
= klass
;
5255 event
->name
= gevent
->name
;
5256 event
->add
= gevent
->add
? mono_class_inflate_generic_method_full_checked (gevent
->add
, klass
, context
, error
) : NULL
;
5257 g_assert (is_ok (error
)); /*FIXME proper error handling*/
5258 event
->remove
= gevent
->remove
? mono_class_inflate_generic_method_full_checked (gevent
->remove
, klass
, context
, error
) : NULL
;
5259 g_assert (is_ok (error
)); /*FIXME proper error handling*/
5260 event
->raise
= gevent
->raise
? mono_class_inflate_generic_method_full_checked (gevent
->raise
, klass
, context
, error
) : NULL
;
5261 g_assert (is_ok (error
)); /*FIXME proper error handling*/
5263 #ifndef MONO_SMALL_CONFIG
5264 event
->other
= gevent
->other
? inflate_method_listz (gevent
->other
, klass
, context
) : NULL
;
5266 event
->attrs
= gevent
->attrs
;
5269 first
= mono_metadata_events_from_typedef (klass
->image
, mono_metadata_token_index (klass
->type_token
) - 1, &last
);
5270 count
= last
- first
;
5273 mono_class_setup_methods (klass
);
5274 if (mono_class_has_failure (klass
)) {
5279 events
= (MonoEvent
*)mono_class_alloc0 (klass
, sizeof (MonoEvent
) * count
);
5280 for (i
= first
; i
< last
; ++i
) {
5281 MonoEvent
*event
= &events
[i
- first
];
5283 mono_metadata_decode_table_row (klass
->image
, MONO_TABLE_EVENT
, i
, cols
, MONO_EVENT_SIZE
);
5284 event
->parent
= klass
;
5285 event
->attrs
= cols
[MONO_EVENT_FLAGS
];
5286 event
->name
= mono_metadata_string_heap (klass
->image
, cols
[MONO_EVENT_NAME
]);
5288 startm
= mono_metadata_methods_from_event (klass
->image
, i
, &endm
);
5289 int first_idx
= mono_class_get_first_method_idx (klass
);
5290 for (j
= startm
; j
< endm
; ++j
) {
5293 mono_metadata_decode_row (msemt
, j
, cols
, MONO_METHOD_SEMA_SIZE
);
5295 if (klass
->image
->uncompressed_metadata
) {
5297 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5298 method
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| cols
[MONO_METHOD_SEMA_METHOD
], klass
, NULL
, error
);
5299 mono_error_cleanup (error
); /* FIXME don't swallow this error */
5301 method
= klass
->methods
[cols
[MONO_METHOD_SEMA_METHOD
] - 1 - first_idx
];
5304 switch (cols
[MONO_METHOD_SEMA_SEMANTICS
]) {
5305 case METHOD_SEMANTIC_ADD_ON
:
5306 event
->add
= method
;
5308 case METHOD_SEMANTIC_REMOVE_ON
:
5309 event
->remove
= method
;
5311 case METHOD_SEMANTIC_FIRE
:
5312 event
->raise
= method
;
5314 case METHOD_SEMANTIC_OTHER
: {
5315 #ifndef MONO_SMALL_CONFIG
5318 if (event
->other
== NULL
) {
5319 event
->other
= g_new0 (MonoMethod
*, 2);
5321 while (event
->other
[n
])
5323 event
->other
= (MonoMethod
**)g_realloc (event
->other
, (n
+ 2) * sizeof (MonoMethod
*));
5325 event
->other
[n
] = method
;
5326 /* NULL terminated */
5327 event
->other
[n
+ 1] = NULL
;
5338 info
= (MonoClassEventInfo
*)mono_class_alloc0 (klass
, sizeof (MonoClassEventInfo
));
5339 info
->events
= events
;
5340 info
->first
= first
;
5341 info
->count
= count
;
5343 mono_memory_barrier ();
5345 mono_class_set_event_info (klass
, info
);
5350 * mono_class_setup_interface_id:
5352 * Initializes MonoClass::interface_id if required.
5354 * LOCKING: Acquires the loader lock.
5357 mono_class_setup_interface_id (MonoClass
*klass
)
5359 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
));
5360 mono_loader_lock ();
5361 mono_class_setup_interface_id_internal (klass
);
5362 mono_loader_unlock ();
5366 * mono_class_setup_interfaces:
5368 * Initialize klass->interfaces/interfaces_count.
5369 * LOCKING: Acquires the loader lock.
5370 * This function can fail the type.
5373 mono_class_setup_interfaces (MonoClass
*klass
, MonoError
*error
)
5375 int i
, interface_count
;
5376 MonoClass
**interfaces
;
5380 if (klass
->interfaces_inited
)
5383 if (klass
->rank
== 1 && m_class_get_byval_arg (klass
)->type
!= MONO_TYPE_ARRAY
) {
5386 /* IList and IReadOnlyList -> 2x if enum*/
5387 interface_count
= klass
->element_class
->enumtype
? 4 : 2;
5388 interfaces
= (MonoClass
**)mono_image_alloc0 (klass
->image
, sizeof (MonoClass
*) * interface_count
);
5390 args
[0] = m_class_get_byval_arg (m_class_get_element_class (klass
));
5391 interfaces
[0] = mono_class_bind_generic_parameters (
5392 mono_defaults
.generic_ilist_class
, 1, args
, FALSE
);
5393 interfaces
[1] = mono_class_bind_generic_parameters (
5394 mono_defaults
.generic_ireadonlylist_class
, 1, args
, FALSE
);
5395 if (klass
->element_class
->enumtype
) {
5396 args
[0] = mono_class_enum_basetype_internal (klass
->element_class
);
5397 interfaces
[2] = mono_class_bind_generic_parameters (
5398 mono_defaults
.generic_ilist_class
, 1, args
, FALSE
);
5399 interfaces
[3] = mono_class_bind_generic_parameters (
5400 mono_defaults
.generic_ireadonlylist_class
, 1, args
, FALSE
);
5402 } else if (mono_class_is_ginst (klass
)) {
5403 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5405 mono_class_setup_interfaces (gklass
, error
);
5406 if (!is_ok (error
)) {
5407 mono_class_set_type_load_failure (klass
, "Could not setup the interfaces");
5411 interface_count
= gklass
->interface_count
;
5412 interfaces
= mono_class_new0 (klass
, MonoClass
*, interface_count
);
5413 for (i
= 0; i
< interface_count
; i
++) {
5414 interfaces
[i
] = mono_class_inflate_generic_class_checked (gklass
->interfaces
[i
], mono_generic_class_get_context (mono_class_get_generic_class (klass
)), error
);
5415 if (!is_ok (error
)) {
5416 mono_class_set_type_load_failure (klass
, "Could not setup the interfaces");
5421 interface_count
= 0;
5425 mono_loader_lock ();
5426 if (!klass
->interfaces_inited
) {
5427 klass
->interface_count
= interface_count
;
5428 klass
->interfaces
= interfaces
;
5430 mono_memory_barrier ();
5432 klass
->interfaces_inited
= TRUE
;
5434 mono_loader_unlock ();
5439 * mono_class_setup_has_finalizer:
5441 * Initialize klass->has_finalizer if it isn't already initialized.
5443 * LOCKING: Acquires the loader lock.
5446 mono_class_setup_has_finalizer (MonoClass
*klass
)
5448 gboolean has_finalize
= FALSE
;
5450 if (m_class_is_has_finalize_inited (klass
))
5453 /* Interfaces and valuetypes are not supposed to have finalizers */
5454 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || m_class_is_valuetype (klass
))) {
5455 MonoMethod
*cmethod
= NULL
;
5457 if (m_class_get_rank (klass
) == 1 && m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
) {
5458 } else if (mono_class_is_ginst (klass
)) {
5459 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5461 has_finalize
= mono_class_has_finalizer (gklass
);
5462 } else if (m_class_get_parent (klass
) && m_class_has_finalize (m_class_get_parent (klass
))) {
5463 has_finalize
= TRUE
;
5465 if (m_class_get_parent (klass
)) {
5467 * Can't search in metadata for a method named Finalize, because that
5468 * ignores overrides.
5470 mono_class_setup_vtable (klass
);
5471 if (mono_class_has_failure (klass
))
5474 cmethod
= m_class_get_vtable (klass
) [mono_class_get_object_finalize_slot ()];
5478 g_assert (m_class_get_vtable_size (klass
) > mono_class_get_object_finalize_slot ());
5480 if (m_class_get_parent (klass
)) {
5481 if (cmethod
->is_inflated
)
5482 cmethod
= ((MonoMethodInflated
*)cmethod
)->declaring
;
5483 if (cmethod
!= mono_class_get_default_finalize_method ())
5484 has_finalize
= TRUE
;
5490 mono_loader_lock ();
5491 if (!m_class_is_has_finalize_inited (klass
)) {
5492 klass
->has_finalize
= has_finalize
? 1 : 0;
5494 mono_memory_barrier ();
5495 klass
->has_finalize_inited
= TRUE
;
5497 mono_loader_unlock ();
5501 * mono_class_setup_supertypes:
5504 * Build the data structure needed to make fast type checks work.
5505 * This currently sets two fields in @class:
5506 * - idepth: distance between @class and System.Object in the type
5508 * - supertypes: array of classes: each element has a class in the hierarchy
5509 * starting from @class up to System.Object
5511 * LOCKING: Acquires the loader lock.
5514 mono_class_setup_supertypes (MonoClass
*klass
)
5517 MonoClass
**supertypes
;
5519 mono_atomic_load_acquire (supertypes
, MonoClass
**, &klass
->supertypes
);
5523 if (klass
->parent
&& !klass
->parent
->supertypes
)
5524 mono_class_setup_supertypes (klass
->parent
);
5526 idepth
= klass
->parent
->idepth
+ 1;
5530 ms
= MAX (MONO_DEFAULT_SUPERTABLE_SIZE
, idepth
);
5531 supertypes
= (MonoClass
**)mono_class_alloc0 (klass
, sizeof (MonoClass
*) * ms
);
5533 if (klass
->parent
) {
5534 CHECKED_METADATA_WRITE_PTR ( supertypes
[idepth
- 1] , klass
);
5537 for (supertype_idx
= 0; supertype_idx
< klass
->parent
->idepth
; supertype_idx
++)
5538 CHECKED_METADATA_WRITE_PTR ( supertypes
[supertype_idx
] , klass
->parent
->supertypes
[supertype_idx
] );
5540 CHECKED_METADATA_WRITE_PTR ( supertypes
[0] , klass
);
5543 mono_memory_barrier ();
5545 mono_loader_lock ();
5546 klass
->idepth
= idepth
;
5547 /* Needed so idepth is visible before supertypes is set */
5548 mono_memory_barrier ();
5549 klass
->supertypes
= supertypes
;
5550 mono_loader_unlock ();
5553 /* mono_class_setup_nested_types:
5555 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5557 * LOCKING: Acquires the loader lock.
5560 mono_class_setup_nested_types (MonoClass
*klass
)
5563 GList
*classes
, *nested_classes
, *l
;
5566 if (klass
->nested_classes_inited
)
5569 if (!klass
->type_token
) {
5570 mono_loader_lock ();
5571 klass
->nested_classes_inited
= TRUE
;
5572 mono_loader_unlock ();
5576 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, 1);
5580 guint32 cols
[MONO_NESTED_CLASS_SIZE
];
5581 mono_metadata_decode_row (&klass
->image
->tables
[MONO_TABLE_NESTEDCLASS
], i
- 1, cols
, MONO_NESTED_CLASS_SIZE
);
5582 nclass
= mono_class_create_from_typedef (klass
->image
, MONO_TOKEN_TYPE_DEF
| cols
[MONO_NESTED_CLASS_NESTED
], error
);
5583 if (!is_ok (error
)) {
5584 /*FIXME don't swallow the error message*/
5585 mono_error_cleanup (error
);
5587 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, i
+ 1);
5591 classes
= g_list_prepend (classes
, nclass
);
5593 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, i
+ 1);
5596 nested_classes
= NULL
;
5597 for (l
= classes
; l
; l
= l
->next
)
5598 nested_classes
= mono_g_list_prepend_image (klass
->image
, nested_classes
, l
->data
);
5599 g_list_free (classes
);
5601 mono_loader_lock ();
5602 if (!klass
->nested_classes_inited
) {
5603 mono_class_set_nested_classes_property (klass
, nested_classes
);
5604 mono_memory_barrier ();
5605 klass
->nested_classes_inited
= TRUE
;
5607 mono_loader_unlock ();
5611 * mono_class_setup_runtime_info:
5612 * \param klass the class to setup
5613 * \param domain the domain of the \p vtable
5616 * Store \p vtable in \c klass->runtime_info.
5618 * Sets the following field in MonoClass:
5621 * LOCKING: domain lock and loaderlock must be held.
5624 mono_class_setup_runtime_info (MonoClass
*klass
, MonoDomain
*domain
, MonoVTable
*vtable
)
5626 MonoClassRuntimeInfo
*old_info
= m_class_get_runtime_info (klass
);
5627 if (old_info
&& old_info
->max_domain
>= domain
->domain_id
) {
5628 /* someone already created a large enough runtime info */
5629 old_info
->domain_vtables
[domain
->domain_id
] = vtable
;
5631 int new_size
= domain
->domain_id
;
5633 new_size
= MAX (new_size
, old_info
->max_domain
);
5635 /* make the new size a power of two */
5637 while (new_size
> i
)
5640 /* this is a bounded memory retention issue: may want to
5641 * handle it differently when we'll have a rcu-like system.
5643 MonoClassRuntimeInfo
*runtime_info
= (MonoClassRuntimeInfo
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_CLASS_RUNTIME_INFO
+ new_size
* sizeof (gpointer
));
5644 runtime_info
->max_domain
= new_size
- 1;
5645 /* copy the stuff from the older info */
5647 memcpy (runtime_info
->domain_vtables
, old_info
->domain_vtables
, (old_info
->max_domain
+ 1) * sizeof (gpointer
));
5649 runtime_info
->domain_vtables
[domain
->domain_id
] = vtable
;
5651 mono_memory_barrier ();
5652 klass
->runtime_info
= runtime_info
;
5657 * mono_class_create_array_fill_type:
5659 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5662 mono_class_create_array_fill_type (void)
5664 static MonoClass klass
;
5666 klass
.element_class
= mono_defaults
.int64_class
;
5668 klass
.instance_size
= MONO_SIZEOF_MONO_ARRAY
;
5669 klass
.sizes
.element_size
= 8;
5670 klass
.size_inited
= 1;
5671 klass
.name
= "array_filler_type";
5677 * mono_classes_init:
5679 * Initialize the resources used by this module.
5680 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5682 MONO_NO_SANITIZE_THREAD
5684 mono_classes_init (void)
5686 mono_os_mutex_init (&classes_mutex
);
5688 mono_native_tls_alloc (&setup_fields_tls_id
, NULL
);
5689 mono_native_tls_alloc (&init_pending_tls_id
, NULL
);
5691 mono_counters_register ("MonoClassDef count",
5692 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_def_count
);
5693 mono_counters_register ("MonoClassGtd count",
5694 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_gtd_count
);
5695 mono_counters_register ("MonoClassGenericInst count",
5696 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_ginst_count
);
5697 mono_counters_register ("MonoClassGenericParam count",
5698 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_gparam_count
);
5699 mono_counters_register ("MonoClassArray count",
5700 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_array_count
);
5701 mono_counters_register ("MonoClassPointer count",
5702 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_pointer_count
);
5703 mono_counters_register ("Inflated methods size",
5704 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mono_inflated_methods_size
);
5705 mono_counters_register ("Inflated classes size",
5706 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &inflated_classes_size
);
5707 mono_counters_register ("MonoClass size",
5708 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &classes_size
);
5712 * mono_classes_cleanup:
5714 * Free the resources used by this module.
5717 mono_classes_cleanup (void)
5719 mono_native_tls_free (setup_fields_tls_id
);
5720 mono_native_tls_free (init_pending_tls_id
);
5722 if (global_interface_bitset
)
5723 mono_bitset_free (global_interface_bitset
);
5724 global_interface_bitset
= NULL
;
5725 mono_os_mutex_destroy (&classes_mutex
);