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 static gint32 classes_size
;
42 static gint32 inflated_classes_size
;
43 gint32 mono_inflated_methods_size
;
44 static gint32 class_def_count
, class_gtd_count
, class_ginst_count
, class_gparam_count
, class_array_count
, class_pointer_count
;
46 /* Low level lock which protects data structures in this module */
47 static mono_mutex_t classes_mutex
;
49 static gboolean
class_kind_may_contain_generic_instances (MonoTypeKind kind
);
50 static int setup_interface_offsets (MonoClass
*klass
, int cur_slot
, gboolean overwrite
);
51 static void mono_class_setup_vtable_full (MonoClass
*klass
, GList
*in_setup
);
52 static void mono_generic_class_setup_parent (MonoClass
*klass
, MonoClass
*gtd
);
53 static int generic_array_methods (MonoClass
*klass
);
54 static void setup_generic_array_ifaces (MonoClass
*klass
, MonoClass
*iface
, MonoMethod
**methods
, int pos
, GHashTable
*cache
);
55 static gboolean
class_has_isbyreflike_attribute (MonoClass
*klass
);
56 static void mono_class_setup_interface_id_internal (MonoClass
*klass
);
58 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
59 static MonoNativeTlsKey setup_fields_tls_id
;
61 static MonoNativeTlsKey init_pending_tls_id
;
66 mono_locks_os_acquire (&classes_mutex
, ClassesLock
);
72 mono_locks_os_release (&classes_mutex
, ClassesLock
);
76 We use gclass recording to allow recursive system f types to be referenced by a parent.
78 Given the following type hierarchy:
80 class TextBox : TextBoxBase<TextBox> {}
81 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
82 class TextInput<T> : Input<T> where T: TextInput<T> {}
85 The runtime tries to load TextBoxBase<>.
86 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
87 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
88 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
90 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
91 at this point, iow, both are registered in the type map and both and a NULL parent. This means
92 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
94 To fix that what we do is to record all generic instantes created while resolving the parent of
95 any generic type definition and, after resolved, correct the parent field if needed.
98 static int record_gclass_instantiation
;
99 static GSList
*gclass_recorded_list
;
100 typedef gboolean (*gclass_record_func
) (MonoClass
*, void*);
103 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
106 enable_gclass_recording (void)
108 ++record_gclass_instantiation
;
112 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
115 disable_gclass_recording (gclass_record_func func
, void *user_data
)
117 GSList
**head
= &gclass_recorded_list
;
119 g_assert (record_gclass_instantiation
> 0);
120 --record_gclass_instantiation
;
123 GSList
*node
= *head
;
124 if (func ((MonoClass
*)node
->data
, user_data
)) {
126 g_slist_free_1 (node
);
132 /* We automatically discard all recorded gclasses when disabled. */
133 if (!record_gclass_instantiation
&& gclass_recorded_list
) {
134 g_slist_free (gclass_recorded_list
);
135 gclass_recorded_list
= NULL
;
139 #define mono_class_new0(klass,struct_type, n_structs) \
140 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
143 * mono_class_setup_basic_field_info:
144 * \param class The class to initialize
146 * Initializes the following fields in MonoClass:
147 * * klass->fields (only field->parent and field->name)
148 * * klass->field.count
149 * * klass->first_field_idx
150 * LOCKING: Acquires the loader lock
153 mono_class_setup_basic_field_info (MonoClass
*klass
)
155 MonoGenericClass
*gklass
;
156 MonoClassField
*field
;
157 MonoClassField
*fields
;
165 gklass
= mono_class_try_get_generic_class (klass
);
166 gtd
= gklass
? mono_class_get_generic_type_definition (klass
) : NULL
;
167 image
= klass
->image
;
170 if (gklass
&& image_is_dynamic (gklass
->container_class
->image
) && !gklass
->container_class
->wastypebuilder
) {
172 * This happens when a generic instance of an unfinished generic typebuilder
173 * is used as an element type for creating an array type. We can't initialize
174 * the fields of this class using the fields of gklass, since gklass is not
175 * finished yet, fields could be added to it later.
181 mono_class_setup_basic_field_info (gtd
);
184 mono_class_set_field_count (klass
, mono_class_get_field_count (gtd
));
185 mono_loader_unlock ();
188 top
= mono_class_get_field_count (klass
);
190 fields
= (MonoClassField
*)mono_class_alloc0 (klass
, sizeof (MonoClassField
) * top
);
193 * Fetch all the field information.
195 int first_field_idx
= mono_class_has_static_metadata (klass
) ? mono_class_get_first_field_idx (klass
) : 0;
196 for (i
= 0; i
< top
; i
++) {
198 field
->parent
= klass
;
201 field
->name
= mono_field_get_name (>d
->fields
[i
]);
203 int idx
= first_field_idx
+ i
;
204 /* first_field_idx and idx points into the fieldptr table */
205 guint32 name_idx
= mono_metadata_decode_table_row_col (image
, MONO_TABLE_FIELD
, idx
, MONO_FIELD_NAME
);
206 /* The name is needed for fieldrefs */
207 field
->name
= mono_metadata_string_heap (image
, name_idx
);
211 mono_memory_barrier ();
215 klass
->fields
= fields
;
216 mono_loader_unlock ();
220 * mono_class_setup_fields:
221 * \p klass The class to initialize
223 * Initializes klass->fields, computes class layout and sizes.
224 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
225 * Sets the following fields in \p klass:
226 * - all the fields initialized by mono_class_init_sizes ()
227 * - element_class/cast_class (for enums)
228 * - sizes:element_size (for arrays)
229 * - field->type/offset for all fields
232 * LOCKING: Acquires the loader lock.
235 mono_class_setup_fields (MonoClass
*klass
)
238 MonoImage
*m
= klass
->image
;
240 guint32 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
242 guint32 real_size
= 0;
243 guint32 packing_size
= 0;
245 gboolean explicit_size
;
246 MonoClassField
*field
;
247 MonoGenericClass
*gklass
= mono_class_try_get_generic_class (klass
);
248 MonoClass
*gtd
= gklass
? mono_class_get_generic_type_definition (klass
) : NULL
;
250 if (klass
->fields_inited
)
253 if (gklass
&& image_is_dynamic (gklass
->container_class
->image
) && !gklass
->container_class
->wastypebuilder
) {
255 * This happens when a generic instance of an unfinished generic typebuilder
256 * is used as an element type for creating an array type. We can't initialize
257 * the fields of this class using the fields of gklass, since gklass is not
258 * finished yet, fields could be added to it later.
263 mono_class_setup_basic_field_info (klass
);
264 top
= mono_class_get_field_count (klass
);
267 mono_class_setup_fields (gtd
);
268 if (mono_class_set_type_load_failure_causedby_class (klass
, gtd
, "Generic type definition failed"))
274 /* For generic instances, klass->parent might not have been initialized */
275 mono_class_init_internal (klass
->parent
);
276 mono_class_setup_fields (klass
->parent
);
277 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Could not set up parent class"))
279 instance_size
= klass
->parent
->instance_size
;
281 instance_size
= MONO_ABI_SIZEOF (MonoObject
);
284 /* Get the real size */
285 explicit_size
= mono_metadata_packing_from_typedef (klass
->image
, klass
->type_token
, &packing_size
, &real_size
);
287 instance_size
+= real_size
;
290 * This function can recursively call itself.
291 * Prevent infinite recursion by using a list in TLS.
293 GSList
*init_list
= (GSList
*)mono_native_tls_get_value (setup_fields_tls_id
);
294 if (g_slist_find (init_list
, klass
))
296 init_list
= g_slist_prepend (init_list
, klass
);
297 mono_native_tls_set_value (setup_fields_tls_id
, init_list
);
300 * Fetch all the field information.
302 int first_field_idx
= mono_class_has_static_metadata (klass
) ? mono_class_get_first_field_idx (klass
) : 0;
303 for (i
= 0; i
< top
; i
++) {
304 int idx
= first_field_idx
+ i
;
305 field
= &klass
->fields
[i
];
308 mono_field_resolve_type (field
, error
);
309 if (!mono_error_ok (error
)) {
310 /*mono_field_resolve_type already failed class*/
311 mono_error_cleanup (error
);
315 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass
), field
->name
);
316 g_assert (field
->type
);
319 if (!mono_type_get_underlying_type (field
->type
)) {
320 mono_class_set_type_load_failure (klass
, "Field '%s' is an enum type with a bad underlying type", field
->name
);
324 if (mono_field_is_deleted (field
))
326 if (layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
328 mono_metadata_field_info (m
, idx
, &uoffset
, NULL
, NULL
);
329 int offset
= uoffset
;
331 if (offset
== (guint32
)-1 && !(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
332 mono_class_set_type_load_failure (klass
, "Missing field layout info for %s", field
->name
);
335 if (offset
< -1) { /*-1 is used to encode special static fields */
336 mono_class_set_type_load_failure (klass
, "Field '%s' has a negative offset %d", field
->name
, offset
);
339 if (mono_class_is_gtd (klass
)) {
340 mono_class_set_type_load_failure (klass
, "Generic class cannot have explicit layout.");
344 if (mono_type_has_exceptions (field
->type
)) {
345 char *class_name
= mono_type_get_full_name (klass
);
346 char *type_name
= mono_type_full_name (field
->type
);
348 mono_class_set_type_load_failure (klass
, "Invalid type %s for instance field %s:%s", type_name
, class_name
, field
->name
);
353 /* The def_value of fields is compute lazily during vtable creation */
356 if (!mono_class_has_failure (klass
)) {
358 mono_class_layout_fields (klass
, instance_size
, packing_size
, real_size
, FALSE
);
359 mono_loader_unlock ();
362 init_list
= g_slist_remove (init_list
, klass
);
363 mono_native_tls_set_value (setup_fields_tls_id
, init_list
);
367 discard_gclass_due_to_failure (MonoClass
*gclass
, void *user_data
)
369 return mono_class_get_generic_class (gclass
)->container_class
== user_data
;
373 fix_gclass_incomplete_instantiation (MonoClass
*gclass
, void *user_data
)
375 MonoClass
*gtd
= (MonoClass
*)user_data
;
376 /* Only try to fix generic instances of @gtd */
377 if (mono_class_get_generic_class (gclass
)->container_class
!= gtd
)
380 /* Check if the generic instance has no parent. */
381 if (gtd
->parent
&& !gclass
->parent
)
382 mono_generic_class_setup_parent (gclass
, gtd
);
388 mono_class_set_failure_and_error (MonoClass
*klass
, MonoError
*error
, const char *msg
)
390 mono_class_set_type_load_failure (klass
, "%s", msg
);
391 mono_error_set_type_load_class (error
, klass
, "%s", msg
);
395 * mono_class_create_from_typedef:
396 * \param image: image where the token is valid
397 * \param type_token: typedef token
398 * \param error: used to return any error found while creating the type
400 * Create the MonoClass* representing the specified type token.
401 * \p type_token must be a TypeDef token.
403 * FIXME: don't return NULL on failure, just let the caller figure it out.
406 mono_class_create_from_typedef (MonoImage
*image
, guint32 type_token
, MonoError
*error
)
408 MonoTableInfo
*tt
= &image
->tables
[MONO_TABLE_TYPEDEF
];
409 MonoClass
*klass
, *parent
= NULL
;
410 guint32 cols
[MONO_TYPEDEF_SIZE
];
411 guint32 cols_next
[MONO_TYPEDEF_SIZE
];
412 guint tidx
= mono_metadata_token_index (type_token
);
413 MonoGenericContext
*context
= NULL
;
414 const char *name
, *nspace
;
416 MonoClass
**interfaces
;
417 guint32 field_last
, method_last
;
418 guint32 nesting_tokeen
;
422 if (mono_metadata_token_table (type_token
) != MONO_TABLE_TYPEDEF
|| tidx
> tt
->rows
) {
423 mono_error_set_bad_image (error
, image
, "Invalid typedef token %x", type_token
);
429 if ((klass
= (MonoClass
*)mono_internal_hash_table_lookup (&image
->class_cache
, GUINT_TO_POINTER (type_token
)))) {
430 mono_loader_unlock ();
434 mono_metadata_decode_row (tt
, tidx
- 1, cols
, MONO_TYPEDEF_SIZE
);
436 name
= mono_metadata_string_heap (image
, cols
[MONO_TYPEDEF_NAME
]);
437 nspace
= mono_metadata_string_heap (image
, cols
[MONO_TYPEDEF_NAMESPACE
]);
439 if (mono_metadata_has_generic_params (image
, type_token
)) {
440 klass
= (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassGtd
));
441 klass
->class_kind
= MONO_CLASS_GTD
;
442 UnlockedAdd (&classes_size
, sizeof (MonoClassGtd
));
445 klass
= (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassDef
));
446 klass
->class_kind
= MONO_CLASS_DEF
;
447 UnlockedAdd (&classes_size
, sizeof (MonoClassDef
));
452 klass
->name_space
= nspace
;
454 MONO_PROFILER_RAISE (class_loading
, (klass
));
456 klass
->image
= image
;
457 klass
->type_token
= type_token
;
458 mono_class_set_flags (klass
, cols
[MONO_TYPEDEF_FLAGS
]);
460 mono_internal_hash_table_insert (&image
->class_cache
, GUINT_TO_POINTER (type_token
), klass
);
463 * Check whether we're a generic type definition.
465 if (mono_class_is_gtd (klass
)) {
466 MonoGenericContainer
*generic_container
= mono_metadata_load_generic_params (image
, klass
->type_token
, NULL
, klass
);
467 context
= &generic_container
->context
;
468 mono_class_set_generic_container (klass
, generic_container
);
469 MonoType
*canonical_inst
= &((MonoClassGtd
*)klass
)->canonical_inst
;
470 canonical_inst
->type
= MONO_TYPE_GENERICINST
;
471 canonical_inst
->data
.generic_class
= mono_metadata_lookup_generic_class (klass
, context
->class_inst
, FALSE
);
472 enable_gclass_recording ();
475 if (cols
[MONO_TYPEDEF_EXTENDS
]) {
477 guint32 parent_token
= mono_metadata_token_from_dor (cols
[MONO_TYPEDEF_EXTENDS
]);
479 if (mono_metadata_token_table (parent_token
) == MONO_TABLE_TYPESPEC
) {
480 /*WARNING: this must satisfy mono_metadata_type_hash*/
481 klass
->this_arg
.byref
= 1;
482 klass
->this_arg
.data
.klass
= klass
;
483 klass
->this_arg
.type
= MONO_TYPE_CLASS
;
484 klass
->_byval_arg
.data
.klass
= klass
;
485 klass
->_byval_arg
.type
= MONO_TYPE_CLASS
;
487 parent
= mono_class_get_checked (image
, parent_token
, error
);
488 if (parent
&& context
) /* Always inflate */
489 parent
= mono_class_inflate_generic_class_checked (parent
, context
, error
);
491 if (parent
== NULL
) {
492 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
496 for (tmp
= parent
; tmp
; tmp
= tmp
->parent
) {
498 mono_class_set_failure_and_error (klass
, error
, "Cycle found while resolving parent");
501 if (mono_class_is_gtd (klass
) && mono_class_is_ginst (tmp
) && mono_class_get_generic_class (tmp
)->container_class
== klass
) {
502 mono_class_set_failure_and_error (klass
, error
, "Parent extends generic instance of this type");
508 mono_class_setup_parent (klass
, parent
);
510 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
511 mono_class_setup_mono_type (klass
);
513 if (mono_class_is_gtd (klass
))
514 disable_gclass_recording (fix_gclass_incomplete_instantiation
, klass
);
517 * This might access klass->_byval_arg for recursion generated by generic constraints,
518 * so it has to come after setup_mono_type ().
520 if ((nesting_tokeen
= mono_metadata_nested_in_typedef (image
, type_token
))) {
521 klass
->nested_in
= mono_class_create_from_typedef (image
, nesting_tokeen
, error
);
522 if (!mono_error_ok (error
)) {
523 /*FIXME implement a mono_class_set_failure_from_mono_error */
524 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
525 mono_loader_unlock ();
526 MONO_PROFILER_RAISE (class_failed
, (klass
));
531 if ((mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK
) == TYPE_ATTRIBUTE_UNICODE_CLASS
)
535 if ((mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK
) == TYPE_ATTRIBUTE_AUTO_CLASS
)
539 klass
->cast_class
= klass
->element_class
= klass
;
540 if (mono_is_corlib_image (klass
->image
)) {
541 switch (m_class_get_byval_arg (klass
)->type
) {
543 if (mono_defaults
.byte_class
)
544 klass
->cast_class
= mono_defaults
.byte_class
;
547 if (mono_defaults
.sbyte_class
)
548 mono_defaults
.sbyte_class
= klass
;
551 if (mono_defaults
.uint16_class
)
552 mono_defaults
.uint16_class
= klass
;
555 if (mono_defaults
.int16_class
)
556 klass
->cast_class
= mono_defaults
.int16_class
;
559 if (mono_defaults
.uint32_class
)
560 mono_defaults
.uint32_class
= klass
;
563 if (mono_defaults
.int32_class
)
564 klass
->cast_class
= mono_defaults
.int32_class
;
567 if (mono_defaults
.uint64_class
)
568 mono_defaults
.uint64_class
= klass
;
571 if (mono_defaults
.int64_class
)
572 klass
->cast_class
= mono_defaults
.int64_class
;
577 if (!klass
->enumtype
) {
578 if (!mono_metadata_interfaces_from_typedef_full (
579 image
, type_token
, &interfaces
, &icount
, FALSE
, context
, error
)){
581 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
582 mono_loader_unlock ();
583 MONO_PROFILER_RAISE (class_failed
, (klass
));
587 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
588 g_assert(icount
<= 65535);
590 klass
->interfaces
= interfaces
;
591 klass
->interface_count
= icount
;
592 klass
->interfaces_inited
= 1;
595 /*g_print ("Load class %s\n", name);*/
598 * Compute the field and method lists
601 first_field_idx
= cols
[MONO_TYPEDEF_FIELD_LIST
] - 1;
602 mono_class_set_first_field_idx (klass
, first_field_idx
);
603 int first_method_idx
;
604 first_method_idx
= cols
[MONO_TYPEDEF_METHOD_LIST
] - 1;
605 mono_class_set_first_method_idx (klass
, first_method_idx
);
607 if (tt
->rows
> tidx
){
608 mono_metadata_decode_row (tt
, tidx
, cols_next
, MONO_TYPEDEF_SIZE
);
609 field_last
= cols_next
[MONO_TYPEDEF_FIELD_LIST
] - 1;
610 method_last
= cols_next
[MONO_TYPEDEF_METHOD_LIST
] - 1;
612 field_last
= image
->tables
[MONO_TABLE_FIELD
].rows
;
613 method_last
= image
->tables
[MONO_TABLE_METHOD
].rows
;
616 if (cols
[MONO_TYPEDEF_FIELD_LIST
] &&
617 cols
[MONO_TYPEDEF_FIELD_LIST
] <= image
->tables
[MONO_TABLE_FIELD
].rows
)
618 mono_class_set_field_count (klass
, field_last
- first_field_idx
);
619 if (cols
[MONO_TYPEDEF_METHOD_LIST
] <= image
->tables
[MONO_TABLE_METHOD
].rows
)
620 mono_class_set_method_count (klass
, method_last
- first_method_idx
);
622 /* reserve space to store vector pointer in arrays */
623 if (mono_is_corlib_image (image
) && !strcmp (nspace
, "System") && !strcmp (name
, "Array")) {
624 klass
->instance_size
+= 2 * TARGET_SIZEOF_VOID_P
;
625 #ifndef ENABLE_NETCORE
626 g_assert (mono_class_get_field_count (klass
) == 0);
628 /* TODO: check that array has 0 non-const fields */
632 if (klass
->enumtype
) {
633 MonoType
*enum_basetype
= mono_class_find_enum_basetype (klass
, error
);
634 if (!enum_basetype
) {
635 /*set it to a default value as the whole runtime can't handle this to be null*/
636 klass
->cast_class
= klass
->element_class
= mono_defaults
.int32_class
;
637 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
638 mono_loader_unlock ();
639 MONO_PROFILER_RAISE (class_failed
, (klass
));
642 klass
->cast_class
= klass
->element_class
= mono_class_from_mono_type_internal (enum_basetype
);
646 * If we're a generic type definition, load the constraints.
647 * We must do this after the class has been constructed to make certain recursive scenarios
650 if (mono_class_is_gtd (klass
) && !mono_metadata_load_generic_param_constraints_checked (image
, type_token
, mono_class_get_generic_container (klass
), error
)) {
651 mono_class_set_type_load_failure (klass
, "Could not load generic parameter constrains due to %s", mono_error_get_message (error
));
652 mono_loader_unlock ();
653 MONO_PROFILER_RAISE (class_failed
, (klass
));
657 if (klass
->image
->assembly_name
&& !strcmp (klass
->image
->assembly_name
, "Mono.Simd") && !strcmp (nspace
, "Mono.Simd")) {
658 if (!strncmp (name
, "Vector", 6))
659 klass
->simd_type
= !strcmp (name
+ 6, "2d") || !strcmp (name
+ 6, "2ul") || !strcmp (name
+ 6, "2l") || !strcmp (name
+ 6, "4f") || !strcmp (name
+ 6, "4ui") || !strcmp (name
+ 6, "4i") || !strcmp (name
+ 6, "8s") || !strcmp (name
+ 6, "8us") || !strcmp (name
+ 6, "16b") || !strcmp (name
+ 6, "16sb");
660 } else if (klass
->image
->assembly_name
&& !strcmp (klass
->image
->assembly_name
, "System.Numerics") && !strcmp (nspace
, "System.Numerics")) {
661 /* The JIT can't handle SIMD types with != 16 size yet */
662 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
663 if (!strcmp (name
, "Vector4"))
664 klass
->simd_type
= 1;
667 // compute is_byreflike
668 if (m_class_is_valuetype (klass
))
669 if (class_has_isbyreflike_attribute (klass
))
670 klass
->is_byreflike
= 1;
672 mono_loader_unlock ();
674 MONO_PROFILER_RAISE (class_loaded
, (klass
));
679 if (mono_class_is_gtd (klass
))
680 disable_gclass_recording (discard_gclass_due_to_failure
, klass
);
682 mono_class_setup_mono_type (klass
);
683 mono_loader_unlock ();
684 MONO_PROFILER_RAISE (class_failed
, (klass
));
690 mono_generic_class_setup_parent (MonoClass
*klass
, MonoClass
*gtd
)
694 MonoGenericClass
*gclass
= mono_class_get_generic_class (klass
);
696 klass
->parent
= mono_class_inflate_generic_class_checked (gtd
->parent
, mono_generic_class_get_context (gclass
), error
);
697 if (!mono_error_ok (error
)) {
698 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
699 klass
->parent
= mono_defaults
.object_class
;
700 mono_class_set_type_load_failure (klass
, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error
));
701 mono_error_cleanup (error
);
706 mono_class_setup_parent (klass
, klass
->parent
);
708 if (klass
->enumtype
) {
709 klass
->cast_class
= gtd
->cast_class
;
710 klass
->element_class
= gtd
->element_class
;
712 mono_loader_unlock ();
715 struct HasIsByrefLikeUD
{
716 gboolean has_isbyreflike
;
720 has_isbyreflike_attribute_func (MonoImage
*image
, guint32 typeref_scope_token
, const char *nspace
, const char *name
, guint32 method_token
, gpointer user_data
)
722 struct HasIsByrefLikeUD
*has_isbyreflike
= (struct HasIsByrefLikeUD
*)user_data
;
723 if (!strcmp (name
, "IsByRefLikeAttribute") && !strcmp (nspace
, "System.Runtime.CompilerServices")) {
724 has_isbyreflike
->has_isbyreflike
= TRUE
;
731 class_has_isbyreflike_attribute (MonoClass
*klass
)
733 struct HasIsByrefLikeUD has_isbyreflike
;
734 has_isbyreflike
.has_isbyreflike
= FALSE
;
735 mono_class_metadata_foreach_custom_attr (klass
, has_isbyreflike_attribute_func
, &has_isbyreflike
);
736 return has_isbyreflike
.has_isbyreflike
;
741 check_valid_generic_inst_arguments (MonoGenericInst
*inst
, MonoError
*error
)
743 for (int i
= 0; i
< inst
->type_argc
; i
++) {
744 if (!mono_type_is_valid_generic_argument (inst
->type_argv
[i
])) {
745 char *type_name
= mono_type_full_name (inst
->type_argv
[i
]);
746 mono_error_set_invalid_program (error
, "generic type cannot be instantiated with type '%s'", type_name
);
755 * Create the `MonoClass' for an instantiation of a generic type.
756 * We only do this if we actually need it.
759 mono_class_create_generic_inst (MonoGenericClass
*gclass
)
761 MonoClass
*klass
, *gklass
;
763 if (gclass
->cached_class
)
764 return gclass
->cached_class
;
766 klass
= (MonoClass
*)mono_image_set_alloc0 (gclass
->owner
, sizeof (MonoClassGenericInst
));
768 gklass
= gclass
->container_class
;
770 if (gklass
->nested_in
) {
771 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
772 klass
->nested_in
= gklass
->nested_in
;
775 klass
->name
= gklass
->name
;
776 klass
->name_space
= gklass
->name_space
;
778 klass
->image
= gklass
->image
;
779 klass
->type_token
= gklass
->type_token
;
781 klass
->class_kind
= MONO_CLASS_GINST
;
783 ((MonoClassGenericInst
*)klass
)->generic_class
= gclass
;
785 klass
->_byval_arg
.type
= MONO_TYPE_GENERICINST
;
786 klass
->this_arg
.type
= m_class_get_byval_arg (klass
)->type
;
787 klass
->this_arg
.data
.generic_class
= klass
->_byval_arg
.data
.generic_class
= gclass
;
788 klass
->this_arg
.byref
= TRUE
;
789 klass
->enumtype
= gklass
->enumtype
;
790 klass
->valuetype
= gklass
->valuetype
;
793 if (gklass
->image
->assembly_name
&& !strcmp (gklass
->image
->assembly_name
, "System.Numerics.Vectors") && !strcmp (gklass
->name_space
, "System.Numerics") && !strcmp (gklass
->name
, "Vector`1")) {
794 g_assert (gclass
->context
.class_inst
);
795 g_assert (gclass
->context
.class_inst
->type_argc
> 0);
796 if (mono_type_is_primitive (gclass
->context
.class_inst
->type_argv
[0]))
797 klass
->simd_type
= 1;
799 klass
->is_array_special_interface
= gklass
->is_array_special_interface
;
801 klass
->cast_class
= klass
->element_class
= klass
;
803 if (m_class_is_valuetype (klass
)) {
804 klass
->is_byreflike
= gklass
->is_byreflike
;
807 if (gclass
->is_dynamic
) {
809 * We don't need to do any init workf with unbaked typebuilders. Generic instances created at this point will be later unregistered and/or fixed.
810 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
811 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
813 if (!gklass
->wastypebuilder
)
816 if (klass
->enumtype
) {
818 * For enums, gklass->fields might not been set, but instance_size etc. is
819 * already set in mono_reflection_create_internal_class (). For non-enums,
820 * these will be computed normally in mono_class_layout_fields ().
822 klass
->instance_size
= gklass
->instance_size
;
823 klass
->sizes
.class_size
= gklass
->sizes
.class_size
;
824 klass
->size_inited
= 1;
829 ERROR_DECL (error_inst
);
830 if (!check_valid_generic_inst_arguments (gclass
->context
.class_inst
, error_inst
)) {
831 char *gklass_name
= mono_type_get_full_name (gklass
);
832 mono_class_set_type_load_failure (klass
, "Could not instantiate %s due to %s", gklass_name
, mono_error_get_message (error_inst
));
833 g_free (gklass_name
);
834 mono_error_cleanup (error_inst
);
840 if (gclass
->cached_class
) {
841 mono_loader_unlock ();
842 return gclass
->cached_class
;
845 if (record_gclass_instantiation
> 0)
846 gclass_recorded_list
= g_slist_append (gclass_recorded_list
, klass
);
848 if (mono_class_is_nullable (klass
))
849 klass
->cast_class
= klass
->element_class
= mono_class_get_nullable_param_internal (klass
);
851 MONO_PROFILER_RAISE (class_loading
, (klass
));
853 mono_generic_class_setup_parent (klass
, gklass
);
855 if (gclass
->is_dynamic
)
856 mono_class_setup_supertypes (klass
);
858 mono_memory_barrier ();
859 gclass
->cached_class
= klass
;
861 MONO_PROFILER_RAISE (class_loaded
, (klass
));
864 inflated_classes_size
+= sizeof (MonoClassGenericInst
);
866 mono_loader_unlock ();
872 class_kind_may_contain_generic_instances (MonoTypeKind kind
)
874 /* classes of type generic inst may contain generic arguments from other images,
875 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
876 return (kind
== MONO_CLASS_GINST
|| kind
== MONO_CLASS_ARRAY
|| kind
== MONO_CLASS_POINTER
);
880 * mono_class_create_bounded_array:
881 * \param element_class element class
882 * \param rank the dimension of the array class
883 * \param bounded whenever the array has non-zero bounds
884 * \returns A class object describing the array with element type \p element_type and
888 mono_class_create_bounded_array (MonoClass
*eclass
, guint32 rank
, gboolean bounded
)
891 MonoClass
*klass
, *cached
, *k
;
892 MonoClass
*parent
= NULL
;
893 GSList
*list
, *rootlist
= NULL
;
896 MonoImageSet
* image_set
;
898 g_assert (rank
<= 255);
901 /* bounded only matters for one-dimensional arrays */
904 image
= eclass
->image
;
905 image_set
= class_kind_may_contain_generic_instances ((MonoTypeKind
)eclass
->class_kind
) ? mono_metadata_get_image_set_for_class (eclass
) : NULL
;
909 if (rank
== 1 && !bounded
) {
911 mono_image_set_lock (image_set
);
912 cached
= (MonoClass
*)g_hash_table_lookup (image_set
->szarray_cache
, eclass
);
913 mono_image_set_unlock (image_set
);
916 * This case is very frequent not just during compilation because of calls
917 * from mono_class_from_mono_type_internal (), mono_array_new (),
918 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
920 mono_os_mutex_lock (&image
->szarray_cache_lock
);
921 if (!image
->szarray_cache
)
922 image
->szarray_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
923 cached
= (MonoClass
*)g_hash_table_lookup (image
->szarray_cache
, eclass
);
924 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
928 mono_image_set_lock (image_set
);
929 rootlist
= (GSList
*)g_hash_table_lookup (image_set
->array_cache
, eclass
);
930 for (list
= rootlist
; list
; list
= list
->next
) {
931 k
= (MonoClass
*)list
->data
;
932 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
937 mono_image_set_unlock (image_set
);
940 if (!image
->array_cache
)
941 image
->array_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
942 rootlist
= (GSList
*)g_hash_table_lookup (image
->array_cache
, eclass
);
943 for (list
= rootlist
; list
; list
= list
->next
) {
944 k
= (MonoClass
*)list
->data
;
945 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
950 mono_loader_unlock ();
956 parent
= mono_defaults
.array_class
;
958 mono_class_init_internal (parent
);
960 klass
= image_set
? (MonoClass
*)mono_image_set_alloc0 (image_set
, sizeof (MonoClassArray
)) : (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassArray
));
962 klass
->image
= image
;
963 klass
->name_space
= eclass
->name_space
;
964 klass
->class_kind
= MONO_CLASS_ARRAY
;
966 nsize
= strlen (eclass
->name
);
967 name
= (char *)g_malloc (nsize
+ 2 + rank
+ 1);
968 memcpy (name
, eclass
->name
, nsize
);
971 memset (name
+ nsize
+ 1, ',', rank
- 1);
973 name
[nsize
+ rank
] = '*';
974 name
[nsize
+ rank
+ bounded
] = ']';
975 name
[nsize
+ rank
+ bounded
+ 1] = 0;
976 klass
->name
= image_set
? mono_image_set_strdup (image_set
, name
) : mono_image_strdup (image
, name
);
979 klass
->type_token
= 0;
980 klass
->parent
= parent
;
981 klass
->instance_size
= mono_class_instance_size (klass
->parent
);
983 if (m_class_get_byval_arg (eclass
)->type
== MONO_TYPE_TYPEDBYREF
) {
984 /*Arrays of those two types are invalid.*/
985 ERROR_DECL (prepared_error
);
986 mono_error_set_invalid_program (prepared_error
, "Arrays of System.TypedReference types are invalid.");
987 mono_class_set_failure (klass
, mono_error_box (prepared_error
, klass
->image
));
988 mono_error_cleanup (prepared_error
);
989 } else if (m_class_is_byreflike (eclass
)) {
990 /* .NET Core throws a type load exception: "Could not create array type 'fullname[]'" */
991 char *full_name
= mono_type_get_full_name (eclass
);
992 mono_class_set_type_load_failure (klass
, "Could not create array type '%s[]'", full_name
);
994 } else if (eclass
->enumtype
&& !mono_class_enum_basetype_internal (eclass
)) {
995 guint32 ref_info_handle
= mono_class_get_ref_info_handle (eclass
);
996 if (!ref_info_handle
|| eclass
->wastypebuilder
) {
997 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
998 g_assert (ref_info_handle
&& !eclass
->wastypebuilder
);
1000 /* element_size -1 is ok as this is not an instantitable type*/
1001 klass
->sizes
.element_size
= -1;
1003 klass
->sizes
.element_size
= -1;
1005 mono_class_setup_supertypes (klass
);
1007 if (mono_class_is_ginst (eclass
))
1008 mono_class_init_internal (eclass
);
1009 if (!eclass
->size_inited
)
1010 mono_class_setup_fields (eclass
);
1011 mono_class_set_type_load_failure_causedby_class (klass
, eclass
, "Could not load array element type");
1012 /*FIXME we fail the array type, but we have to let other fields be set.*/
1014 klass
->has_references
= MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (eclass
)) || m_class_has_references (eclass
)? TRUE
: FALSE
;
1018 if (eclass
->enumtype
)
1019 klass
->cast_class
= eclass
->element_class
;
1021 klass
->cast_class
= eclass
;
1023 switch (m_class_get_byval_arg (m_class_get_cast_class (klass
))->type
) {
1025 klass
->cast_class
= mono_defaults
.byte_class
;
1028 klass
->cast_class
= mono_defaults
.int16_class
;
1031 #if TARGET_SIZEOF_VOID_P == 4
1035 klass
->cast_class
= mono_defaults
.int32_class
;
1038 #if TARGET_SIZEOF_VOID_P == 8
1042 klass
->cast_class
= mono_defaults
.int64_class
;
1048 klass
->element_class
= eclass
;
1050 if ((rank
> 1) || bounded
) {
1051 MonoArrayType
*at
= image_set
? (MonoArrayType
*)mono_image_set_alloc0 (image_set
, sizeof (MonoArrayType
)) : (MonoArrayType
*)mono_image_alloc0 (image
, sizeof (MonoArrayType
));
1052 klass
->_byval_arg
.type
= MONO_TYPE_ARRAY
;
1053 klass
->_byval_arg
.data
.array
= at
;
1054 at
->eklass
= eclass
;
1056 /* FIXME: complete.... */
1058 klass
->_byval_arg
.type
= MONO_TYPE_SZARRAY
;
1059 klass
->_byval_arg
.data
.klass
= eclass
;
1061 klass
->this_arg
= klass
->_byval_arg
;
1062 klass
->this_arg
.byref
= 1;
1065 ERROR_DECL (prepared_error
);
1066 name
= mono_type_get_full_name (klass
);
1067 mono_error_set_type_load_class (prepared_error
, klass
, "%s has too many dimensions.", name
);
1068 mono_class_set_failure (klass
, mono_error_box (prepared_error
, klass
->image
));
1069 mono_error_cleanup (prepared_error
);
1073 mono_loader_lock ();
1075 /* Check cache again */
1077 if (rank
== 1 && !bounded
) {
1079 mono_image_set_lock (image_set
);
1080 cached
= (MonoClass
*)g_hash_table_lookup (image_set
->szarray_cache
, eclass
);
1081 mono_image_set_unlock (image_set
);
1083 mono_os_mutex_lock (&image
->szarray_cache_lock
);
1084 cached
= (MonoClass
*)g_hash_table_lookup (image
->szarray_cache
, eclass
);
1085 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
1089 mono_image_set_lock (image_set
);
1090 rootlist
= (GSList
*)g_hash_table_lookup (image_set
->array_cache
, eclass
);
1091 for (list
= rootlist
; list
; list
= list
->next
) {
1092 k
= (MonoClass
*)list
->data
;
1093 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
1098 mono_image_set_unlock (image_set
);
1100 rootlist
= (GSList
*)g_hash_table_lookup (image
->array_cache
, eclass
);
1101 for (list
= rootlist
; list
; list
= list
->next
) {
1102 k
= (MonoClass
*)list
->data
;
1103 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
1111 mono_loader_unlock ();
1115 MONO_PROFILER_RAISE (class_loading
, (klass
));
1117 UnlockedAdd (&classes_size
, sizeof (MonoClassArray
));
1118 ++class_array_count
;
1120 if (rank
== 1 && !bounded
) {
1122 mono_image_set_lock (image_set
);
1123 g_hash_table_insert (image_set
->szarray_cache
, eclass
, klass
);
1124 mono_image_set_unlock (image_set
);
1126 mono_os_mutex_lock (&image
->szarray_cache_lock
);
1127 g_hash_table_insert (image
->szarray_cache
, eclass
, klass
);
1128 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
1132 mono_image_set_lock (image_set
);
1133 list
= g_slist_append (rootlist
, klass
);
1134 g_hash_table_insert (image_set
->array_cache
, eclass
, list
);
1135 mono_image_set_unlock (image_set
);
1137 list
= g_slist_append (rootlist
, klass
);
1138 g_hash_table_insert (image
->array_cache
, eclass
, list
);
1142 mono_loader_unlock ();
1144 MONO_PROFILER_RAISE (class_loaded
, (klass
));
1150 * mono_class_create_array:
1151 * \param element_class element class
1152 * \param rank the dimension of the array class
1153 * \returns A class object describing the array with element type \p element_type and
1154 * dimension \p rank.
1157 mono_class_create_array (MonoClass
*eclass
, guint32 rank
)
1159 return mono_class_create_bounded_array (eclass
, rank
, FALSE
);
1162 // This is called by mono_class_create_generic_parameter when a new class must be created.
1164 make_generic_param_class (MonoGenericParam
*param
)
1166 MonoClass
*klass
, **ptr
;
1168 MonoGenericParamInfo
*pinfo
= mono_generic_param_info (param
);
1169 MonoGenericContainer
*container
= mono_generic_param_owner (param
);
1170 g_assert_checked (container
);
1172 MonoImage
*image
= mono_get_image_for_generic_param (param
);
1173 gboolean is_mvar
= container
->is_method
;
1174 gboolean is_anonymous
= container
->is_anonymous
;
1176 klass
= (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassGenericParam
));
1177 klass
->class_kind
= MONO_CLASS_GPARAM
;
1178 UnlockedAdd (&classes_size
, sizeof (MonoClassGenericParam
));
1179 UnlockedIncrement (&class_gparam_count
);
1181 if (!is_anonymous
) {
1182 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name
, pinfo
->name
);
1184 int n
= mono_generic_param_num (param
);
1185 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->name
, mono_make_generic_name_string (image
, n
) );
1189 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, "" );
1190 } else if (is_mvar
) {
1191 MonoMethod
*omethod
= container
->owner
.method
;
1192 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, (omethod
&& omethod
->klass
) ? omethod
->klass
->name_space
: "" );
1194 MonoClass
*oklass
= container
->owner
.klass
;
1195 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, oklass
? oklass
->name_space
: "" );
1198 MONO_PROFILER_RAISE (class_loading
, (klass
));
1200 // Count non-NULL items in pinfo->constraints
1203 for (ptr
= pinfo
->constraints
; ptr
&& *ptr
; ptr
++, count
++)
1207 if ((count
> 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo
->constraints
[0])) {
1208 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, pinfo
->constraints
[0] );
1210 } else if (pinfo
&& pinfo
->flags
& GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT
) {
1211 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, mono_class_load_from_name (mono_defaults
.corlib
, "System", "ValueType") );
1213 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, mono_defaults
.object_class
);
1216 if (count
- pos
> 0) {
1217 klass
->interface_count
= count
- pos
;
1218 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->interfaces
, (MonoClass
**)mono_image_alloc0 (image
, sizeof (MonoClass
*) * (count
- pos
)) );
1219 klass
->interfaces_inited
= TRUE
;
1220 for (i
= pos
; i
< count
; i
++)
1221 CHECKED_METADATA_WRITE_PTR ( klass
->interfaces
[i
- pos
] , pinfo
->constraints
[i
] );
1224 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->image
, image
);
1226 klass
->inited
= TRUE
;
1227 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->cast_class
, klass
);
1228 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->element_class
, klass
);
1230 MonoTypeEnum t
= is_mvar
? MONO_TYPE_MVAR
: MONO_TYPE_VAR
;
1231 klass
->_byval_arg
.type
= t
;
1232 klass
->this_arg
.type
= t
;
1233 CHECKED_METADATA_WRITE_PTR ( klass
->this_arg
.data
.generic_param
, param
);
1234 CHECKED_METADATA_WRITE_PTR ( klass
->_byval_arg
.data
.generic_param
, param
);
1235 klass
->this_arg
.byref
= TRUE
;
1237 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1238 klass
->sizes
.generic_param_token
= !is_anonymous
? pinfo
->token
: 0;
1240 /*Init these fields to sane values*/
1241 klass
->min_align
= 1;
1243 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1244 * constrained to, the JIT depends on this.
1246 klass
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + mono_type_stack_size_internal (m_class_get_byval_arg (klass
), NULL
, TRUE
);
1247 mono_memory_barrier ();
1248 klass
->size_inited
= 1;
1250 mono_class_setup_supertypes (klass
);
1252 if (count
- pos
> 0) {
1253 mono_class_setup_vtable (klass
->parent
);
1254 if (mono_class_has_failure (klass
->parent
))
1255 mono_class_set_type_load_failure (klass
, "Failed to setup parent interfaces");
1257 setup_interface_offsets (klass
, klass
->parent
->vtable_size
, TRUE
);
1264 * LOCKING: Acquires the image lock (@image).
1267 mono_class_create_generic_parameter (MonoGenericParam
*param
)
1269 MonoImage
*image
= mono_get_image_for_generic_param (param
);
1270 MonoGenericParamInfo
*pinfo
= mono_generic_param_info (param
);
1271 MonoClass
*klass
, *klass2
;
1273 // If a klass already exists for this object and is cached, return it.
1274 klass
= pinfo
->pklass
;
1279 // Create a new klass
1280 klass
= make_generic_param_class (param
);
1282 // Now we need to cache the klass we created.
1283 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1284 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1285 // and allow our newly-created klass object to just leak.
1286 mono_memory_barrier ();
1288 mono_image_lock (image
);
1290 // Here "klass2" refers to the klass potentially created by the other thread.
1291 klass2
= pinfo
->pklass
;
1296 pinfo
->pklass
= klass
;
1298 mono_image_unlock (image
);
1300 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1302 MONO_PROFILER_RAISE (class_failed
, (klass2
));
1304 MONO_PROFILER_RAISE (class_loaded
, (klass
));
1310 * mono_class_create_ptr:
1313 mono_class_create_ptr (MonoType
*type
)
1316 MonoClass
*el_class
;
1319 MonoImageSet
* image_set
;
1321 el_class
= mono_class_from_mono_type_internal (type
);
1322 image
= el_class
->image
;
1323 image_set
= class_kind_may_contain_generic_instances ((MonoTypeKind
)el_class
->class_kind
) ? mono_metadata_get_image_set_for_class (el_class
) : NULL
;
1326 mono_image_set_lock (image_set
);
1327 if (image_set
->ptr_cache
) {
1328 if ((result
= (MonoClass
*)g_hash_table_lookup (image_set
->ptr_cache
, el_class
))) {
1329 mono_image_set_unlock (image_set
);
1333 mono_image_set_unlock (image_set
);
1335 mono_image_lock (image
);
1336 if (image
->ptr_cache
) {
1337 if ((result
= (MonoClass
*)g_hash_table_lookup (image
->ptr_cache
, el_class
))) {
1338 mono_image_unlock (image
);
1342 mono_image_unlock (image
);
1345 result
= image_set
? (MonoClass
*)mono_image_set_alloc0 (image_set
, sizeof (MonoClassPointer
)) : (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassPointer
));
1347 UnlockedAdd (&classes_size
, sizeof (MonoClassPointer
));
1348 ++class_pointer_count
;
1350 result
->parent
= NULL
; /* no parent for PTR types */
1351 result
->name_space
= el_class
->name_space
;
1352 name
= g_strdup_printf ("%s*", el_class
->name
);
1353 result
->name
= image_set
? mono_image_set_strdup (image_set
, name
) : mono_image_strdup (image
, name
);
1354 result
->class_kind
= MONO_CLASS_POINTER
;
1357 MONO_PROFILER_RAISE (class_loading
, (result
));
1359 result
->image
= el_class
->image
;
1360 result
->inited
= TRUE
;
1361 result
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
1362 result
->min_align
= sizeof (gpointer
);
1363 result
->cast_class
= result
->element_class
= el_class
;
1364 result
->blittable
= TRUE
;
1366 result
->this_arg
.type
= result
->_byval_arg
.type
= MONO_TYPE_PTR
;
1367 result
->this_arg
.data
.type
= result
->_byval_arg
.data
.type
= m_class_get_byval_arg (el_class
);
1368 result
->this_arg
.byref
= TRUE
;
1370 mono_class_setup_supertypes (result
);
1373 mono_image_set_lock (image_set
);
1374 if (image_set
->ptr_cache
) {
1376 if ((result2
= (MonoClass
*)g_hash_table_lookup (image_set
->ptr_cache
, el_class
))) {
1377 mono_image_set_unlock (image_set
);
1378 MONO_PROFILER_RAISE (class_failed
, (result
));
1383 image_set
->ptr_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1385 g_hash_table_insert (image_set
->ptr_cache
, el_class
, result
);
1386 mono_image_set_unlock (image_set
);
1388 mono_image_lock (image
);
1389 if (image
->ptr_cache
) {
1391 if ((result2
= (MonoClass
*)g_hash_table_lookup (image
->ptr_cache
, el_class
))) {
1392 mono_image_unlock (image
);
1393 MONO_PROFILER_RAISE (class_failed
, (result
));
1397 image
->ptr_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1399 g_hash_table_insert (image
->ptr_cache
, el_class
, result
);
1400 mono_image_unlock (image
);
1403 MONO_PROFILER_RAISE (class_loaded
, (result
));
1409 mono_class_create_fnptr (MonoMethodSignature
*sig
)
1411 MonoClass
*result
, *cached
;
1412 static GHashTable
*ptr_hash
= NULL
;
1414 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1416 mono_loader_lock ();
1418 ptr_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1419 cached
= (MonoClass
*)g_hash_table_lookup (ptr_hash
, sig
);
1420 mono_loader_unlock ();
1424 result
= g_new0 (MonoClass
, 1);
1426 result
->parent
= NULL
; /* no parent for PTR types */
1427 result
->name_space
= "System";
1428 result
->name
= "MonoFNPtrFakeClass";
1429 result
->class_kind
= MONO_CLASS_POINTER
;
1431 result
->image
= mono_defaults
.corlib
; /* need to fix... */
1432 result
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
1433 result
->min_align
= sizeof (gpointer
);
1434 result
->cast_class
= result
->element_class
= result
;
1435 result
->this_arg
.type
= result
->_byval_arg
.type
= MONO_TYPE_FNPTR
;
1436 result
->this_arg
.data
.method
= result
->_byval_arg
.data
.method
= sig
;
1437 result
->this_arg
.byref
= TRUE
;
1438 result
->blittable
= TRUE
;
1439 result
->inited
= TRUE
;
1441 mono_class_setup_supertypes (result
);
1443 mono_loader_lock ();
1445 cached
= (MonoClass
*)g_hash_table_lookup (ptr_hash
, sig
);
1448 mono_loader_unlock ();
1452 MONO_PROFILER_RAISE (class_loading
, (result
));
1454 UnlockedAdd (&classes_size
, sizeof (MonoClassPointer
));
1455 ++class_pointer_count
;
1457 g_hash_table_insert (ptr_hash
, sig
, result
);
1459 mono_loader_unlock ();
1461 MONO_PROFILER_RAISE (class_loaded
, (result
));
1468 print_implemented_interfaces (MonoClass
*klass
)
1472 GPtrArray
*ifaces
= NULL
;
1474 int ancestor_level
= 0;
1476 name
= mono_type_get_full_name (klass
);
1477 printf ("Packed interface table for class %s has size %d\n", name
, klass
->interface_offsets_count
);
1480 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
1481 char *ic_name
= mono_type_get_full_name (klass
->interfaces_packed
[i
]);
1482 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i
,
1483 klass
->interfaces_packed
[i
]->interface_id
,
1484 klass
->interface_offsets_packed
[i
],
1485 mono_class_get_method_count (klass
->interfaces_packed
[i
]),
1489 printf ("Interface flags: ");
1490 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
1491 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
1492 printf ("(%d,T)", i
);
1494 printf ("(%d,F)", i
);
1496 printf ("Dump interface flags:");
1497 #ifdef COMPRESSED_INTERFACE_BITMAP
1499 const uint8_t* p
= klass
->interface_bitmap
;
1500 i
= klass
->max_interface_id
;
1502 printf (" %d x 00 %02X", p
[0], p
[1]);
1508 for (i
= 0; i
< ((((klass
->max_interface_id
+ 1) >> 3)) + (((klass
->max_interface_id
+ 1) & 7)? 1 :0)); i
++)
1509 printf (" %02X", klass
->interface_bitmap
[i
]);
1512 while (klass
!= NULL
) {
1513 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level
, klass
->name
);
1514 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
1515 if (!mono_error_ok (error
)) {
1516 printf (" Type failed due to %s\n", mono_error_get_message (error
));
1517 mono_error_cleanup (error
);
1518 } else if (ifaces
) {
1519 for (i
= 0; i
< ifaces
->len
; i
++) {
1520 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1521 printf (" [UIID %d] interface %s\n", ic
->interface_id
, ic
->name
);
1522 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i
,
1524 mono_class_interface_offset (klass
, ic
),
1525 mono_class_get_method_count (ic
),
1529 g_ptr_array_free (ifaces
, TRUE
);
1532 klass
= klass
->parent
;
1537 method_is_reabstracted (guint16 flags
)
1539 if ((flags
& METHOD_ATTRIBUTE_ABSTRACT
&& flags
& METHOD_ATTRIBUTE_FINAL
))
1545 * Return the number of virtual methods.
1546 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1547 * Return -1 on failure.
1548 * FIXME It would be nice if this information could be cached somewhere.
1551 count_virtual_methods (MonoClass
*klass
)
1553 int i
, mcount
, vcount
= 0;
1555 klass
= mono_class_get_generic_type_definition (klass
); /*We can find this information by looking at the GTD*/
1557 if (klass
->methods
|| !MONO_CLASS_HAS_STATIC_METADATA (klass
)) {
1558 mono_class_setup_methods (klass
);
1559 if (mono_class_has_failure (klass
))
1562 mcount
= mono_class_get_method_count (klass
);
1563 for (i
= 0; i
< mcount
; ++i
) {
1564 flags
= klass
->methods
[i
]->flags
;
1565 if ((flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
1566 if (method_is_reabstracted (flags
))
1572 int first_idx
= mono_class_get_first_method_idx (klass
);
1573 mcount
= mono_class_get_method_count (klass
);
1574 for (i
= 0; i
< mcount
; ++i
) {
1575 flags
= mono_metadata_decode_table_row_col (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
, MONO_METHOD_FLAGS
);
1577 if ((flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
1578 if (method_is_reabstracted (flags
))
1588 set_interface_and_offset (int num_ifaces
, MonoClass
**interfaces_full
, int *interface_offsets_full
, MonoClass
*ic
, int offset
, mono_bool force_set
)
1591 for (i
= 0; i
< num_ifaces
; ++i
) {
1592 if (interfaces_full
[i
] && interfaces_full
[i
]->interface_id
== ic
->interface_id
) {
1595 interface_offsets_full
[i
] = offset
;
1598 if (interfaces_full
[i
])
1600 interfaces_full
[i
] = ic
;
1601 interface_offsets_full
[i
] = offset
;
1607 #ifdef COMPRESSED_INTERFACE_BITMAP
1610 * Compressed interface bitmap design.
1612 * Interface bitmaps take a large amount of memory, because their size is
1613 * linear with the maximum interface id assigned in the process (each interface
1614 * is assigned a unique id as it is loaded). The number of interface classes
1615 * is high because of the many implicit interfaces implemented by arrays (we'll
1616 * need to lazy-load them in the future).
1617 * Most classes implement a very small number of interfaces, so the bitmap is
1618 * sparse. This bitmap needs to be checked by interface casts, so access to the
1619 * needed bit must be fast and doable with few jit instructions.
1621 * The current compression format is as follows:
1622 * *) it is a sequence of one or more two-byte elements
1623 * *) the first byte in the element is the count of empty bitmap bytes
1624 * at the current bitmap position
1625 * *) the second byte in the element is an actual bitmap byte at the current
1628 * As an example, the following compressed bitmap bytes:
1629 * 0x07 0x01 0x00 0x7
1630 * correspond to the following bitmap:
1631 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1633 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1634 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1635 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1639 * mono_compress_bitmap:
1640 * \param dest destination buffer
1641 * \param bitmap bitmap buffer
1642 * \param size size of \p bitmap in bytes
1644 * This is a mono internal function.
1645 * The \p bitmap data is compressed into a format that is small but
1646 * still searchable in few instructions by the JIT and runtime.
1647 * The compressed data is stored in the buffer pointed to by the
1648 * \p dest array. Passing a NULL value for \p dest allows to just compute
1649 * the size of the buffer.
1650 * This compression algorithm assumes the bits set in the bitmap are
1651 * few and far between, like in interface bitmaps.
1652 * \returns The size of the compressed bitmap in bytes.
1655 mono_compress_bitmap (uint8_t *dest
, const uint8_t *bitmap
, int size
)
1659 const uint8_t *end
= bitmap
+ size
;
1660 while (bitmap
< end
) {
1661 if (*bitmap
|| numz
== 255) {
1685 * mono_class_interface_match:
1686 * \param bitmap a compressed bitmap buffer
1687 * \param id the index to check in the bitmap
1689 * This is a mono internal function.
1690 * Checks if a bit is set in a compressed interface bitmap. \p id must
1691 * be already checked for being smaller than the maximum id encoded in the
1694 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1698 mono_class_interface_match (const uint8_t *bitmap
, int id
)
1701 id
-= bitmap
[0] * 8;
1705 return bitmap
[1] & (1 << id
);
1716 int insertion_order
;
1720 compare_by_interface_id (const void *a
, const void *b
)
1722 const ClassAndOffset
*ca
= (const ClassAndOffset
*)a
;
1723 const ClassAndOffset
*cb
= (const ClassAndOffset
*)b
;
1725 /* Sort on interface_id, but keep equal elements in the same relative
1727 int primary_order
= ca
->ic
->interface_id
- cb
->ic
->interface_id
;
1728 if (primary_order
!= 0)
1729 return primary_order
;
1731 return ca
->insertion_order
- cb
->insertion_order
;
1735 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1736 * LOCKING: Acquires the loader lock.
1739 setup_interface_offsets (MonoClass
*klass
, int cur_slot
, gboolean overwrite
)
1743 int i
, j
, num_ifaces
;
1745 MonoClass
**interfaces_full
= NULL
;
1746 int *interface_offsets_full
= NULL
;
1748 GPtrArray
**ifaces_array
= NULL
;
1749 int interface_offsets_count
;
1751 num_ifaces
= interface_offsets_count
= 0;
1753 mono_loader_lock ();
1755 mono_class_setup_supertypes (klass
);
1757 if (mono_class_is_ginst (klass
)) {
1758 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
1760 interface_offsets_count
= num_ifaces
= gklass
->interface_offsets_count
;
1761 interfaces_full
= (MonoClass
**)g_malloc (sizeof (MonoClass
*) * num_ifaces
);
1762 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
1765 for (int i
= 0; i
< num_ifaces
; ++i
) {
1766 MonoClass
*gklass_ic
= gklass
->interfaces_packed
[i
];
1767 MonoClass
*inflated
= mono_class_inflate_generic_class_checked (gklass_ic
, mono_class_get_context(klass
), error
);
1768 if (!is_ok (error
)) {
1769 char *name
= mono_type_get_full_name (gklass_ic
);
1770 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1776 mono_class_setup_interface_id_internal (inflated
);
1778 interfaces_full
[i
] = inflated
;
1779 interface_offsets_full
[i
] = gklass
->interface_offsets_packed
[i
];
1781 int count
= count_virtual_methods (inflated
);
1783 char *name
= mono_type_get_full_name (inflated
);
1784 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1790 cur_slot
= MAX (cur_slot
, interface_offsets_full
[i
] + count
);
1791 max_iid
= MAX (max_iid
, inflated
->interface_id
);
1796 /* compute maximum number of slots and maximum interface id */
1798 num_ifaces
= 0; /* this can include duplicated ones */
1799 ifaces_array
= g_new0 (GPtrArray
*, klass
->idepth
);
1800 for (j
= 0; j
< klass
->idepth
; j
++) {
1801 k
= klass
->supertypes
[j
];
1803 num_ifaces
+= k
->interface_count
;
1804 for (i
= 0; i
< k
->interface_count
; i
++) {
1805 ic
= k
->interfaces
[i
];
1807 /* A gparam does not have any interface_id set. */
1808 if (! mono_class_is_gparam (ic
))
1809 mono_class_setup_interface_id_internal (ic
);
1811 if (max_iid
< ic
->interface_id
)
1812 max_iid
= ic
->interface_id
;
1814 ifaces
= mono_class_get_implemented_interfaces (k
, error
);
1815 if (!mono_error_ok (error
)) {
1816 char *name
= mono_type_get_full_name (k
);
1817 mono_class_set_type_load_failure (klass
, "Error getting the interfaces of %s due to %s", name
, mono_error_get_message (error
));
1819 mono_error_cleanup (error
);
1824 num_ifaces
+= ifaces
->len
;
1825 for (i
= 0; i
< ifaces
->len
; ++i
) {
1826 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1827 if (max_iid
< ic
->interface_id
)
1828 max_iid
= ic
->interface_id
;
1830 ifaces_array
[j
] = ifaces
;
1834 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
1836 if (max_iid
< klass
->interface_id
)
1837 max_iid
= klass
->interface_id
;
1840 /* compute vtable offset for interfaces */
1841 interfaces_full
= (MonoClass
**)g_malloc0 (sizeof (MonoClass
*) * num_ifaces
);
1842 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
1844 for (i
= 0; i
< num_ifaces
; i
++)
1845 interface_offsets_full
[i
] = -1;
1847 /* skip the current class */
1848 for (j
= 0; j
< klass
->idepth
- 1; j
++) {
1849 k
= klass
->supertypes
[j
];
1850 ifaces
= ifaces_array
[j
];
1853 for (i
= 0; i
< ifaces
->len
; ++i
) {
1855 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1857 /*Force the sharing of interface offsets between parent and subtypes.*/
1858 io
= mono_class_interface_offset (k
, ic
);
1859 g_assertf (io
>= 0, "class %s parent %s has no offset for iface %s",
1860 mono_type_get_full_name (klass
),
1861 mono_type_get_full_name (k
),
1862 mono_type_get_full_name (ic
));
1864 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, io
, TRUE
);
1869 g_assert (klass
== klass
->supertypes
[klass
->idepth
- 1]);
1870 ifaces
= ifaces_array
[klass
->idepth
- 1];
1872 for (i
= 0; i
< ifaces
->len
; ++i
) {
1874 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1875 if (set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, cur_slot
, FALSE
))
1877 count
= count_virtual_methods (ic
);
1879 char *name
= mono_type_get_full_name (ic
);
1880 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1889 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
))
1890 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, klass
, cur_slot
, TRUE
);
1892 for (interface_offsets_count
= 0, i
= 0; i
< num_ifaces
; i
++) {
1893 if (interface_offsets_full
[i
] != -1)
1894 interface_offsets_count
++;
1898 /* Publish the data */
1899 klass
->max_interface_id
= max_iid
;
1901 * We might get called multiple times:
1902 * - mono_class_init_internal ()
1903 * - mono_class_setup_vtable ().
1904 * - mono_class_setup_interface_offsets ().
1905 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1906 * means we have to overwrite those when called from other places (#4440).
1908 if (klass
->interfaces_packed
) {
1910 g_assert (klass
->interface_offsets_count
== interface_offsets_count
);
1914 klass
->interface_offsets_count
= interface_offsets_count
;
1915 klass
->interfaces_packed
= (MonoClass
**)mono_class_alloc (klass
, sizeof (MonoClass
*) * interface_offsets_count
);
1916 klass
->interface_offsets_packed
= (guint16
*)mono_class_alloc (klass
, sizeof (guint16
) * interface_offsets_count
);
1917 bsize
= (sizeof (guint8
) * ((max_iid
+ 1) >> 3)) + (((max_iid
+ 1) & 7)? 1 :0);
1918 #ifdef COMPRESSED_INTERFACE_BITMAP
1919 bitmap
= g_malloc0 (bsize
);
1921 bitmap
= (uint8_t *)mono_class_alloc0 (klass
, bsize
);
1923 for (i
= 0; i
< interface_offsets_count
; i
++) {
1924 guint32 id
= interfaces_full
[i
]->interface_id
;
1925 bitmap
[id
>> 3] |= (1 << (id
& 7));
1926 klass
->interfaces_packed
[i
] = interfaces_full
[i
];
1927 klass
->interface_offsets_packed
[i
] = interface_offsets_full
[i
];
1929 #ifdef COMPRESSED_INTERFACE_BITMAP
1930 i
= mono_compress_bitmap (NULL
, bitmap
, bsize
);
1931 klass
->interface_bitmap
= mono_class_alloc0 (klass
, i
);
1932 mono_compress_bitmap (klass
->interface_bitmap
, bitmap
, bsize
);
1935 klass
->interface_bitmap
= bitmap
;
1939 mono_loader_unlock ();
1941 g_free (interfaces_full
);
1942 g_free (interface_offsets_full
);
1944 for (i
= 0; i
< klass
->idepth
; i
++) {
1945 ifaces
= ifaces_array
[i
];
1947 g_ptr_array_free (ifaces
, TRUE
);
1949 g_free (ifaces_array
);
1952 //printf ("JUST DONE: ");
1953 //print_implemented_interfaces (klass);
1959 * Setup interface offsets for interfaces.
1961 * - klass->max_interface_id
1962 * - klass->interface_offsets_count
1963 * - klass->interfaces_packed
1964 * - klass->interface_offsets_packed
1965 * - klass->interface_bitmap
1967 * This function can fail @class.
1971 mono_class_setup_interface_offsets (MonoClass
*klass
)
1973 /* NOTE: This function is only correct for interfaces.
1975 * It assumes that klass's interfaces can be assigned offsets starting
1976 * from 0. That assumption is incorrect for classes and valuetypes.
1978 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) && !mono_class_is_ginst (klass
));
1979 setup_interface_offsets (klass
, 0, FALSE
);
1982 #define DEBUG_INTERFACE_VTABLE_CODE 0
1983 #define TRACE_INTERFACE_VTABLE_CODE 0
1984 #define VERIFY_INTERFACE_VTABLE_CODE 0
1985 #define VTABLE_SELECTOR (1)
1987 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
1988 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
1989 if (!(VTABLE_SELECTOR)) break; \
1993 #define DEBUG_INTERFACE_VTABLE(stmt)
1996 #if TRACE_INTERFACE_VTABLE_CODE
1997 #define TRACE_INTERFACE_VTABLE(stmt) do {\
1998 if (!(VTABLE_SELECTOR)) break; \
2002 #define TRACE_INTERFACE_VTABLE(stmt)
2005 #if VERIFY_INTERFACE_VTABLE_CODE
2006 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
2007 if (!(VTABLE_SELECTOR)) break; \
2011 #define VERIFY_INTERFACE_VTABLE(stmt)
2015 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2017 mono_signature_get_full_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
2021 GString
*res
= g_string_new ("");
2023 g_string_append_c (res
, '(');
2024 for (i
= 0; i
< sig
->param_count
; ++i
) {
2026 g_string_append_c (res
, ',');
2027 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
2029 g_string_append (res
, ")=>");
2030 if (sig
->ret
!= NULL
) {
2031 mono_type_get_desc (res
, sig
->ret
, include_namespace
);
2033 g_string_append (res
, "NULL");
2036 g_string_free (res
, FALSE
);
2040 print_method_signatures (MonoMethod
*im
, MonoMethod
*cm
) {
2041 char *im_sig
= mono_signature_get_full_desc (mono_method_signature_internal (im
), TRUE
);
2042 char *cm_sig
= mono_signature_get_full_desc (mono_method_signature_internal (cm
), TRUE
);
2043 printf ("(IM \"%s\", CM \"%s\")", im_sig
, cm_sig
);
2052 is_wcf_hack_disabled (void)
2054 static char disabled
;
2056 disabled
= g_hasenv ("MONO_DISABLE_WCF_HACK") ? 1 : 2;
2057 return disabled
== 1;
2061 check_interface_method_override (MonoClass
*klass
, MonoMethod
*im
, MonoMethod
*cm
, gboolean require_newslot
, gboolean interface_is_explicitly_implemented_by_class
, gboolean slot_is_empty
)
2063 MonoMethodSignature
*cmsig
, *imsig
;
2064 if (strcmp (im
->name
, cm
->name
) == 0) {
2065 if (! (cm
->flags
& METHOD_ATTRIBUTE_PUBLIC
)) {
2066 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2069 if (! slot_is_empty
) {
2070 if (require_newslot
) {
2071 if (! interface_is_explicitly_implemented_by_class
) {
2072 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2075 if (! (cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
2076 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2080 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2083 cmsig
= mono_method_signature_internal (cm
);
2084 imsig
= mono_method_signature_internal (im
);
2085 if (!cmsig
|| !imsig
) {
2086 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
2090 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
2091 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2092 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
2093 TRACE_INTERFACE_VTABLE (printf ("]"));
2096 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2097 if (mono_security_core_clr_enabled ())
2098 mono_security_core_clr_check_override (klass
, cm
, im
);
2100 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2101 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
2102 char *body_name
= mono_method_full_name (cm
, TRUE
);
2103 char *decl_name
= mono_method_full_name (im
, TRUE
);
2104 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2112 MonoClass
*ic
= im
->klass
;
2113 const char *ic_name_space
= ic
->name_space
;
2114 const char *ic_name
= ic
->name
;
2117 if (! require_newslot
) {
2118 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2121 if (cm
->klass
->rank
== 0) {
2122 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2125 cmsig
= mono_method_signature_internal (cm
);
2126 imsig
= mono_method_signature_internal (im
);
2127 if (!cmsig
|| !imsig
) {
2128 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
2132 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
2133 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2134 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
2135 TRACE_INTERFACE_VTABLE (printf ("]"));
2138 if (mono_class_get_image (ic
) != mono_defaults
.corlib
) {
2139 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2142 if ((ic_name_space
== NULL
) || (strcmp (ic_name_space
, "System.Collections.Generic") != 0)) {
2143 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2146 if ((ic_name
== NULL
) || ((strcmp (ic_name
, "IEnumerable`1") != 0) && (strcmp (ic_name
, "ICollection`1") != 0) && (strcmp (ic_name
, "IList`1") != 0) && (strcmp (ic_name
, "IReadOnlyList`1") != 0) && (strcmp (ic_name
, "IReadOnlyCollection`1") != 0))) {
2147 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2151 subname
= (char*)strstr (cm
->name
, ic_name_space
);
2152 if (subname
!= cm
->name
) {
2153 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2156 subname
+= strlen (ic_name_space
);
2157 if (subname
[0] != '.') {
2158 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2162 if (strstr (subname
, ic_name
) != subname
) {
2163 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2166 subname
+= strlen (ic_name
);
2167 if (subname
[0] != '.') {
2168 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2172 if (strcmp (subname
, im
->name
) != 0) {
2173 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2177 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2178 if (mono_security_core_clr_enabled ())
2179 mono_security_core_clr_check_override (klass
, cm
, im
);
2181 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2182 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
2183 char *body_name
= mono_method_full_name (cm
, TRUE
);
2184 char *decl_name
= mono_method_full_name (im
, TRUE
);
2185 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2195 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2197 foreach_override (gpointer key
, gpointer value
, gpointer user_data
)
2199 MonoMethod
*method
= key
;
2200 MonoMethod
*override
= value
;
2202 char *method_name
= mono_method_get_full_name (method
);
2203 char *override_name
= mono_method_get_full_name (override
);
2204 printf (" Method '%s' has override '%s'\n", method_name
, override_name
);
2205 g_free (method_name
);
2206 g_free (override_name
);
2210 print_overrides (GHashTable
*override_map
, const char *message
)
2213 printf ("Override map \"%s\" START:\n", message
);
2214 g_hash_table_foreach (override_map
, foreach_override
, NULL
);
2215 printf ("Override map \"%s\" END.\n", message
);
2217 printf ("Override map \"%s\" EMPTY.\n", message
);
2222 print_vtable_full (MonoClass
*klass
, MonoMethod
** vtable
, int size
, int first_non_interface_slot
, const char *message
, gboolean print_interfaces
)
2224 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2228 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name
, message
, size
);
2230 if (print_interfaces
) {
2231 print_implemented_interfaces (klass
);
2232 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name
, size
);
2235 if (klass
->parent
) {
2236 parent_size
= klass
->parent
->vtable_size
;
2240 for (i
= 0; i
< size
; ++i
) {
2241 MonoMethod
*cm
= vtable
[i
];
2242 char *cm_name
= cm
? mono_method_full_name (cm
, TRUE
) : g_strdup ("nil");
2243 char newness
= (i
< parent_size
) ? 'O' : ((i
< first_non_interface_slot
) ? 'I' : 'N');
2245 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness
, i
, cm
? cm
->slot
: - 1, cm_name
, cm
);
2253 #if VERIFY_INTERFACE_VTABLE_CODE
2255 mono_method_try_get_vtable_index (MonoMethod
*method
)
2257 if (method
->is_inflated
&& (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
2258 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
2259 if (imethod
->declaring
->is_generic
)
2260 return imethod
->declaring
->slot
;
2262 return method
->slot
;
2266 mono_class_verify_vtable (MonoClass
*klass
)
2269 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2271 printf ("*** Verifying VTable of class '%s' \n", full_name
);
2275 if (!klass
->methods
)
2278 count
= mono_class_get_method_count (klass
);
2279 for (i
= 0; i
< count
; ++i
) {
2280 MonoMethod
*cm
= klass
->methods
[i
];
2283 if (!(cm
->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2287 full_name
= mono_method_full_name (cm
, TRUE
);
2289 slot
= mono_method_try_get_vtable_index (cm
);
2291 if (slot
>= klass
->vtable_size
) {
2292 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name
, slot
, klass
->vtable_size
);
2296 if (slot
>= 0 && klass
->vtable
[slot
] != cm
&& (klass
->vtable
[slot
])) {
2297 char *other_name
= klass
->vtable
[slot
] ? mono_method_full_name (klass
->vtable
[slot
], TRUE
) : g_strdup ("[null value]");
2298 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name
, slot
, other_name
);
2299 g_free (other_name
);
2302 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name
);
2309 mono_method_get_method_definition (MonoMethod
*method
)
2311 while (method
->is_inflated
)
2312 method
= ((MonoMethodInflated
*)method
)->declaring
;
2317 verify_class_overrides (MonoClass
*klass
, MonoMethod
**overrides
, int onum
)
2321 for (i
= 0; i
< onum
; ++i
) {
2322 MonoMethod
*decl
= overrides
[i
* 2];
2323 MonoMethod
*body
= overrides
[i
* 2 + 1];
2325 if (mono_class_get_generic_type_definition (body
->klass
) != mono_class_get_generic_type_definition (klass
)) {
2326 mono_class_set_type_load_failure (klass
, "Method belongs to a different class than the declared one");
2330 if (!(body
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (body
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2331 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
2332 mono_class_set_type_load_failure (klass
, "Method must not be static to override a base type");
2334 mono_class_set_type_load_failure (klass
, "Method must be virtual to override a base type");
2338 if (!(decl
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (decl
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2339 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
2340 mono_class_set_type_load_failure (klass
, "Cannot override a static method in a base type");
2342 mono_class_set_type_load_failure (klass
, "Cannot override a non virtual method in a base type");
2346 if (!mono_class_is_assignable_from_slow (decl
->klass
, klass
)) {
2347 mono_class_set_type_load_failure (klass
, "Method overrides a class or interface that is not extended or implemented by this type");
2351 body
= mono_method_get_method_definition (body
);
2352 decl
= mono_method_get_method_definition (decl
);
2354 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body
, decl
, NULL
)) {
2355 char *body_name
= mono_method_full_name (body
, TRUE
);
2356 char *decl_name
= mono_method_full_name (decl
, TRUE
);
2357 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2366 /*Checks if @klass has @parent as one of it's parents type gtd
2370 * Bar<T> : Foo<Bar<Bar<T>>>
2374 mono_class_has_gtd_parent (MonoClass
*klass
, MonoClass
*parent
)
2376 klass
= mono_class_get_generic_type_definition (klass
);
2377 parent
= mono_class_get_generic_type_definition (parent
);
2378 mono_class_setup_supertypes (klass
);
2379 mono_class_setup_supertypes (parent
);
2381 return klass
->idepth
>= parent
->idepth
&&
2382 mono_class_get_generic_type_definition (klass
->supertypes
[parent
->idepth
- 1]) == parent
;
2386 mono_class_check_vtable_constraints (MonoClass
*klass
, GList
*in_setup
)
2388 MonoGenericInst
*ginst
;
2391 if (!mono_class_is_ginst (klass
)) {
2392 mono_class_setup_vtable_full (klass
, in_setup
);
2393 return !mono_class_has_failure (klass
);
2396 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass
), in_setup
);
2397 if (mono_class_set_type_load_failure_causedby_class (klass
, mono_class_get_generic_class (klass
)->container_class
, "Failed to load generic definition vtable"))
2400 ginst
= mono_class_get_generic_class (klass
)->context
.class_inst
;
2401 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
2403 if (ginst
->type_argv
[i
]->type
!= MONO_TYPE_GENERICINST
)
2405 arg
= mono_class_from_mono_type_internal (ginst
->type_argv
[i
]);
2406 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2407 if (mono_class_has_gtd_parent (klass
, arg
) || mono_class_has_gtd_parent (arg
, klass
))
2409 if (!mono_class_check_vtable_constraints (arg
, in_setup
)) {
2410 mono_class_set_type_load_failure (klass
, "Failed to load generic parameter %d", i
);
2418 * mono_class_setup_vtable:
2420 * Creates the generic vtable of CLASS.
2421 * Initializes the following fields in MonoClass:
2424 * Plus all the fields initialized by setup_interface_offsets ().
2425 * If there is an error during vtable construction, klass->has_failure
2426 * is set and details are stored in a MonoErrorBoxed.
2428 * LOCKING: Acquires the loader lock.
2431 mono_class_setup_vtable (MonoClass
*klass
)
2433 mono_class_setup_vtable_full (klass
, NULL
);
2437 mono_class_setup_vtable_full (MonoClass
*klass
, GList
*in_setup
)
2440 MonoMethod
**overrides
= NULL
;
2441 MonoGenericContext
*context
;
2448 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
2449 /* This sets method->slot for all methods if this is an interface */
2450 mono_class_setup_methods (klass
);
2454 if (mono_class_has_failure (klass
))
2457 if (g_list_find (in_setup
, klass
))
2460 mono_loader_lock ();
2462 if (klass
->vtable
) {
2463 mono_loader_unlock ();
2467 UnlockedIncrement (&mono_stats
.generic_vtable_count
);
2468 in_setup
= g_list_prepend (in_setup
, klass
);
2470 if (mono_class_is_ginst (klass
)) {
2471 if (!mono_class_check_vtable_constraints (klass
, in_setup
)) {
2472 mono_loader_unlock ();
2473 g_list_remove (in_setup
, klass
);
2477 context
= mono_class_get_context (klass
);
2478 type_token
= mono_class_get_generic_class (klass
)->container_class
->type_token
;
2480 context
= (MonoGenericContext
*) mono_class_try_get_generic_container (klass
); //FIXME is this a case of a try?
2481 type_token
= klass
->type_token
;
2484 if (image_is_dynamic (klass
->image
)) {
2485 /* Generic instances can have zero method overrides without causing any harm.
2486 * This is true since we don't do layout all over again for them, we simply inflate
2487 * the layout of the parent.
2489 mono_reflection_get_dynamic_overrides (klass
, &overrides
, &onum
, error
);
2490 if (!is_ok (error
)) {
2491 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
2495 /* The following call fails if there are missing methods in the type */
2496 /* FIXME it's probably a good idea to avoid this for generic instances. */
2497 mono_class_get_overrides_full (klass
->image
, type_token
, &overrides
, &onum
, context
, error
);
2498 if (!is_ok (error
)) {
2499 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
2504 mono_class_setup_vtable_general (klass
, overrides
, onum
, in_setup
);
2508 mono_error_cleanup (error
);
2510 mono_loader_unlock ();
2511 g_list_remove (in_setup
, klass
);
2517 mono_class_need_stelemref_method (MonoClass
*klass
)
2519 return klass
->rank
== 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass
)));
2523 apply_override (MonoClass
*klass
, MonoClass
*override_class
, MonoMethod
**vtable
, MonoMethod
*decl
, MonoMethod
*override
,
2524 GHashTable
**override_map
, GHashTable
**override_class_map
, GHashTable
**conflict_map
)
2527 dslot
= mono_method_get_vtable_slot (decl
);
2529 mono_class_set_type_load_failure (klass
, "");
2533 dslot
+= mono_class_interface_offset (klass
, decl
->klass
);
2534 vtable
[dslot
] = override
;
2535 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override
->klass
)) {
2537 * If override from an interface, then it is an override of a default interface method,
2538 * don't override its slot.
2540 vtable
[dslot
]->slot
= dslot
;
2543 if (!*override_map
) {
2544 *override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2545 *override_class_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2547 GHashTable
*map
= *override_map
;
2548 GHashTable
*class_map
= *override_class_map
;
2550 MonoMethod
*prev_override
= (MonoMethod
*)g_hash_table_lookup (map
, decl
);
2551 MonoClass
*prev_override_class
= (MonoClass
*)g_hash_table_lookup (class_map
, decl
);
2553 g_hash_table_insert (map
, decl
, override
);
2554 g_hash_table_insert (class_map
, decl
, override_class
);
2556 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2557 if (prev_override
) {
2561 * The override methods are part of the generic definition, need to inflate them so their
2562 * parent class becomes the actual interface/class containing the override, i.e.
2564 * class Foo<T> : IFace<T>
2565 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2566 * conflict resolution work.
2568 if (mono_class_is_ginst (override_class
)) {
2569 override
= mono_class_inflate_generic_method_checked (override
, &mono_class_get_generic_class (override_class
)->context
, error
);
2570 mono_error_assert_ok (error
);
2573 if (mono_class_is_ginst (prev_override_class
)) {
2574 prev_override
= mono_class_inflate_generic_method_checked (prev_override
, &mono_class_get_generic_class (prev_override_class
)->context
, error
);
2575 mono_error_assert_ok (error
);
2579 *conflict_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2580 GHashTable
*cmap
= *conflict_map
;
2581 GSList
*entries
= (GSList
*)g_hash_table_lookup (cmap
, decl
);
2582 if (!(decl
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
2583 entries
= g_slist_prepend (entries
, decl
);
2584 entries
= g_slist_prepend (entries
, prev_override
);
2585 entries
= g_slist_prepend (entries
, override
);
2587 g_hash_table_insert (cmap
, decl
, entries
);
2594 handle_dim_conflicts (MonoMethod
**vtable
, MonoClass
*klass
, GHashTable
*conflict_map
)
2596 GHashTableIter iter
;
2598 GSList
*entries
, *l
, *l2
;
2599 GSList
*dim_conflicts
= NULL
;
2601 g_hash_table_iter_init (&iter
, conflict_map
);
2602 while (g_hash_table_iter_next (&iter
, (gpointer
*)&decl
, (gpointer
*)&entries
)) {
2604 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2605 * class of another one.
2607 /* This is O(n^2), but that shouldn't be a problem in practice */
2608 for (l
= entries
; l
; l
= l
->next
) {
2609 for (l2
= entries
; l2
; l2
= l2
->next
) {
2610 MonoMethod
*m1
= (MonoMethod
*)l
->data
;
2611 MonoMethod
*m2
= (MonoMethod
*)l2
->data
;
2612 if (!m1
|| !m2
|| m1
== m2
)
2614 if (mono_class_is_assignable_from_internal (m1
->klass
, m2
->klass
))
2616 else if (mono_class_is_assignable_from_internal (m2
->klass
, m1
->klass
))
2621 MonoMethod
*impl
= NULL
;
2622 for (l
= entries
; l
; l
= l
->next
) {
2625 impl
= (MonoMethod
*)l
->data
;
2629 /* If more than one method is left, we have a conflict */
2630 if (decl
->is_inflated
)
2631 decl
= ((MonoMethodInflated
*)decl
)->declaring
;
2632 dim_conflicts
= g_slist_prepend (dim_conflicts
, decl
);
2634 for (l = entries; l; l = l->next) {
2636 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2641 * Use the implementing method computed above instead of the already
2642 * computed one, which depends on interface ordering.
2644 int ic_offset
= mono_class_interface_offset (klass
, decl
->klass
);
2645 int im_slot
= ic_offset
+ decl
->slot
;
2646 vtable
[im_slot
] = impl
;
2648 g_slist_free (entries
);
2650 if (dim_conflicts
) {
2651 mono_loader_lock ();
2652 klass
->has_dim_conflicts
= 1;
2653 mono_loader_unlock ();
2656 * Exceptions are thrown at method call time and only for the methods which have
2657 * conflicts, so just save them in the class.
2660 /* Make a copy of the list from the class mempool */
2661 GSList
*conflicts
= (GSList
*)mono_class_alloc0 (klass
, g_slist_length (dim_conflicts
) * sizeof (GSList
));
2663 for (l
= dim_conflicts
; l
; l
= l
->next
) {
2664 conflicts
[i
].data
= l
->data
;
2665 conflicts
[i
].next
= &conflicts
[i
+ 1];
2668 conflicts
[i
- 1].next
= NULL
;
2670 mono_class_set_dim_conflicts (klass
, conflicts
);
2671 g_slist_free (dim_conflicts
);
2676 print_unimplemented_interface_method_info (MonoClass
*klass
, MonoClass
*ic
, MonoMethod
*im
, int im_slot
, MonoMethod
**overrides
, int onum
)
2679 char *method_signature
;
2682 for (index
= 0; index
< onum
; ++index
) {
2683 mono_trace_warning (MONO_TRACE_TYPE
, " at slot %d: %s (%d) overrides %s (%d)", im_slot
, overrides
[index
*2+1]->name
,
2684 overrides
[index
*2+1]->slot
, overrides
[index
*2]->name
, overrides
[index
*2]->slot
);
2686 method_signature
= mono_signature_get_desc (mono_method_signature_internal (im
), FALSE
);
2687 type_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2688 mono_trace_warning (MONO_TRACE_TYPE
, "no implementation for interface method %s::%s(%s) in class %s",
2689 mono_type_get_name (m_class_get_byval_arg (ic
)), im
->name
, method_signature
, type_name
);
2690 g_free (method_signature
);
2692 mono_class_setup_methods (klass
);
2693 if (mono_class_has_failure (klass
)) {
2694 char *name
= mono_type_get_full_name (klass
);
2695 mono_trace_warning (MONO_TRACE_TYPE
, "CLASS %s failed to resolve methods", name
);
2699 mcount
= mono_class_get_method_count (klass
);
2700 for (index
= 0; index
< mcount
; ++index
) {
2701 MonoMethod
*cm
= klass
->methods
[index
];
2702 method_signature
= mono_signature_get_desc (mono_method_signature_internal (cm
), TRUE
);
2704 mono_trace_warning (MONO_TRACE_TYPE
, "METHOD %s(%s)", cm
->name
, method_signature
);
2705 g_free (method_signature
);
2710 * mono_class_get_virtual_methods:
2712 * Iterate over the virtual methods of KLASS.
2714 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2717 mono_class_get_virtual_methods (MonoClass
* klass
, gpointer
*iter
)
2719 gboolean static_iter
= FALSE
;
2725 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2726 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2729 if ((gsize
)(*iter
) & 1)
2731 /* Use the static metadata only if klass->methods is not yet initialized */
2732 if (!static_iter
&& !(klass
->methods
|| !MONO_CLASS_HAS_STATIC_METADATA (klass
)))
2736 MonoMethod
** methodptr
;
2739 mono_class_setup_methods (klass
);
2741 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2742 * FIXME we should better report this error to the caller
2744 if (!klass
->methods
)
2746 /* start from the first */
2747 methodptr
= &klass
->methods
[0];
2749 methodptr
= (MonoMethod
**)*iter
;
2753 g_assert ((guint64
)(*iter
) > 0x100);
2754 int mcount
= mono_class_get_method_count (klass
);
2755 while (methodptr
< &klass
->methods
[mcount
]) {
2756 if (*methodptr
&& ((*methodptr
)->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2760 if (methodptr
< &klass
->methods
[mcount
]) {
2767 /* Search directly in metadata to avoid calling setup_methods () */
2768 MonoMethod
*res
= NULL
;
2774 start_index
= GPOINTER_TO_UINT (*iter
) >> 1;
2777 int first_idx
= mono_class_get_first_method_idx (klass
);
2778 int mcount
= mono_class_get_method_count (klass
);
2779 for (i
= start_index
; i
< mcount
; ++i
) {
2782 /* first_idx points into the methodptr table */
2783 flags
= mono_metadata_decode_table_row_col (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
, MONO_METHOD_FLAGS
);
2785 if (flags
& METHOD_ATTRIBUTE_VIRTUAL
)
2791 res
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| (first_idx
+ i
+ 1), klass
, NULL
, error
);
2792 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2794 /* Add 1 here so the if (*iter) check fails */
2795 *iter
= GUINT_TO_POINTER (((i
+ 1) << 1) | 1);
2804 print_vtable_layout_result (MonoClass
*klass
, MonoMethod
**vtable
, int cur_slot
)
2808 print_implemented_interfaces (klass
);
2810 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
2811 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
2814 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass
)),
2815 klass
->vtable_size
, icount
);
2817 for (i
= 0; i
< cur_slot
; ++i
) {
2822 printf (" slot assigned: %03d, slot index: %03d %s\n", i
, cm
->slot
,
2823 mono_method_get_full_name (cm
));
2825 printf (" slot assigned: %03d, <null>\n", i
);
2831 printf ("Interfaces %s.%s (max_iid = %d)\n", klass
->name_space
,
2832 klass
->name
, klass
->max_interface_id
);
2834 for (i
= 0; i
< klass
->interface_count
; i
++) {
2835 MonoClass
*ic
= klass
->interfaces
[i
];
2836 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2837 mono_class_interface_offset (klass
, ic
),
2838 count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
2841 for (MonoClass
*k
= klass
->parent
; k
; k
= k
->parent
) {
2842 for (i
= 0; i
< k
->interface_count
; i
++) {
2843 MonoClass
*ic
= k
->interfaces
[i
];
2844 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2845 mono_class_interface_offset (klass
, ic
),
2846 count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
2853 * LOCKING: this is supposed to be called with the loader lock held.
2856 mono_class_setup_vtable_general (MonoClass
*klass
, MonoMethod
**overrides
, int onum
, GList
*in_setup
)
2860 MonoMethod
**vtable
= NULL
;
2861 int i
, max_vtsize
= 0, cur_slot
= 0;
2862 GPtrArray
*ifaces
= NULL
;
2863 GHashTable
*override_map
= NULL
;
2864 GHashTable
*override_class_map
= NULL
;
2865 GHashTable
*conflict_map
= NULL
;
2867 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2868 int first_non_interface_slot
;
2870 GSList
*virt_methods
= NULL
, *l
;
2871 int stelemref_slot
= 0;
2878 if (overrides
&& !verify_class_overrides (klass
, overrides
, onum
))
2881 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
2882 if (!mono_error_ok (error
)) {
2883 char *name
= mono_type_get_full_name (klass
);
2884 mono_class_set_type_load_failure (klass
, "Could not resolve %s interfaces due to %s", name
, mono_error_get_message (error
));
2886 mono_error_cleanup (error
);
2888 } else if (ifaces
) {
2889 for (i
= 0; i
< ifaces
->len
; i
++) {
2890 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2891 max_vtsize
+= mono_class_get_method_count (ic
);
2893 g_ptr_array_free (ifaces
, TRUE
);
2897 if (klass
->parent
) {
2898 mono_class_init_internal (klass
->parent
);
2899 mono_class_setup_vtable_full (klass
->parent
, in_setup
);
2901 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Parent class failed to load"))
2904 max_vtsize
+= klass
->parent
->vtable_size
;
2905 cur_slot
= klass
->parent
->vtable_size
;
2908 max_vtsize
+= mono_class_get_method_count (klass
);
2910 /*Array have a slot for stelemref*/
2911 if (mono_class_need_stelemref_method (klass
)) {
2912 stelemref_slot
= cur_slot
;
2917 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
2919 cur_slot
= setup_interface_offsets (klass
, cur_slot
, TRUE
);
2920 if (cur_slot
== -1) /*setup_interface_offsets fails the type.*/
2923 DEBUG_INTERFACE_VTABLE (first_non_interface_slot
= cur_slot
);
2925 /* Optimized version for generic instances */
2926 if (mono_class_is_ginst (klass
)) {
2928 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
2931 mono_class_setup_vtable_full (gklass
, in_setup
);
2932 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Could not load generic definition"))
2935 tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * gklass
->vtable_size
);
2936 klass
->vtable_size
= gklass
->vtable_size
;
2937 for (i
= 0; i
< gklass
->vtable_size
; ++i
)
2938 if (gklass
->vtable
[i
]) {
2939 MonoMethod
*inflated
= mono_class_inflate_generic_method_full_checked (gklass
->vtable
[i
], klass
, mono_class_get_context (klass
), error
);
2940 goto_if_nok (error
, fail
);
2942 tmp
[i
]->slot
= gklass
->vtable
[i
]->slot
;
2944 mono_memory_barrier ();
2945 klass
->vtable
= tmp
;
2947 mono_loader_lock ();
2948 klass
->has_dim_conflicts
= gklass
->has_dim_conflicts
;
2949 mono_loader_unlock ();
2951 /* Have to set method->slot for abstract virtual methods */
2952 if (klass
->methods
&& gklass
->methods
) {
2953 int mcount
= mono_class_get_method_count (klass
);
2954 for (i
= 0; i
< mcount
; ++i
)
2955 if (klass
->methods
[i
]->slot
== -1)
2956 klass
->methods
[i
]->slot
= gklass
->methods
[i
]->slot
;
2959 if (mono_print_vtable
)
2960 print_vtable_layout_result (klass
, klass
->vtable
, gklass
->vtable_size
);
2965 vtable
= (MonoMethod
**)g_malloc0 (sizeof (gpointer
) * max_vtsize
);
2967 if (klass
->parent
&& klass
->parent
->vtable_size
) {
2968 MonoClass
*parent
= klass
->parent
;
2971 memcpy (vtable
, parent
->vtable
, sizeof (gpointer
) * parent
->vtable_size
);
2973 // Also inherit parent interface vtables, just as a starting point.
2974 // This is needed otherwise bug-77127.exe fails when the property methods
2975 // have different names in the iterface and the class, because for child
2976 // classes the ".override" information is not used anymore.
2977 for (i
= 0; i
< parent
->interface_offsets_count
; i
++) {
2978 MonoClass
*parent_interface
= parent
->interfaces_packed
[i
];
2979 int interface_offset
= mono_class_interface_offset (klass
, parent_interface
);
2980 /*FIXME this is now dead code as this condition will never hold true.
2981 Since interface offsets are inherited then the offset of an interface implemented
2982 by a parent will never be the out of it's vtable boundary.
2984 if (interface_offset
>= parent
->vtable_size
) {
2985 int parent_interface_offset
= mono_class_interface_offset (parent
, parent_interface
);
2988 mono_class_setup_methods (parent_interface
); /*FIXME Just kill this whole chunk of dead code*/
2989 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface
->name_space
, parent_interface
->name
));
2990 int mcount
= mono_class_get_method_count (parent_interface
);
2991 for (j
= 0; j
< mcount
&& !mono_class_has_failure (klass
); j
++) {
2992 vtable
[interface_offset
+ j
] = parent
->vtable
[parent_interface_offset
+ j
];
2993 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
2994 parent_interface_offset
+ j
, parent_interface_offset
, j
,
2995 interface_offset
+ j
, interface_offset
, j
));
3002 /*Array have a slot for stelemref*/
3003 if (mono_class_need_stelemref_method (klass
)) {
3004 MonoMethod
*method
= mono_marshal_get_virtual_stelemref (klass
);
3006 method
->slot
= stelemref_slot
;
3008 g_assert (method
->slot
== stelemref_slot
);
3010 vtable
[stelemref_slot
] = method
;
3013 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER INHERITING PARENT VTABLE", TRUE
));
3015 /* Process overrides from interface default methods */
3016 // FIXME: Ordering between interfaces
3017 for (int ifindex
= 0; ifindex
< klass
->interface_offsets_count
; ifindex
++) {
3018 ic
= klass
->interfaces_packed
[ifindex
];
3020 mono_class_setup_methods (ic
);
3021 if (mono_class_has_failure (ic
))
3024 MonoMethod
**iface_overrides
;
3026 mono_class_get_overrides_full (ic
->image
, ic
->type_token
, &iface_overrides
, &iface_onum
, mono_class_get_context (ic
), error
);
3027 goto_if_nok (error
, fail
);
3028 for (int i
= 0; i
< iface_onum
; i
++) {
3029 MonoMethod
*decl
= iface_overrides
[i
*2];
3030 MonoMethod
*override
= iface_overrides
[i
*2 + 1];
3031 if (decl
->is_inflated
) {
3032 override
= mono_class_inflate_generic_method_checked (override
, mono_method_get_context (decl
), error
);
3033 mono_error_assert_ok (error
);
3035 if (!apply_override (klass
, ic
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
3038 g_free (iface_overrides
);
3041 /* override interface methods */
3042 for (i
= 0; i
< onum
; i
++) {
3043 MonoMethod
*decl
= overrides
[i
*2];
3044 MonoMethod
*override
= overrides
[i
*2 + 1];
3045 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
3046 if (!apply_override (klass
, klass
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
3051 TRACE_INTERFACE_VTABLE (print_overrides (override_map
, "AFTER OVERRIDING INTERFACE METHODS"));
3052 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER OVERRIDING INTERFACE METHODS", FALSE
));
3055 * Create a list of virtual methods to avoid calling
3056 * mono_class_get_virtual_methods () which is slow because of the metadata
3060 gpointer iter
= NULL
;
3063 virt_methods
= NULL
;
3064 while ((cm
= mono_class_get_virtual_methods (klass
, &iter
))) {
3065 virt_methods
= g_slist_prepend (virt_methods
, cm
);
3067 if (mono_class_has_failure (klass
))
3071 // Loop on all implemented interfaces...
3072 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
3073 MonoClass
*parent
= klass
->parent
;
3075 gboolean interface_is_explicitly_implemented_by_class
;
3078 ic
= klass
->interfaces_packed
[i
];
3079 ic_offset
= mono_class_interface_offset (klass
, ic
);
3081 mono_class_setup_methods (ic
);
3082 if (mono_class_has_failure (ic
))
3085 // Check if this interface is explicitly implemented (instead of just inherited)
3086 if (parent
!= NULL
) {
3087 int implemented_interfaces_index
;
3088 interface_is_explicitly_implemented_by_class
= FALSE
;
3089 for (implemented_interfaces_index
= 0; implemented_interfaces_index
< klass
->interface_count
; implemented_interfaces_index
++) {
3090 if (ic
== klass
->interfaces
[implemented_interfaces_index
]) {
3091 interface_is_explicitly_implemented_by_class
= TRUE
;
3096 interface_is_explicitly_implemented_by_class
= TRUE
;
3099 // Loop on all interface methods...
3100 int mcount
= mono_class_get_method_count (ic
);
3101 for (im_index
= 0; im_index
< mcount
; im_index
++) {
3102 gboolean foundOverrideInClassOrParent
= FALSE
;
3103 MonoMethod
*im
= ic
->methods
[im_index
];
3104 int im_slot
= ic_offset
+ im
->slot
;
3105 MonoMethod
*override_im
= (override_map
!= NULL
) ? (MonoMethod
*)g_hash_table_lookup (override_map
, im
) : NULL
;
3107 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
3110 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im
,1)));
3115 // First look for a suitable method among the class methods
3116 for (l
= virt_methods
; l
; l
= l
->next
) {
3117 cm
= (MonoMethod
*)l
->data
;
3118 TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot
, ic
->name_space
, ic
->name
, im
->name
, cm
->klass
->name_space
, cm
->klass
->name
, cm
->name
, interface_is_explicitly_implemented_by_class
, (vtable
[im_slot
] == NULL
)));
3119 if (check_interface_method_override (klass
, im
, cm
, TRUE
, interface_is_explicitly_implemented_by_class
, (vtable
[im_slot
] == NULL
))) {
3120 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3121 vtable
[im_slot
] = cm
;
3122 foundOverrideInClassOrParent
= TRUE
;
3123 /* Why do we need this? */
3128 g_hash_table_remove(conflict_map
, im
);
3130 TRACE_INTERFACE_VTABLE (printf ("\n"));
3131 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
3135 // If the slot is still empty, look in all the inherited virtual methods...
3136 if ((vtable
[im_slot
] == NULL
) && klass
->parent
!= NULL
) {
3137 MonoClass
*parent
= klass
->parent
;
3138 // Reverse order, so that last added methods are preferred
3139 for (cm_index
= parent
->vtable_size
- 1; cm_index
>= 0; cm_index
--) {
3140 cm
= parent
->vtable
[cm_index
];
3142 TRACE_INTERFACE_VTABLE ((cm
!= NULL
) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot
, ic
->name_space
, ic
->name
, im
->name
, cm
->klass
->name_space
, cm
->klass
->name
, cm
->name
));
3143 if ((cm
!= NULL
) && check_interface_method_override (klass
, im
, cm
, FALSE
, FALSE
, TRUE
)) {
3144 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3145 vtable
[im_slot
] = cm
;
3146 foundOverrideInClassOrParent
= TRUE
;
3147 /* Why do we need this? */
3152 g_hash_table_remove(conflict_map
, im
);
3155 TRACE_INTERFACE_VTABLE (printf ("\n"));
3156 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
3161 if (vtable
[im_slot
] == NULL
) {
3162 if (!(im
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)) {
3163 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im
, 1)));
3164 vtable
[im_slot
] = im
;
3168 if (override_im
!= NULL
&& !foundOverrideInClassOrParent
)
3169 g_assert (vtable
[im_slot
] == override_im
);
3173 // If the class is not abstract, check that all its interface slots are full.
3174 // The check is done here and not directly at the end of the loop above because
3175 // it can happen (for injected generic array interfaces) that the same slot is
3176 // processed multiple times (those interfaces have overlapping slots), and it
3177 // will not always be the first pass the one that fills the slot.
3178 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
3179 if (!mono_class_is_abstract (klass
)) {
3180 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
3184 ic
= klass
->interfaces_packed
[i
];
3185 ic_offset
= mono_class_interface_offset (klass
, ic
);
3187 int mcount
= mono_class_get_method_count (ic
);
3188 for (im_index
= 0; im_index
< mcount
; im_index
++) {
3189 MonoMethod
*im
= ic
->methods
[im_index
];
3190 int im_slot
= ic_offset
+ im
->slot
;
3192 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
3194 if (im
->is_reabstracted
== 1)
3197 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3198 im_slot
, ic
->name_space
, ic
->name
, im
->name
, (vtable
[im_slot
] == NULL
)));
3199 if (vtable
[im_slot
] == NULL
) {
3200 print_unimplemented_interface_method_info (klass
, ic
, im
, im_slot
, overrides
, onum
);
3207 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER SETTING UP INTERFACE METHODS", FALSE
));
3208 for (l
= virt_methods
; l
; l
= l
->next
) {
3209 cm
= (MonoMethod
*)l
->data
;
3211 * If the method is REUSE_SLOT, we must check in the
3212 * base class for a method to override.
3214 if (!(cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
3216 for (k
= klass
->parent
; k
; k
= k
->parent
) {
3221 while ((m1
= mono_class_get_virtual_methods (k
, &k_iter
))) {
3222 MonoMethodSignature
*cmsig
, *m1sig
;
3224 cmsig
= mono_method_signature_internal (cm
);
3225 m1sig
= mono_method_signature_internal (m1
);
3227 if (!cmsig
|| !m1sig
) /* FIXME proper error message, use signature_checked? */
3230 if (!strcmp(cm
->name
, m1
->name
) &&
3231 mono_metadata_signature_equal (cmsig
, m1sig
)) {
3233 if (mono_security_core_clr_enabled ())
3234 mono_security_core_clr_check_override (klass
, cm
, m1
);
3236 slot
= mono_method_get_vtable_slot (m1
);
3240 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, m1
, NULL
)) {
3241 char *body_name
= mono_method_full_name (cm
, TRUE
);
3242 char *decl_name
= mono_method_full_name (m1
, TRUE
);
3243 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
3249 g_assert (cm
->slot
< max_vtsize
);
3251 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3252 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3253 mono_method_full_name (m1
, 1), m1
,
3254 mono_method_full_name (cm
, 1), cm
));
3255 g_hash_table_insert (override_map
, m1
, cm
);
3259 if (mono_class_has_failure (k
))
3269 /*Non final newslot methods must be given a non-interface vtable slot*/
3270 if ((cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
) && !(cm
->flags
& METHOD_ATTRIBUTE_FINAL
) && cm
->slot
>= 0)
3274 cm
->slot
= cur_slot
++;
3276 if (!(cm
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
3277 vtable
[cm
->slot
] = cm
;
3280 /* override non interface methods */
3281 for (i
= 0; i
< onum
; i
++) {
3282 MonoMethod
*decl
= overrides
[i
*2];
3283 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
3284 g_assert (decl
->slot
!= -1);
3285 vtable
[decl
->slot
] = overrides
[i
*2 + 1];
3286 overrides
[i
* 2 + 1]->slot
= decl
->slot
;
3288 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3289 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3290 mono_method_full_name (decl
, 1), decl
,
3291 mono_method_full_name (overrides
[i
* 2 + 1], 1), overrides
[i
* 2 + 1]));
3292 g_hash_table_insert (override_map
, decl
, overrides
[i
* 2 + 1]);
3294 if (mono_security_core_clr_enabled ())
3295 mono_security_core_clr_check_override (klass
, vtable
[decl
->slot
], decl
);
3300 * If a method occupies more than one place in the vtable, and it is
3301 * overriden, then change the other occurances too.
3306 for (i
= 0; i
< max_vtsize
; ++i
)
3308 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i
, mono_method_full_name (vtable
[i
], 1), vtable
[i
]));
3310 cm
= (MonoMethod
*)g_hash_table_lookup (override_map
, vtable
[i
]);
3315 g_hash_table_destroy (override_map
);
3316 override_map
= NULL
;
3319 if (override_class_map
)
3320 g_hash_table_destroy (override_class_map
);
3323 handle_dim_conflicts (vtable
, klass
, conflict_map
);
3324 g_hash_table_destroy (conflict_map
);
3327 g_slist_free (virt_methods
);
3328 virt_methods
= NULL
;
3330 g_assert (cur_slot
<= max_vtsize
);
3332 /* Ensure that all vtable slots are filled with concrete instance methods */
3333 // Now it is okay to implement a class that is not abstract and implements a interface that has an abstract method because it's reabstracted
3334 if (!mono_class_is_abstract (klass
)) {
3335 for (i
= 0; i
< cur_slot
; ++i
) {
3336 if (vtable
[i
] == NULL
|| (vtable
[i
]->flags
& (METHOD_ATTRIBUTE_ABSTRACT
| METHOD_ATTRIBUTE_STATIC
))) {
3337 if (vtable
[i
]->is_reabstracted
== 1)
3339 char *type_name
= mono_type_get_full_name (klass
);
3340 char *method_name
= vtable
[i
] ? mono_method_full_name (vtable
[i
], TRUE
) : g_strdup ("none");
3341 mono_class_set_type_load_failure (klass
, "Type %s has invalid vtable method slot %d with method %s", type_name
, i
, method_name
);
3343 g_free (method_name
);
3345 if (mono_print_vtable
)
3346 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3354 if (mono_class_is_ginst (klass
)) {
3355 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
3357 mono_class_init_internal (gklass
);
3359 klass
->vtable_size
= MAX (gklass
->vtable_size
, cur_slot
);
3361 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
3362 if (klass
->vtable_size
)
3363 g_assert (cur_slot
== klass
->vtable_size
);
3364 klass
->vtable_size
= cur_slot
;
3367 /* Try to share the vtable with our parent. */
3368 if (klass
->parent
&& (klass
->parent
->vtable_size
== klass
->vtable_size
) && (memcmp (klass
->parent
->vtable
, vtable
, sizeof (gpointer
) * klass
->vtable_size
) == 0)) {
3369 mono_memory_barrier ();
3370 klass
->vtable
= klass
->parent
->vtable
;
3372 MonoMethod
**tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * klass
->vtable_size
);
3373 memcpy (tmp
, vtable
, sizeof (gpointer
) * klass
->vtable_size
);
3374 mono_memory_barrier ();
3375 klass
->vtable
= tmp
;
3378 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass
, klass
->vtable
, klass
->vtable_size
, first_non_interface_slot
, "FINALLY", FALSE
));
3379 if (mono_print_vtable
)
3380 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3384 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass
));
3389 char *name
= mono_type_get_full_name (klass
);
3391 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed due to: %s", name
, mono_error_get_message (error
));
3393 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed", name
);
3394 mono_error_cleanup (error
);
3396 if (mono_print_vtable
)
3397 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3402 g_hash_table_destroy (override_map
);
3404 g_slist_free (virt_methods
);
3409 concat_two_strings_with_zero (MonoImage
*image
, const char *s1
, const char *s2
)
3411 int null_length
= strlen ("(null)");
3412 int len
= (s1
? strlen (s1
) : null_length
) + (s2
? strlen (s2
) : null_length
) + 2;
3413 char *s
= (char *)mono_image_alloc (image
, len
);
3416 result
= g_snprintf (s
, len
, "%s%c%s", s1
? s1
: "(null)", '\0', s2
? s2
: "(null)");
3417 g_assert (result
== len
- 1);
3424 init_sizes_with_info (MonoClass
*klass
, MonoCachedClassInfo
*cached_info
)
3427 mono_loader_lock ();
3428 klass
->instance_size
= cached_info
->instance_size
;
3429 klass
->sizes
.class_size
= cached_info
->class_size
;
3430 klass
->packing_size
= cached_info
->packing_size
;
3431 klass
->min_align
= cached_info
->min_align
;
3432 klass
->blittable
= cached_info
->blittable
;
3433 klass
->has_references
= cached_info
->has_references
;
3434 klass
->has_static_refs
= cached_info
->has_static_refs
;
3435 klass
->no_special_static_fields
= cached_info
->no_special_static_fields
;
3436 klass
->has_weak_fields
= cached_info
->has_weak_fields
;
3437 mono_loader_unlock ();
3440 if (!klass
->size_inited
)
3441 mono_class_setup_fields (klass
);
3446 * mono_class_init_sizes:
3448 * Initializes the size related fields of @klass without loading all field data if possible.
3449 * Sets the following fields in @klass:
3451 * - sizes.class_size
3458 * Can fail the class.
3460 * LOCKING: Acquires the loader lock.
3463 mono_class_init_sizes (MonoClass
*klass
)
3465 MonoCachedClassInfo cached_info
;
3466 gboolean has_cached_info
;
3468 if (klass
->size_inited
)
3471 has_cached_info
= mono_class_get_cached_class_info (klass
, &cached_info
);
3473 init_sizes_with_info (klass
, has_cached_info
? &cached_info
: NULL
);
3478 class_has_references (MonoClass
*klass
)
3480 mono_class_init_sizes (klass
);
3483 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3484 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3487 return klass
->has_references
;
3491 type_has_references (MonoClass
*klass
, MonoType
*ftype
)
3493 if (MONO_TYPE_IS_REFERENCE (ftype
) || IS_GC_REFERENCE (klass
, ftype
) || ((MONO_TYPE_ISSTRUCT (ftype
) && class_has_references (mono_class_from_mono_type_internal (ftype
)))))
3495 if (!ftype
->byref
&& (ftype
->type
== MONO_TYPE_VAR
|| ftype
->type
== MONO_TYPE_MVAR
)) {
3496 MonoGenericParam
*gparam
= ftype
->data
.generic_param
;
3498 if (gparam
->gshared_constraint
)
3499 return class_has_references (mono_class_from_mono_type_internal (gparam
->gshared_constraint
));
3505 * mono_class_layout_fields:
3507 * @base_instance_size: base instance size
3510 * This contains the common code for computing the layout of classes and sizes.
3511 * This should only be called from mono_class_setup_fields () and
3512 * typebuilder_setup_fields ().
3514 * LOCKING: Acquires the loader lock
3517 mono_class_layout_fields (MonoClass
*klass
, int base_instance_size
, int packing_size
, int explicit_size
, gboolean sre
)
3520 const int top
= mono_class_get_field_count (klass
);
3521 guint32 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
3522 guint32 pass
, passes
, real_size
;
3523 gboolean gc_aware_layout
= FALSE
;
3524 gboolean has_static_fields
= FALSE
;
3525 gboolean has_references
= FALSE
;
3526 gboolean has_static_refs
= FALSE
;
3527 MonoClassField
*field
;
3529 int instance_size
= base_instance_size
;
3530 int element_size
= -1;
3531 int class_size
, min_align
;
3533 gboolean
*fields_has_references
;
3536 * We want to avoid doing complicated work inside locks, so we compute all the required
3537 * information and write it to @klass inside a lock.
3539 if (klass
->fields_inited
)
3542 if ((packing_size
& 0xffffff00) != 0) {
3543 mono_class_set_type_load_failure (klass
, "Could not load struct '%s' with packing size %d >= 256", klass
->name
, packing_size
);
3547 if (klass
->parent
) {
3548 min_align
= klass
->parent
->min_align
;
3549 /* we use | since it may have been set already */
3550 has_references
= klass
->has_references
| klass
->parent
->has_references
;
3554 /* We can't really enable 16 bytes alignment until the GC supports it.
3555 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3556 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3557 Bug #506144 is an example of this issue.
3559 if (klass->simd_type)
3564 * When we do generic sharing we need to have layout
3565 * information for open generic classes (either with a generic
3566 * context containing type variables or with a generic
3567 * container), so we don't return in that case anymore.
3570 if (klass
->enumtype
) {
3571 for (i
= 0; i
< top
; i
++) {
3572 field
= &klass
->fields
[i
];
3573 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
3574 klass
->cast_class
= klass
->element_class
= mono_class_from_mono_type_internal (field
->type
);
3579 if (!mono_class_enum_basetype_internal (klass
)) {
3580 mono_class_set_type_load_failure (klass
, "The enumeration's base type is invalid.");
3586 * Enable GC aware auto layout: in this mode, reference
3587 * fields are grouped together inside objects, increasing collector
3589 * Requires that all classes whose layout is known to native code be annotated
3590 * with [StructLayout (LayoutKind.Sequential)]
3591 * Value types have gc_aware_layout disabled by default, as per
3592 * what the default is for other runtimes.
3594 /* corlib is missing [StructLayout] directives in many places */
3595 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
3596 if (!klass
->valuetype
)
3597 gc_aware_layout
= TRUE
;
3600 /* Compute klass->blittable */
3603 blittable
= klass
->parent
->blittable
;
3604 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
&& !(mono_is_corlib_image (klass
->image
) && !strcmp (klass
->name_space
, "System") && !strcmp (klass
->name
, "ValueType")) && top
)
3606 for (i
= 0; i
< top
; i
++) {
3607 field
= &klass
->fields
[i
];
3609 if (mono_field_is_deleted (field
))
3611 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3614 if (field
->type
->byref
|| MONO_TYPE_IS_REFERENCE (field
->type
)) {
3617 MonoClass
*field_class
= mono_class_from_mono_type_internal (field
->type
);
3619 mono_class_setup_fields (field_class
);
3620 if (mono_class_has_failure (field_class
)) {
3621 ERROR_DECL (field_error
);
3622 mono_error_set_for_class_failure (field_error
, field_class
);
3623 mono_class_set_type_load_failure (klass
, "Could not set up field '%s' due to: %s", field
->name
, mono_error_get_message (field_error
));
3624 mono_error_cleanup (field_error
);
3628 if (!field_class
|| !field_class
->blittable
)
3632 if (klass
->enumtype
)
3633 blittable
= klass
->element_class
->blittable
;
3635 if (mono_class_has_failure (klass
))
3637 if (klass
== mono_defaults
.string_class
)
3640 /* Compute klass->has_references */
3642 * Process non-static fields first, since static fields might recursively
3643 * refer to the class itself.
3645 for (i
= 0; i
< top
; i
++) {
3648 field
= &klass
->fields
[i
];
3650 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
3651 ftype
= mono_type_get_underlying_type (field
->type
);
3652 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3653 if (type_has_references (klass
, ftype
))
3654 has_references
= TRUE
;
3659 * Compute field layout and total size (not considering static fields)
3661 field_offsets
= g_new0 (int, top
);
3662 fields_has_references
= g_new0 (gboolean
, top
);
3663 int first_field_idx
= mono_class_has_static_metadata (klass
) ? mono_class_get_first_field_idx (klass
) : 0;
3665 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
3666 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
3667 if (gc_aware_layout
)
3672 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
)
3675 if (klass
->parent
) {
3676 mono_class_setup_fields (klass
->parent
);
3677 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Cannot initialize parent class"))
3679 real_size
= klass
->parent
->instance_size
;
3681 real_size
= MONO_ABI_SIZEOF (MonoObject
);
3684 for (pass
= 0; pass
< passes
; ++pass
) {
3685 for (i
= 0; i
< top
; i
++){
3690 field
= &klass
->fields
[i
];
3692 if (mono_field_is_deleted (field
))
3694 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3697 ftype
= mono_type_get_underlying_type (field
->type
);
3698 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3699 if (gc_aware_layout
) {
3700 fields_has_references
[i
] = type_has_references (klass
, ftype
);
3701 if (fields_has_references
[i
]) {
3710 if ((top
== 1) && (instance_size
== MONO_ABI_SIZEOF (MonoObject
)) &&
3711 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
3712 /* This field is a hack inserted by MCS to empty structures */
3716 size
= mono_type_size (field
->type
, &align
);
3718 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3719 align
= packing_size
? MIN (packing_size
, align
): align
;
3720 /* if the field has managed references, we need to force-align it
3723 if (type_has_references (klass
, ftype
))
3724 align
= MAX (align
, TARGET_SIZEOF_VOID_P
);
3726 min_align
= MAX (align
, min_align
);
3727 field_offsets
[i
] = real_size
;
3729 field_offsets
[i
] += align
- 1;
3730 field_offsets
[i
] &= ~(align
- 1);
3732 /*TypeBuilders produce all sort of weird things*/
3733 g_assert (image_is_dynamic (klass
->image
) || field_offsets
[i
] > 0);
3734 real_size
= field_offsets
[i
] + size
;
3737 instance_size
= MAX (real_size
, instance_size
);
3739 if (instance_size
& (min_align
- 1)) {
3740 instance_size
+= min_align
- 1;
3741 instance_size
&= ~(min_align
- 1);
3745 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
: {
3749 for (i
= 0; i
< top
; i
++) {
3754 field
= &klass
->fields
[i
];
3757 * There must be info about all the fields in a type if it
3758 * uses explicit layout.
3760 if (mono_field_is_deleted (field
))
3762 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3765 size
= mono_type_size (field
->type
, &align
);
3766 align
= packing_size
? MIN (packing_size
, align
): align
;
3767 min_align
= MAX (align
, min_align
);
3770 /* Already set by typebuilder_setup_fields () */
3771 field_offsets
[i
] = field
->offset
+ MONO_ABI_SIZEOF (MonoObject
);
3773 int idx
= first_field_idx
+ i
;
3775 mono_metadata_field_info (klass
->image
, idx
, &offset
, NULL
, NULL
);
3776 field_offsets
[i
] = offset
+ MONO_ABI_SIZEOF (MonoObject
);
3778 ftype
= mono_type_get_underlying_type (field
->type
);
3779 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3780 if (type_has_references (klass
, ftype
)) {
3781 if (field_offsets
[i
] % TARGET_SIZEOF_VOID_P
) {
3782 mono_class_set_type_load_failure (klass
, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field
->name
);
3789 real_size
= MAX (real_size
, size
+ field_offsets
[i
]);
3792 if (klass
->has_references
) {
3793 ref_bitmap
= g_new0 (guint8
, real_size
/ TARGET_SIZEOF_VOID_P
);
3795 /* Check for overlapping reference and non-reference fields */
3796 for (i
= 0; i
< top
; i
++) {
3799 field
= &klass
->fields
[i
];
3801 if (mono_field_is_deleted (field
))
3803 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3805 ftype
= mono_type_get_underlying_type (field
->type
);
3806 if (MONO_TYPE_IS_REFERENCE (ftype
))
3807 ref_bitmap
[field_offsets
[i
] / TARGET_SIZEOF_VOID_P
] = 1;
3809 for (i
= 0; i
< top
; i
++) {
3810 field
= &klass
->fields
[i
];
3812 if (mono_field_is_deleted (field
))
3814 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3817 // FIXME: Too much code does this
3819 if (!MONO_TYPE_IS_REFERENCE (field
->type
) && ref_bitmap
[field_offsets
[i
] / TARGET_SIZEOF_VOID_P
]) {
3820 mono_class_set_type_load_failure (klass
, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass
->name
, field_offsets
[i
]);
3824 g_free (ref_bitmap
);
3827 instance_size
= MAX (real_size
, instance_size
);
3828 if (!((layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) && explicit_size
)) {
3829 if (instance_size
& (min_align
- 1)) {
3830 instance_size
+= min_align
- 1;
3831 instance_size
&= ~(min_align
- 1);
3838 if (layout
!= TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
3840 * This leads to all kinds of problems with nested structs, so only
3841 * enable it when a MONO_DEBUG property is set.
3843 * For small structs, set min_align to at least the struct size to improve
3844 * performance, and since the JIT memset/memcpy code assumes this and generates
3845 * unaligned accesses otherwise. See #78990 for a testcase.
3847 if (mono_align_small_structs
&& top
) {
3848 if (instance_size
<= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
))
3849 min_align
= MAX (min_align
, instance_size
- MONO_ABI_SIZEOF (MonoObject
));
3853 MonoType
*klass_byval_arg
= m_class_get_byval_arg (klass
);
3854 if (klass_byval_arg
->type
== MONO_TYPE_VAR
|| klass_byval_arg
->type
== MONO_TYPE_MVAR
)
3855 instance_size
= MONO_ABI_SIZEOF (MonoObject
) + mono_type_stack_size_internal (klass_byval_arg
, NULL
, TRUE
);
3856 else if (klass_byval_arg
->type
== MONO_TYPE_PTR
)
3857 instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
3859 if (klass_byval_arg
->type
== MONO_TYPE_SZARRAY
|| klass_byval_arg
->type
== MONO_TYPE_ARRAY
)
3860 element_size
= mono_class_array_element_size (klass
->element_class
);
3862 /* Publish the data */
3863 mono_loader_lock ();
3864 if (klass
->instance_size
&& !klass
->image
->dynamic
) {
3865 /* Might be already set using cached info */
3866 if (klass
->instance_size
!= instance_size
) {
3867 /* Emit info to help debugging */
3868 g_print ("%s\n", mono_class_full_name (klass
));
3869 g_print ("%d %d %d %d\n", klass
->instance_size
, instance_size
, klass
->blittable
, blittable
);
3870 g_print ("%d %d %d %d\n", klass
->has_references
, has_references
, klass
->packing_size
, packing_size
);
3871 g_print ("%d %d\n", klass
->min_align
, min_align
);
3872 for (i
= 0; i
< top
; ++i
) {
3873 field
= &klass
->fields
[i
];
3874 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3875 printf (" %s %d %d %d\n", klass
->fields
[i
].name
, klass
->fields
[i
].offset
, field_offsets
[i
], fields_has_references
[i
]);
3878 g_assert (klass
->instance_size
== instance_size
);
3880 klass
->instance_size
= instance_size
;
3882 klass
->blittable
= blittable
;
3883 klass
->has_references
= has_references
;
3884 klass
->packing_size
= packing_size
;
3885 klass
->min_align
= min_align
;
3886 for (i
= 0; i
< top
; ++i
) {
3887 field
= &klass
->fields
[i
];
3888 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3889 klass
->fields
[i
].offset
= field_offsets
[i
];
3892 if (klass_byval_arg
->type
== MONO_TYPE_SZARRAY
|| klass_byval_arg
->type
== MONO_TYPE_ARRAY
)
3893 klass
->sizes
.element_size
= element_size
;
3895 mono_memory_barrier ();
3896 klass
->size_inited
= 1;
3897 mono_loader_unlock ();
3900 * Compute static field layout and size
3901 * Static fields can reference the class itself, so this has to be
3902 * done after instance_size etc. are initialized.
3905 for (i
= 0; i
< top
; i
++) {
3909 field
= &klass
->fields
[i
];
3911 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) || field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
3913 if (mono_field_is_deleted (field
))
3916 if (mono_type_has_exceptions (field
->type
)) {
3917 mono_class_set_type_load_failure (klass
, "Field '%s' has an invalid type.", field
->name
);
3921 has_static_fields
= TRUE
;
3923 size
= mono_type_size (field
->type
, &align
);
3924 field_offsets
[i
] = class_size
;
3925 /*align is always non-zero here*/
3926 field_offsets
[i
] += align
- 1;
3927 field_offsets
[i
] &= ~(align
- 1);
3928 class_size
= field_offsets
[i
] + size
;
3931 if (has_static_fields
&& class_size
== 0)
3932 /* Simplify code which depends on class_size != 0 if the class has static fields */
3935 /* Compute klass->has_static_refs */
3936 has_static_refs
= FALSE
;
3937 for (i
= 0; i
< top
; i
++) {
3940 field
= &klass
->fields
[i
];
3942 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3943 ftype
= mono_type_get_underlying_type (field
->type
);
3944 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3945 if (type_has_references (klass
, ftype
))
3946 has_static_refs
= TRUE
;
3950 /*valuetypes can't be neither bigger than 1Mb or empty. */
3951 if (klass
->valuetype
&& (klass
->instance_size
<= 0 || klass
->instance_size
> (0x100000 + MONO_ABI_SIZEOF (MonoObject
)))) {
3952 /* Special case compiler generated types */
3953 /* Hard to check for [CompilerGenerated] here */
3954 if (!strstr (klass
->name
, "StaticArrayInitTypeSize") && !strstr (klass
->name
, "$ArrayType"))
3955 mono_class_set_type_load_failure (klass
, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass
->instance_size
);
3958 // Weak field support
3961 // - generic instances
3962 // - Disallow on structs/static fields/nonref fields
3963 gboolean has_weak_fields
= FALSE
;
3965 if (mono_class_has_static_metadata (klass
)) {
3966 for (MonoClass
*p
= klass
; p
!= NULL
; p
= p
->parent
) {
3967 gpointer iter
= NULL
;
3968 guint32 first_field_idx
= mono_class_get_first_field_idx (p
);
3970 while ((field
= mono_class_get_fields_internal (p
, &iter
))) {
3971 guint32 field_idx
= first_field_idx
+ (field
- p
->fields
);
3972 if (MONO_TYPE_IS_REFERENCE (field
->type
) && mono_assembly_is_weak_field (p
->image
, field_idx
+ 1)) {
3973 has_weak_fields
= TRUE
;
3974 mono_trace_message (MONO_TRACE_TYPE
, "Field %s:%s at offset %x is weak.", field
->parent
->name
, field
->name
, field
->offset
);
3981 * Check that any fields of IsByRefLike type are instance
3982 * fields and only inside other IsByRefLike structs.
3984 * (Has to be done late because we call
3985 * mono_class_from_mono_type_internal which may recursively
3986 * refer to the current class)
3988 gboolean allow_isbyreflike_fields
= m_class_is_byreflike (klass
);
3989 for (i
= 0; i
< top
; i
++) {
3990 field
= &klass
->fields
[i
];
3992 if (mono_field_is_deleted (field
))
3994 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
3996 MonoClass
*field_class
= NULL
;
3997 /* have to be careful not to recursively invoke mono_class_init on a static field.
3998 * for example - if the field is an array of a subclass of klass, we can loop.
4000 switch (field
->type
->type
) {
4001 case MONO_TYPE_TYPEDBYREF
:
4002 case MONO_TYPE_VALUETYPE
:
4003 case MONO_TYPE_GENERICINST
:
4004 field_class
= mono_class_from_mono_type_internal (field
->type
);
4009 if (!field_class
|| !m_class_is_byreflike (field_class
))
4011 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
4012 mono_class_set_type_load_failure (klass
, "Static ByRefLike field '%s' is not allowed", field
->name
);
4015 /* instance field */
4016 if (allow_isbyreflike_fields
)
4018 mono_class_set_type_load_failure (klass
, "Instance ByRefLike field '%s' not in a ref struct", field
->name
);
4023 /* Publish the data */
4024 mono_loader_lock ();
4026 klass
->sizes
.class_size
= class_size
;
4027 klass
->has_static_refs
= has_static_refs
;
4028 klass
->has_weak_fields
= has_weak_fields
;
4029 for (i
= 0; i
< top
; ++i
) {
4030 field
= &klass
->fields
[i
];
4032 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4033 field
->offset
= field_offsets
[i
];
4035 mono_memory_barrier ();
4036 klass
->fields_inited
= 1;
4037 mono_loader_unlock ();
4039 g_free (field_offsets
);
4040 g_free (fields_has_references
);
4043 static MonoMethod
*default_ghc
= NULL
;
4044 static MonoMethod
*default_finalize
= NULL
;
4045 static int finalize_slot
= -1;
4046 static int ghc_slot
= -1;
4049 initialize_object_slots (MonoClass
*klass
)
4054 if (klass
== mono_defaults
.object_class
) {
4055 mono_class_setup_vtable (klass
);
4056 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
4057 MonoMethod
*cm
= klass
->vtable
[i
];
4059 if (!strcmp (cm
->name
, "GetHashCode"))
4061 else if (!strcmp (cm
->name
, "Finalize"))
4065 g_assert (ghc_slot
>= 0);
4066 default_ghc
= klass
->vtable
[ghc_slot
];
4068 g_assert (finalize_slot
>= 0);
4069 default_finalize
= klass
->vtable
[finalize_slot
];
4074 mono_class_get_object_finalize_slot ()
4076 return finalize_slot
;
4080 mono_class_get_default_finalize_method ()
4082 return default_finalize
;
4086 MonoMethod
*array_method
;
4088 } GenericArrayMethodInfo
;
4090 static int generic_array_method_num
= 0;
4091 static GenericArrayMethodInfo
*generic_array_method_info
= NULL
;
4094 setup_generic_array_ifaces (MonoClass
*klass
, MonoClass
*iface
, MonoMethod
**methods
, int pos
, GHashTable
*cache
)
4096 MonoGenericContext tmp_context
;
4099 tmp_context
.class_inst
= NULL
;
4100 tmp_context
.method_inst
= mono_class_get_generic_class (iface
)->context
.class_inst
;
4101 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4103 for (i
= 0; i
< generic_array_method_num
; i
++) {
4105 MonoMethod
*m
= generic_array_method_info
[i
].array_method
;
4106 MonoMethod
*inflated
, *helper
;
4108 inflated
= mono_class_inflate_generic_method_checked (m
, &tmp_context
, error
);
4109 mono_error_assert_ok (error
);
4110 helper
= (MonoMethod
*)g_hash_table_lookup (cache
, inflated
);
4112 helper
= mono_marshal_get_generic_array_helper (klass
, generic_array_method_info
[i
].name
, inflated
);
4113 g_hash_table_insert (cache
, inflated
, helper
);
4115 methods
[pos
++] = helper
;
4120 generic_array_methods (MonoClass
*klass
)
4122 int i
, count_generic
= 0, mcount
;
4123 GList
*list
= NULL
, *tmp
;
4124 if (generic_array_method_num
)
4125 return generic_array_method_num
;
4126 mono_class_setup_methods (klass
->parent
); /*This is setting up System.Array*/
4127 g_assert (!mono_class_has_failure (klass
->parent
)); /*So hitting this assert is a huge problem*/
4128 mcount
= mono_class_get_method_count (klass
->parent
);
4129 for (i
= 0; i
< mcount
; i
++) {
4130 MonoMethod
*m
= klass
->parent
->methods
[i
];
4131 if (!strncmp (m
->name
, "InternalArray__", 15)) {
4133 list
= g_list_prepend (list
, m
);
4136 list
= g_list_reverse (list
);
4137 generic_array_method_info
= (GenericArrayMethodInfo
*)mono_image_alloc (mono_defaults
.corlib
, sizeof (GenericArrayMethodInfo
) * count_generic
);
4139 for (tmp
= list
; tmp
; tmp
= tmp
->next
) {
4140 const char *mname
, *iname
;
4142 MonoMethod
*m
= (MonoMethod
*)tmp
->data
;
4143 const char *ireadonlylist_prefix
= "InternalArray__IReadOnlyList_";
4144 const char *ireadonlycollection_prefix
= "InternalArray__IReadOnlyCollection_";
4146 generic_array_method_info
[i
].array_method
= m
;
4147 if (!strncmp (m
->name
, "InternalArray__ICollection_", 27)) {
4148 iname
= "System.Collections.Generic.ICollection`1.";
4149 mname
= m
->name
+ 27;
4150 } else if (!strncmp (m
->name
, "InternalArray__IEnumerable_", 27)) {
4151 iname
= "System.Collections.Generic.IEnumerable`1.";
4152 mname
= m
->name
+ 27;
4153 } else if (!strncmp (m
->name
, ireadonlylist_prefix
, strlen (ireadonlylist_prefix
))) {
4154 iname
= "System.Collections.Generic.IReadOnlyList`1.";
4155 mname
= m
->name
+ strlen (ireadonlylist_prefix
);
4156 } else if (!strncmp (m
->name
, ireadonlycollection_prefix
, strlen (ireadonlycollection_prefix
))) {
4157 iname
= "System.Collections.Generic.IReadOnlyCollection`1.";
4158 mname
= m
->name
+ strlen (ireadonlycollection_prefix
);
4159 } else if (!strncmp (m
->name
, "InternalArray__", 15)) {
4160 iname
= "System.Collections.Generic.IList`1.";
4161 mname
= m
->name
+ 15;
4163 g_assert_not_reached ();
4166 name
= (gchar
*)mono_image_alloc (mono_defaults
.corlib
, strlen (iname
) + strlen (mname
) + 1);
4167 strcpy (name
, iname
);
4168 strcpy (name
+ strlen (iname
), mname
);
4169 generic_array_method_info
[i
].name
= name
;
4172 /*g_print ("array generic methods: %d\n", count_generic);*/
4174 generic_array_method_num
= count_generic
;
4176 return generic_array_method_num
;
4180 * Global pool of interface IDs, represented as a bitset.
4181 * LOCKING: Protected by the classes lock.
4183 static MonoBitSet
*global_interface_bitset
= NULL
;
4186 * mono_unload_interface_ids:
4187 * @bitset: bit set of interface IDs
4189 * When an image is unloaded, the interface IDs associated with
4190 * the image are put back in the global pool of IDs so the numbers
4194 mono_unload_interface_ids (MonoBitSet
*bitset
)
4197 mono_bitset_sub (global_interface_bitset
, bitset
);
4202 mono_unload_interface_id (MonoClass
*klass
)
4204 if (global_interface_bitset
&& klass
->interface_id
) {
4206 mono_bitset_clear (global_interface_bitset
, klass
->interface_id
);
4212 * mono_get_unique_iid:
4213 * \param klass interface
4215 * Assign a unique integer ID to the interface represented by \p klass.
4216 * The ID will positive and as small as possible.
4217 * LOCKING: Acquires the classes lock.
4218 * \returns The new ID.
4221 mono_get_unique_iid (MonoClass
*klass
)
4225 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
));
4229 if (!global_interface_bitset
) {
4230 global_interface_bitset
= mono_bitset_new (128, 0);
4231 mono_bitset_set (global_interface_bitset
, 0); //don't let 0 be a valid iid
4234 iid
= mono_bitset_find_first_unset (global_interface_bitset
, -1);
4236 int old_size
= mono_bitset_size (global_interface_bitset
);
4237 MonoBitSet
*new_set
= mono_bitset_clone (global_interface_bitset
, old_size
* 2);
4238 mono_bitset_free (global_interface_bitset
);
4239 global_interface_bitset
= new_set
;
4242 mono_bitset_set (global_interface_bitset
, iid
);
4243 /* set the bit also in the per-image set */
4244 if (!mono_class_is_ginst (klass
)) {
4245 if (klass
->image
->interface_bitset
) {
4246 if (iid
>= mono_bitset_size (klass
->image
->interface_bitset
)) {
4247 MonoBitSet
*new_set
= mono_bitset_clone (klass
->image
->interface_bitset
, iid
+ 1);
4248 mono_bitset_free (klass
->image
->interface_bitset
);
4249 klass
->image
->interface_bitset
= new_set
;
4252 klass
->image
->interface_bitset
= mono_bitset_new (iid
+ 1, 0);
4254 mono_bitset_set (klass
->image
->interface_bitset
, iid
);
4259 #ifndef MONO_SMALL_CONFIG
4260 if (mono_print_vtable
) {
4262 char *type_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
4263 MonoGenericClass
*gklass
= mono_class_try_get_generic_class (klass
);
4264 if (gklass
&& !gklass
->context
.class_inst
->is_open
) {
4265 generic_id
= gklass
->context
.class_inst
->id
;
4266 g_assert (generic_id
!= 0);
4270 printf ("Interface: assigned id %d to %s|%s|%d\n", iid
, klass
->image
->assembly_name
, type_name
, generic_id
);
4275 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4276 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4277 g_assert (iid
< INT_MAX
);
4282 * mono_class_init_internal:
4283 * \param klass the class to initialize
4285 * Compute the \c instance_size, \c class_size and other infos that cannot be
4286 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4287 * Initializes the following fields in \p klass:
4288 * - all the fields initialized by \c mono_class_init_sizes
4293 * LOCKING: Acquires the loader lock.
4295 * \returns TRUE on success or FALSE if there was a problem in loading
4296 * the type (incorrect assemblies, missing assemblies, methods, etc).
4299 mono_class_init_internal (MonoClass
*klass
)
4301 int i
, vtable_size
= 0, array_method_count
= 0;
4302 MonoCachedClassInfo cached_info
;
4303 gboolean has_cached_info
;
4304 gboolean locked
= FALSE
;
4305 gboolean ghcimpl
= FALSE
;
4306 gboolean has_cctor
= FALSE
;
4307 int first_iface_slot
= 0;
4311 /* Double-checking locking pattern */
4312 if (klass
->inited
|| mono_class_has_failure (klass
))
4313 return !mono_class_has_failure (klass
);
4315 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4318 * This function can recursively call itself.
4320 GSList
*init_list
= (GSList
*)mono_native_tls_get_value (init_pending_tls_id
);
4321 if (g_slist_find (init_list
, klass
)) {
4322 mono_class_set_type_load_failure (klass
, "Recursive type definition detected %s.%s", klass
->name_space
, klass
->name
);
4323 goto leave_no_init_pending
;
4325 init_list
= g_slist_prepend (init_list
, klass
);
4326 mono_native_tls_set_value (init_pending_tls_id
, init_list
);
4329 * We want to avoid doing complicated work inside locks, so we compute all the required
4330 * information and write it to @klass inside a lock.
4333 if (mono_verifier_is_enabled_for_class (klass
) && !mono_verifier_verify_class (klass
)) {
4334 mono_class_set_type_load_failure (klass
, "%s", concat_two_strings_with_zero (klass
->image
, klass
->name
, klass
->image
->assembly_name
));
4338 MonoType
*klass_byval_arg
;
4339 klass_byval_arg
= m_class_get_byval_arg (klass
);
4340 if (klass_byval_arg
->type
== MONO_TYPE_ARRAY
|| klass_byval_arg
->type
== MONO_TYPE_SZARRAY
) {
4341 MonoClass
*element_class
= klass
->element_class
;
4342 MonoClass
*cast_class
= klass
->cast_class
;
4344 if (!element_class
->inited
)
4345 mono_class_init_internal (element_class
);
4346 if (mono_class_set_type_load_failure_causedby_class (klass
, element_class
, "Could not load array element class"))
4348 if (!cast_class
->inited
)
4349 mono_class_init_internal (cast_class
);
4350 if (mono_class_set_type_load_failure_causedby_class (klass
, cast_class
, "Could not load array cast class"))
4354 UnlockedIncrement (&mono_stats
.initialized_class_count
);
4356 if (mono_class_is_ginst (klass
) && !mono_class_get_generic_class (klass
)->is_dynamic
) {
4357 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4359 mono_class_init_internal (gklass
);
4360 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic Type Definition failed to init"))
4363 mono_loader_lock ();
4364 mono_class_setup_interface_id_internal (klass
);
4365 mono_loader_unlock ();
4368 if (klass
->parent
&& !klass
->parent
->inited
)
4369 mono_class_init_internal (klass
->parent
);
4371 has_cached_info
= mono_class_get_cached_class_info (klass
, &cached_info
);
4373 /* Compute instance size etc. */
4374 init_sizes_with_info (klass
, has_cached_info
? &cached_info
: NULL
);
4375 if (mono_class_has_failure (klass
))
4378 mono_class_setup_supertypes (klass
);
4381 initialize_object_slots (klass
);
4384 * Initialize the rest of the data without creating a generic vtable if possible.
4385 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4386 * also avoid computing a generic vtable.
4388 if (has_cached_info
) {
4390 vtable_size
= cached_info
.vtable_size
;
4391 ghcimpl
= cached_info
.ghcimpl
;
4392 has_cctor
= cached_info
.has_cctor
;
4393 } else if (klass
->rank
== 1 && klass_byval_arg
->type
== MONO_TYPE_SZARRAY
) {
4394 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4395 * The first slot if for array with.
4397 static int szarray_vtable_size
[3] = { 0 };
4401 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass
))))
4403 else if (klass
->element_class
->enumtype
)
4409 if (!szarray_vtable_size
[slot
]) {
4410 mono_class_setup_vtable (klass
);
4411 szarray_vtable_size
[slot
] = klass
->vtable_size
;
4412 vtable_size
= klass
->vtable_size
;
4414 vtable_size
= szarray_vtable_size
[slot
];
4416 } else if (mono_class_is_ginst (klass
) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
4417 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4419 /* Generic instance case */
4420 ghcimpl
= gklass
->ghcimpl
;
4421 has_cctor
= gklass
->has_cctor
;
4423 mono_class_setup_vtable (gklass
);
4424 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to init"))
4427 vtable_size
= gklass
->vtable_size
;
4431 /* ghcimpl is not currently used
4433 if (klass->parent) {
4434 MonoMethod *cmethod = klass->vtable [ghc_slot];
4435 if (cmethod->is_inflated)
4436 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
4437 if (cmethod == default_ghc) {
4443 /* C# doesn't allow interfaces to have cctors */
4444 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || klass
->image
!= mono_defaults
.corlib
) {
4445 MonoMethod
*cmethod
= NULL
;
4447 if (mono_class_is_ginst (klass
)) {
4448 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4450 /* Generic instance case */
4451 ghcimpl
= gklass
->ghcimpl
;
4452 has_cctor
= gklass
->has_cctor
;
4453 } else if (klass
->type_token
&& !image_is_dynamic(klass
->image
)) {
4454 cmethod
= mono_find_method_in_metadata (klass
, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME
);
4455 /* The find_method function ignores the 'flags' argument */
4456 if (cmethod
&& (cmethod
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
))
4459 mono_class_setup_methods (klass
);
4460 if (mono_class_has_failure (klass
))
4463 int mcount
= mono_class_get_method_count (klass
);
4464 for (i
= 0; i
< mcount
; ++i
) {
4465 MonoMethod
*method
= klass
->methods
[i
];
4466 if ((method
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) &&
4467 (strcmp (".cctor", method
->name
) == 0)) {
4477 array_method_count
= 3 + (klass
->rank
> 1? 2: 1);
4479 if (klass
->interface_count
) {
4480 int count_generic
= generic_array_methods (klass
);
4481 array_method_count
+= klass
->interface_count
* count_generic
;
4485 if (klass
->parent
) {
4486 if (!klass
->parent
->vtable_size
)
4487 mono_class_setup_vtable (klass
->parent
);
4488 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Parent class vtable failed to initialize"))
4490 g_assert (klass
->parent
->vtable_size
);
4491 first_iface_slot
= klass
->parent
->vtable_size
;
4492 if (mono_class_need_stelemref_method (klass
))
4497 * Do the actual changes to @klass inside the loader lock
4499 mono_loader_lock ();
4502 if (klass
->inited
|| mono_class_has_failure (klass
)) {
4503 mono_loader_unlock ();
4504 /* Somebody might have gotten in before us */
4505 return !mono_class_has_failure (klass
);
4508 UnlockedIncrement (&mono_stats
.initialized_class_count
);
4510 if (mono_class_is_ginst (klass
) && !mono_class_get_generic_class (klass
)->is_dynamic
)
4511 UnlockedIncrement (&mono_stats
.generic_class_count
);
4513 if (mono_class_is_ginst (klass
) || image_is_dynamic (klass
->image
) || !klass
->type_token
|| (has_cached_info
&& !cached_info
.has_nested_classes
))
4514 klass
->nested_classes_inited
= TRUE
;
4515 klass
->ghcimpl
= ghcimpl
;
4516 klass
->has_cctor
= has_cctor
;
4518 klass
->vtable_size
= vtable_size
;
4519 if (has_cached_info
) {
4520 klass
->has_finalize
= cached_info
.has_finalize
;
4521 klass
->has_finalize_inited
= TRUE
;
4524 mono_class_set_method_count (klass
, array_method_count
);
4526 mono_loader_unlock ();
4529 setup_interface_offsets (klass
, first_iface_slot
, TRUE
);
4531 if (mono_security_core_clr_enabled ())
4532 mono_security_core_clr_check_inheritance (klass
);
4534 if (mono_class_is_ginst (klass
) && !mono_verifier_class_is_valid_generic_instantiation (klass
))
4535 mono_class_set_type_load_failure (klass
, "Invalid generic instantiation");
4540 init_list
= (GSList
*)mono_native_tls_get_value (init_pending_tls_id
);
4541 init_list
= g_slist_remove (init_list
, klass
);
4542 mono_native_tls_set_value (init_pending_tls_id
, init_list
);
4544 leave_no_init_pending
:
4546 mono_loader_unlock ();
4548 /* Leave this for last */
4549 mono_loader_lock ();
4551 mono_loader_unlock ();
4553 return !mono_class_has_failure (klass
);
4557 mono_class_init_checked (MonoClass
*klass
, MonoError
*error
)
4560 gboolean
const success
= mono_class_init_internal (klass
);
4562 mono_error_set_for_class_failure (error
, klass
);
4568 * COM initialization is delayed until needed.
4569 * However when a [ComImport] attribute is present on a type it will trigger
4570 * the initialization. This is not a problem unless the BCL being executed
4571 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4574 init_com_from_comimport (MonoClass
*klass
)
4576 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4577 if (mono_security_core_clr_enabled ()) {
4578 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4579 if (!mono_security_core_clr_determine_platform_image (klass
->image
)) {
4580 /* but it can not be made available for application (i.e. user code) since all COM calls
4581 * are considered native calls. In this case we fail with a TypeLoadException (just like
4582 * Silverlight 2 does */
4583 mono_class_set_type_load_failure (klass
, "");
4588 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4590 #endif /*DISABLE_COM*/
4593 * LOCKING: this assumes the loader lock is held
4596 mono_class_setup_parent (MonoClass
*klass
, MonoClass
*parent
)
4598 gboolean system_namespace
;
4599 gboolean is_corlib
= mono_is_corlib_image (klass
->image
);
4601 system_namespace
= !strcmp (klass
->name_space
, "System") && is_corlib
;
4603 /* if root of the hierarchy */
4604 if (system_namespace
&& !strcmp (klass
->name
, "Object")) {
4605 klass
->parent
= NULL
;
4606 klass
->instance_size
= MONO_ABI_SIZEOF (MonoObject
);
4609 if (!strcmp (klass
->name
, "<Module>")) {
4610 klass
->parent
= NULL
;
4611 klass
->instance_size
= 0;
4615 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
4616 /* Imported COM Objects always derive from __ComObject. */
4618 if (MONO_CLASS_IS_IMPORT (klass
)) {
4619 init_com_from_comimport (klass
);
4620 if (parent
== mono_defaults
.object_class
)
4621 parent
= mono_class_get_com_object_class ();
4625 /* set the parent to something useful and safe, but mark the type as broken */
4626 parent
= mono_defaults
.object_class
;
4627 mono_class_set_type_load_failure (klass
, "");
4631 klass
->parent
= parent
;
4633 if (mono_class_is_ginst (parent
) && !parent
->name
) {
4635 * If the parent is a generic instance, we may get
4636 * called before it is fully initialized, especially
4637 * before it has its name.
4642 #ifndef DISABLE_REMOTING
4643 klass
->marshalbyref
= parent
->marshalbyref
;
4644 klass
->contextbound
= parent
->contextbound
;
4647 klass
->delegate
= parent
->delegate
;
4649 if (MONO_CLASS_IS_IMPORT (klass
) || mono_class_is_com_object (parent
))
4650 mono_class_set_is_com_object (klass
);
4652 if (system_namespace
) {
4653 #ifndef DISABLE_REMOTING
4654 if (klass
->name
[0] == 'M' && !strcmp (klass
->name
, "MarshalByRefObject"))
4655 klass
->marshalbyref
= 1;
4657 if (klass
->name
[0] == 'C' && !strcmp (klass
->name
, "ContextBoundObject"))
4658 klass
->contextbound
= 1;
4660 if (klass
->name
[0] == 'D' && !strcmp (klass
->name
, "Delegate"))
4661 klass
->delegate
= 1;
4664 if (klass
->parent
->enumtype
|| (mono_is_corlib_image (klass
->parent
->image
) && (strcmp (klass
->parent
->name
, "ValueType") == 0) &&
4665 (strcmp (klass
->parent
->name_space
, "System") == 0)))
4666 klass
->valuetype
= 1;
4667 if (mono_is_corlib_image (klass
->parent
->image
) && ((strcmp (klass
->parent
->name
, "Enum") == 0) && (strcmp (klass
->parent
->name_space
, "System") == 0))) {
4668 klass
->valuetype
= klass
->enumtype
= 1;
4670 /*klass->enumtype = klass->parent->enumtype; */
4672 /* initialize com types if COM interfaces are present */
4674 if (MONO_CLASS_IS_IMPORT (klass
))
4675 init_com_from_comimport (klass
);
4677 klass
->parent
= NULL
;
4682 /* Locking: must be called with the loader lock held. */
4684 mono_class_setup_interface_id_internal (MonoClass
*klass
)
4686 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || klass
->interface_id
)
4688 klass
->interface_id
= mono_get_unique_iid (klass
);
4690 if (mono_is_corlib_image (klass
->image
) && !strcmp (m_class_get_name_space (klass
), "System.Collections.Generic")) {
4691 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4692 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4693 * MS returns diferrent types based on which instance is called. For example:
4694 * object obj = new byte[10][];
4695 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4696 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4699 const char *name
= m_class_get_name (klass
);
4700 if (!strcmp (name
, "IList`1") || !strcmp (name
, "ICollection`1") || !strcmp (name
, "IEnumerable`1") || !strcmp (name
, "IEnumerator`1"))
4701 klass
->is_array_special_interface
= 1;
4707 * LOCKING: this assumes the loader lock is held
4710 mono_class_setup_mono_type (MonoClass
*klass
)
4712 const char *name
= klass
->name
;
4713 const char *nspace
= klass
->name_space
;
4714 gboolean is_corlib
= mono_is_corlib_image (klass
->image
);
4716 klass
->this_arg
.byref
= 1;
4717 klass
->this_arg
.data
.klass
= klass
;
4718 klass
->this_arg
.type
= MONO_TYPE_CLASS
;
4719 klass
->_byval_arg
.data
.klass
= klass
;
4720 klass
->_byval_arg
.type
= MONO_TYPE_CLASS
;
4722 if (is_corlib
&& !strcmp (nspace
, "System")) {
4723 if (!strcmp (name
, "ValueType")) {
4725 * do not set the valuetype bit for System.ValueType.
4726 * klass->valuetype = 1;
4728 klass
->blittable
= TRUE
;
4729 } else if (!strcmp (name
, "Enum")) {
4731 * do not set the valuetype bit for System.Enum.
4732 * klass->valuetype = 1;
4734 klass
->valuetype
= 0;
4735 klass
->enumtype
= 0;
4736 } else if (!strcmp (name
, "Object")) {
4737 klass
->_byval_arg
.type
= MONO_TYPE_OBJECT
;
4738 klass
->this_arg
.type
= MONO_TYPE_OBJECT
;
4739 } else if (!strcmp (name
, "String")) {
4740 klass
->_byval_arg
.type
= MONO_TYPE_STRING
;
4741 klass
->this_arg
.type
= MONO_TYPE_STRING
;
4742 } else if (!strcmp (name
, "TypedReference")) {
4743 klass
->_byval_arg
.type
= MONO_TYPE_TYPEDBYREF
;
4744 klass
->this_arg
.type
= MONO_TYPE_TYPEDBYREF
;
4748 if (klass
->valuetype
) {
4749 int t
= MONO_TYPE_VALUETYPE
;
4751 if (is_corlib
&& !strcmp (nspace
, "System")) {
4754 if (!strcmp (name
, "Boolean")) {
4755 t
= MONO_TYPE_BOOLEAN
;
4756 } else if (!strcmp(name
, "Byte")) {
4758 klass
->blittable
= TRUE
;
4762 if (!strcmp (name
, "Char")) {
4767 if (!strcmp (name
, "Double")) {
4769 klass
->blittable
= TRUE
;
4773 if (!strcmp (name
, "Int32")) {
4775 klass
->blittable
= TRUE
;
4776 } else if (!strcmp(name
, "Int16")) {
4778 klass
->blittable
= TRUE
;
4779 } else if (!strcmp(name
, "Int64")) {
4781 klass
->blittable
= TRUE
;
4782 } else if (!strcmp(name
, "IntPtr")) {
4784 klass
->blittable
= TRUE
;
4788 if (!strcmp (name
, "Single")) {
4790 klass
->blittable
= TRUE
;
4791 } else if (!strcmp(name
, "SByte")) {
4793 klass
->blittable
= TRUE
;
4797 if (!strcmp (name
, "UInt32")) {
4799 klass
->blittable
= TRUE
;
4800 } else if (!strcmp(name
, "UInt16")) {
4802 klass
->blittable
= TRUE
;
4803 } else if (!strcmp(name
, "UInt64")) {
4805 klass
->blittable
= TRUE
;
4806 } else if (!strcmp(name
, "UIntPtr")) {
4808 klass
->blittable
= TRUE
;
4812 if (!strcmp (name
, "TypedReference")) {
4813 t
= MONO_TYPE_TYPEDBYREF
;
4814 klass
->blittable
= TRUE
;
4818 if (!strcmp (name
, "Void")) {
4826 klass
->_byval_arg
.type
= (MonoTypeEnum
)t
;
4827 klass
->this_arg
.type
= (MonoTypeEnum
)t
;
4830 mono_class_setup_interface_id_internal (klass
);
4834 create_array_method (MonoClass
*klass
, const char *name
, MonoMethodSignature
*sig
)
4838 method
= (MonoMethod
*) mono_image_alloc0 (klass
->image
, sizeof (MonoMethodPInvoke
));
4839 method
->klass
= klass
;
4840 method
->flags
= METHOD_ATTRIBUTE_PUBLIC
;
4841 method
->iflags
= METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
;
4842 method
->signature
= sig
;
4843 method
->name
= name
;
4846 if (name
[0] == '.') {
4847 method
->flags
|= METHOD_ATTRIBUTE_RT_SPECIAL_NAME
| METHOD_ATTRIBUTE_SPECIAL_NAME
;
4849 method
->iflags
|= METHOD_IMPL_ATTRIBUTE_RUNTIME
;
4855 * mono_class_setup_methods:
4858 * Initializes the 'methods' array in CLASS.
4859 * Calling this method should be avoided if possible since it allocates a lot
4860 * of long-living MonoMethod structures.
4861 * Methods belonging to an interface are assigned a sequential slot starting
4864 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4867 mono_class_setup_methods (MonoClass
*klass
)
4870 MonoMethod
**methods
;
4875 if (mono_class_is_ginst (klass
)) {
4877 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4879 mono_class_init_internal (gklass
);
4880 if (!mono_class_has_failure (gklass
))
4881 mono_class_setup_methods (gklass
);
4882 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
4885 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4886 count
= mono_class_get_method_count (gklass
);
4887 methods
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (MonoMethod
*) * (count
+ 1));
4889 for (i
= 0; i
< count
; i
++) {
4890 methods
[i
] = mono_class_inflate_generic_method_full_checked (
4891 gklass
->methods
[i
], klass
, mono_class_get_context (klass
), error
);
4892 if (!mono_error_ok (error
)) {
4893 char *method
= mono_method_full_name (gklass
->methods
[i
], TRUE
);
4894 mono_class_set_type_load_failure (klass
, "Could not inflate method %s due to %s", method
, mono_error_get_message (error
));
4897 mono_error_cleanup (error
);
4901 } else if (klass
->rank
) {
4903 MonoMethod
*amethod
;
4904 MonoMethodSignature
*sig
;
4905 int count_generic
= 0, first_generic
= 0;
4907 gboolean jagged_ctor
= FALSE
;
4909 count
= 3 + (klass
->rank
> 1? 2: 1);
4911 mono_class_setup_interfaces (klass
, error
);
4912 g_assert (mono_error_ok (error
)); /*FIXME can this fail for array types?*/
4914 if (klass
->rank
== 1 && klass
->element_class
->rank
) {
4919 if (klass
->interface_count
) {
4920 count_generic
= generic_array_methods (klass
);
4921 first_generic
= count
;
4922 count
+= klass
->interface_count
* count_generic
;
4925 methods
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (MonoMethod
*) * count
);
4927 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
4928 sig
->ret
= mono_get_void_type ();
4929 sig
->pinvoke
= TRUE
;
4930 sig
->hasthis
= TRUE
;
4931 for (i
= 0; i
< klass
->rank
; ++i
)
4932 sig
->params
[i
] = mono_get_int32_type ();
4934 amethod
= create_array_method (klass
, ".ctor", sig
);
4935 methods
[method_num
++] = amethod
;
4936 if (klass
->rank
> 1) {
4937 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
* 2);
4938 sig
->ret
= mono_get_void_type ();
4939 sig
->pinvoke
= TRUE
;
4940 sig
->hasthis
= TRUE
;
4941 for (i
= 0; i
< klass
->rank
* 2; ++i
)
4942 sig
->params
[i
] = mono_get_int32_type ();
4944 amethod
= create_array_method (klass
, ".ctor", sig
);
4945 methods
[method_num
++] = amethod
;
4949 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4950 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
+ 1);
4951 sig
->ret
= mono_get_void_type ();
4952 sig
->pinvoke
= TRUE
;
4953 sig
->hasthis
= TRUE
;
4954 for (i
= 0; i
< klass
->rank
+ 1; ++i
)
4955 sig
->params
[i
] = mono_get_int32_type ();
4956 amethod
= create_array_method (klass
, ".ctor", sig
);
4957 methods
[method_num
++] = amethod
;
4960 /* element Get (idx11, [idx2, ...]) */
4961 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
4962 sig
->ret
= m_class_get_byval_arg (m_class_get_element_class (klass
));
4963 sig
->pinvoke
= TRUE
;
4964 sig
->hasthis
= TRUE
;
4965 for (i
= 0; i
< klass
->rank
; ++i
)
4966 sig
->params
[i
] = mono_get_int32_type ();
4967 amethod
= create_array_method (klass
, "Get", sig
);
4968 methods
[method_num
++] = amethod
;
4969 /* element& Address (idx11, [idx2, ...]) */
4970 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
4971 sig
->ret
= &klass
->element_class
->this_arg
;
4972 sig
->pinvoke
= TRUE
;
4973 sig
->hasthis
= TRUE
;
4974 for (i
= 0; i
< klass
->rank
; ++i
)
4975 sig
->params
[i
] = mono_get_int32_type ();
4976 amethod
= create_array_method (klass
, "Address", sig
);
4977 methods
[method_num
++] = amethod
;
4978 /* void Set (idx11, [idx2, ...], element) */
4979 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
+ 1);
4980 sig
->ret
= mono_get_void_type ();
4981 sig
->pinvoke
= TRUE
;
4982 sig
->hasthis
= TRUE
;
4983 for (i
= 0; i
< klass
->rank
; ++i
)
4984 sig
->params
[i
] = mono_get_int32_type ();
4985 sig
->params
[i
] = m_class_get_byval_arg (m_class_get_element_class (klass
));
4986 amethod
= create_array_method (klass
, "Set", sig
);
4987 methods
[method_num
++] = amethod
;
4989 GHashTable
*cache
= g_hash_table_new (NULL
, NULL
);
4990 for (i
= 0; i
< klass
->interface_count
; i
++)
4991 setup_generic_array_ifaces (klass
, klass
->interfaces
[i
], methods
, first_generic
+ i
* count_generic
, cache
);
4992 g_hash_table_destroy (cache
);
4993 } else if (mono_class_has_static_metadata (klass
)) {
4995 int first_idx
= mono_class_get_first_method_idx (klass
);
4997 count
= mono_class_get_method_count (klass
);
4998 methods
= (MonoMethod
**)mono_class_alloc (klass
, sizeof (MonoMethod
*) * count
);
4999 for (i
= 0; i
< count
; ++i
) {
5000 int idx
= mono_metadata_translate_token_index (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
+ 1);
5001 methods
[i
] = mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| idx
, klass
, NULL
, error
);
5003 mono_class_set_type_load_failure (klass
, "Could not load method %d due to %s", i
, mono_error_get_message (error
));
5004 mono_error_cleanup (error
);
5008 methods
= (MonoMethod
**)mono_class_alloc (klass
, sizeof (MonoMethod
*) * 1);
5012 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
5014 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
5015 for (i
= 0; i
< count
; ++i
) {
5016 if (methods
[i
]->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
5018 if (method_is_reabstracted (methods
[i
]->flags
)) {
5019 methods
[i
]->is_reabstracted
= 1;
5022 methods
[i
]->slot
= slot
++;
5027 mono_image_lock (klass
->image
);
5029 if (!klass
->methods
) {
5030 mono_class_set_method_count (klass
, count
);
5032 /* Needed because of the double-checking locking pattern */
5033 mono_memory_barrier ();
5035 klass
->methods
= methods
;
5038 mono_image_unlock (klass
->image
);
5042 * mono_class_setup_properties:
5044 * Initialize klass->ext.property and klass->ext.properties.
5046 * This method can fail the class.
5049 mono_class_setup_properties (MonoClass
*klass
)
5051 guint startm
, endm
, i
, j
;
5052 guint32 cols
[MONO_PROPERTY_SIZE
];
5053 MonoTableInfo
*msemt
= &klass
->image
->tables
[MONO_TABLE_METHODSEMANTICS
];
5054 MonoProperty
*properties
;
5057 MonoClassPropertyInfo
*info
;
5059 info
= mono_class_get_property_info (klass
);
5063 if (mono_class_is_ginst (klass
)) {
5064 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5066 mono_class_init_internal (gklass
);
5067 mono_class_setup_properties (gklass
);
5068 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
5071 MonoClassPropertyInfo
*ginfo
= mono_class_get_property_info (gklass
);
5072 properties
= mono_class_new0 (klass
, MonoProperty
, ginfo
->count
+ 1);
5074 for (i
= 0; i
< ginfo
->count
; i
++) {
5076 MonoProperty
*prop
= &properties
[i
];
5078 *prop
= ginfo
->properties
[i
];
5081 prop
->get
= mono_class_inflate_generic_method_full_checked (
5082 prop
->get
, klass
, mono_class_get_context (klass
), error
);
5084 prop
->set
= mono_class_inflate_generic_method_full_checked (
5085 prop
->set
, klass
, mono_class_get_context (klass
), error
);
5087 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5088 prop
->parent
= klass
;
5091 first
= ginfo
->first
;
5092 count
= ginfo
->count
;
5094 first
= mono_metadata_properties_from_typedef (klass
->image
, mono_metadata_token_index (klass
->type_token
) - 1, &last
);
5095 count
= last
- first
;
5098 mono_class_setup_methods (klass
);
5099 if (mono_class_has_failure (klass
))
5103 properties
= (MonoProperty
*)mono_class_alloc0 (klass
, sizeof (MonoProperty
) * count
);
5104 for (i
= first
; i
< last
; ++i
) {
5105 mono_metadata_decode_table_row (klass
->image
, MONO_TABLE_PROPERTY
, i
, cols
, MONO_PROPERTY_SIZE
);
5106 properties
[i
- first
].parent
= klass
;
5107 properties
[i
- first
].attrs
= cols
[MONO_PROPERTY_FLAGS
];
5108 properties
[i
- first
].name
= mono_metadata_string_heap (klass
->image
, cols
[MONO_PROPERTY_NAME
]);
5110 startm
= mono_metadata_methods_from_property (klass
->image
, i
, &endm
);
5111 int first_idx
= mono_class_get_first_method_idx (klass
);
5112 for (j
= startm
; j
< endm
; ++j
) {
5115 mono_metadata_decode_row (msemt
, j
, cols
, MONO_METHOD_SEMA_SIZE
);
5117 if (klass
->image
->uncompressed_metadata
) {
5119 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5120 method
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| cols
[MONO_METHOD_SEMA_METHOD
], klass
, NULL
, error
);
5121 mono_error_cleanup (error
); /* FIXME don't swallow this error */
5123 method
= klass
->methods
[cols
[MONO_METHOD_SEMA_METHOD
] - 1 - first_idx
];
5126 switch (cols
[MONO_METHOD_SEMA_SEMANTICS
]) {
5127 case METHOD_SEMANTIC_SETTER
:
5128 properties
[i
- first
].set
= method
;
5130 case METHOD_SEMANTIC_GETTER
:
5131 properties
[i
- first
].get
= method
;
5140 info
= (MonoClassPropertyInfo
*)mono_class_alloc0 (klass
, sizeof (MonoClassPropertyInfo
));
5141 info
->first
= first
;
5142 info
->count
= count
;
5143 info
->properties
= properties
;
5144 mono_memory_barrier ();
5146 /* This might leak 'info' which was allocated from the image mempool */
5147 mono_class_set_property_info (klass
, info
);
5151 inflate_method_listz (MonoMethod
**methods
, MonoClass
*klass
, MonoGenericContext
*context
)
5153 MonoMethod
**om
, **retval
;
5156 for (om
= methods
, count
= 0; *om
; ++om
, ++count
)
5159 retval
= g_new0 (MonoMethod
*, count
+ 1);
5161 for (om
= methods
, count
= 0; *om
; ++om
, ++count
) {
5163 retval
[count
] = mono_class_inflate_generic_method_full_checked (*om
, klass
, context
, error
);
5164 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5170 /*This method can fail the class.*/
5172 mono_class_setup_events (MonoClass
*klass
)
5175 guint startm
, endm
, i
, j
;
5176 guint32 cols
[MONO_EVENT_SIZE
];
5177 MonoTableInfo
*msemt
= &klass
->image
->tables
[MONO_TABLE_METHODSEMANTICS
];
5181 MonoClassEventInfo
*info
= mono_class_get_event_info (klass
);
5185 if (mono_class_is_ginst (klass
)) {
5186 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5187 MonoGenericContext
*context
= NULL
;
5189 mono_class_setup_events (gklass
);
5190 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
5193 MonoClassEventInfo
*ginfo
= mono_class_get_event_info (gklass
);
5194 first
= ginfo
->first
;
5195 count
= ginfo
->count
;
5197 events
= mono_class_new0 (klass
, MonoEvent
, count
);
5200 context
= mono_class_get_context (klass
);
5202 for (i
= 0; i
< count
; i
++) {
5204 MonoEvent
*event
= &events
[i
];
5205 MonoEvent
*gevent
= &ginfo
->events
[i
];
5207 error_init (error
); //since we do conditional calls, we must ensure the default value is ok
5209 event
->parent
= klass
;
5210 event
->name
= gevent
->name
;
5211 event
->add
= gevent
->add
? mono_class_inflate_generic_method_full_checked (gevent
->add
, klass
, context
, error
) : NULL
;
5212 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5213 event
->remove
= gevent
->remove
? mono_class_inflate_generic_method_full_checked (gevent
->remove
, klass
, context
, error
) : NULL
;
5214 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5215 event
->raise
= gevent
->raise
? mono_class_inflate_generic_method_full_checked (gevent
->raise
, klass
, context
, error
) : NULL
;
5216 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5218 #ifndef MONO_SMALL_CONFIG
5219 event
->other
= gevent
->other
? inflate_method_listz (gevent
->other
, klass
, context
) : NULL
;
5221 event
->attrs
= gevent
->attrs
;
5224 first
= mono_metadata_events_from_typedef (klass
->image
, mono_metadata_token_index (klass
->type_token
) - 1, &last
);
5225 count
= last
- first
;
5228 mono_class_setup_methods (klass
);
5229 if (mono_class_has_failure (klass
)) {
5234 events
= (MonoEvent
*)mono_class_alloc0 (klass
, sizeof (MonoEvent
) * count
);
5235 for (i
= first
; i
< last
; ++i
) {
5236 MonoEvent
*event
= &events
[i
- first
];
5238 mono_metadata_decode_table_row (klass
->image
, MONO_TABLE_EVENT
, i
, cols
, MONO_EVENT_SIZE
);
5239 event
->parent
= klass
;
5240 event
->attrs
= cols
[MONO_EVENT_FLAGS
];
5241 event
->name
= mono_metadata_string_heap (klass
->image
, cols
[MONO_EVENT_NAME
]);
5243 startm
= mono_metadata_methods_from_event (klass
->image
, i
, &endm
);
5244 int first_idx
= mono_class_get_first_method_idx (klass
);
5245 for (j
= startm
; j
< endm
; ++j
) {
5248 mono_metadata_decode_row (msemt
, j
, cols
, MONO_METHOD_SEMA_SIZE
);
5250 if (klass
->image
->uncompressed_metadata
) {
5252 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5253 method
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| cols
[MONO_METHOD_SEMA_METHOD
], klass
, NULL
, error
);
5254 mono_error_cleanup (error
); /* FIXME don't swallow this error */
5256 method
= klass
->methods
[cols
[MONO_METHOD_SEMA_METHOD
] - 1 - first_idx
];
5259 switch (cols
[MONO_METHOD_SEMA_SEMANTICS
]) {
5260 case METHOD_SEMANTIC_ADD_ON
:
5261 event
->add
= method
;
5263 case METHOD_SEMANTIC_REMOVE_ON
:
5264 event
->remove
= method
;
5266 case METHOD_SEMANTIC_FIRE
:
5267 event
->raise
= method
;
5269 case METHOD_SEMANTIC_OTHER
: {
5270 #ifndef MONO_SMALL_CONFIG
5273 if (event
->other
== NULL
) {
5274 event
->other
= g_new0 (MonoMethod
*, 2);
5276 while (event
->other
[n
])
5278 event
->other
= (MonoMethod
**)g_realloc (event
->other
, (n
+ 2) * sizeof (MonoMethod
*));
5280 event
->other
[n
] = method
;
5281 /* NULL terminated */
5282 event
->other
[n
+ 1] = NULL
;
5293 info
= (MonoClassEventInfo
*)mono_class_alloc0 (klass
, sizeof (MonoClassEventInfo
));
5294 info
->events
= events
;
5295 info
->first
= first
;
5296 info
->count
= count
;
5298 mono_memory_barrier ();
5300 mono_class_set_event_info (klass
, info
);
5305 * mono_class_setup_interface_id:
5307 * Initializes MonoClass::interface_id if required.
5309 * LOCKING: Acquires the loader lock.
5312 mono_class_setup_interface_id (MonoClass
*klass
)
5314 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
));
5315 mono_loader_lock ();
5316 mono_class_setup_interface_id_internal (klass
);
5317 mono_loader_unlock ();
5321 * mono_class_setup_interfaces:
5323 * Initialize klass->interfaces/interfaces_count.
5324 * LOCKING: Acquires the loader lock.
5325 * This function can fail the type.
5328 mono_class_setup_interfaces (MonoClass
*klass
, MonoError
*error
)
5330 int i
, interface_count
;
5331 MonoClass
**interfaces
;
5335 if (klass
->interfaces_inited
)
5338 if (klass
->rank
== 1 && m_class_get_byval_arg (klass
)->type
!= MONO_TYPE_ARRAY
) {
5341 /* IList and IReadOnlyList -> 2x if enum*/
5342 interface_count
= klass
->element_class
->enumtype
? 4 : 2;
5343 interfaces
= (MonoClass
**)mono_image_alloc0 (klass
->image
, sizeof (MonoClass
*) * interface_count
);
5345 args
[0] = m_class_get_byval_arg (m_class_get_element_class (klass
));
5346 interfaces
[0] = mono_class_bind_generic_parameters (
5347 mono_defaults
.generic_ilist_class
, 1, args
, FALSE
);
5348 interfaces
[1] = mono_class_bind_generic_parameters (
5349 mono_defaults
.generic_ireadonlylist_class
, 1, args
, FALSE
);
5350 if (klass
->element_class
->enumtype
) {
5351 args
[0] = mono_class_enum_basetype_internal (klass
->element_class
);
5352 interfaces
[2] = mono_class_bind_generic_parameters (
5353 mono_defaults
.generic_ilist_class
, 1, args
, FALSE
);
5354 interfaces
[3] = mono_class_bind_generic_parameters (
5355 mono_defaults
.generic_ireadonlylist_class
, 1, args
, FALSE
);
5357 } else if (mono_class_is_ginst (klass
)) {
5358 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5360 mono_class_setup_interfaces (gklass
, error
);
5361 if (!mono_error_ok (error
)) {
5362 mono_class_set_type_load_failure (klass
, "Could not setup the interfaces");
5366 interface_count
= gklass
->interface_count
;
5367 interfaces
= mono_class_new0 (klass
, MonoClass
*, interface_count
);
5368 for (i
= 0; i
< interface_count
; i
++) {
5369 interfaces
[i
] = mono_class_inflate_generic_class_checked (gklass
->interfaces
[i
], mono_generic_class_get_context (mono_class_get_generic_class (klass
)), error
);
5370 if (!mono_error_ok (error
)) {
5371 mono_class_set_type_load_failure (klass
, "Could not setup the interfaces");
5376 interface_count
= 0;
5380 mono_loader_lock ();
5381 if (!klass
->interfaces_inited
) {
5382 klass
->interface_count
= interface_count
;
5383 klass
->interfaces
= interfaces
;
5385 mono_memory_barrier ();
5387 klass
->interfaces_inited
= TRUE
;
5389 mono_loader_unlock ();
5394 * mono_class_setup_has_finalizer:
5396 * Initialize klass->has_finalizer if it isn't already initialized.
5398 * LOCKING: Acquires the loader lock.
5401 mono_class_setup_has_finalizer (MonoClass
*klass
)
5403 gboolean has_finalize
= FALSE
;
5405 if (m_class_is_has_finalize_inited (klass
))
5408 /* Interfaces and valuetypes are not supposed to have finalizers */
5409 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || m_class_is_valuetype (klass
))) {
5410 MonoMethod
*cmethod
= NULL
;
5412 if (m_class_get_rank (klass
) == 1 && m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
) {
5413 } else if (mono_class_is_ginst (klass
)) {
5414 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5416 has_finalize
= mono_class_has_finalizer (gklass
);
5417 } else if (m_class_get_parent (klass
) && m_class_has_finalize (m_class_get_parent (klass
))) {
5418 has_finalize
= TRUE
;
5420 if (m_class_get_parent (klass
)) {
5422 * Can't search in metadata for a method named Finalize, because that
5423 * ignores overrides.
5425 mono_class_setup_vtable (klass
);
5426 if (mono_class_has_failure (klass
))
5429 cmethod
= m_class_get_vtable (klass
) [mono_class_get_object_finalize_slot ()];
5433 g_assert (m_class_get_vtable_size (klass
) > mono_class_get_object_finalize_slot ());
5435 if (m_class_get_parent (klass
)) {
5436 if (cmethod
->is_inflated
)
5437 cmethod
= ((MonoMethodInflated
*)cmethod
)->declaring
;
5438 if (cmethod
!= mono_class_get_default_finalize_method ())
5439 has_finalize
= TRUE
;
5445 mono_loader_lock ();
5446 if (!m_class_is_has_finalize_inited (klass
)) {
5447 klass
->has_finalize
= has_finalize
? 1 : 0;
5449 mono_memory_barrier ();
5450 klass
->has_finalize_inited
= TRUE
;
5452 mono_loader_unlock ();
5456 * mono_class_setup_supertypes:
5459 * Build the data structure needed to make fast type checks work.
5460 * This currently sets two fields in @class:
5461 * - idepth: distance between @class and System.Object in the type
5463 * - supertypes: array of classes: each element has a class in the hierarchy
5464 * starting from @class up to System.Object
5466 * LOCKING: Acquires the loader lock.
5469 mono_class_setup_supertypes (MonoClass
*klass
)
5472 MonoClass
**supertypes
;
5474 mono_atomic_load_acquire (supertypes
, MonoClass
**, &klass
->supertypes
);
5478 if (klass
->parent
&& !klass
->parent
->supertypes
)
5479 mono_class_setup_supertypes (klass
->parent
);
5481 idepth
= klass
->parent
->idepth
+ 1;
5485 ms
= MAX (MONO_DEFAULT_SUPERTABLE_SIZE
, idepth
);
5486 supertypes
= (MonoClass
**)mono_class_alloc0 (klass
, sizeof (MonoClass
*) * ms
);
5488 if (klass
->parent
) {
5489 CHECKED_METADATA_WRITE_PTR ( supertypes
[idepth
- 1] , klass
);
5492 for (supertype_idx
= 0; supertype_idx
< klass
->parent
->idepth
; supertype_idx
++)
5493 CHECKED_METADATA_WRITE_PTR ( supertypes
[supertype_idx
] , klass
->parent
->supertypes
[supertype_idx
] );
5495 CHECKED_METADATA_WRITE_PTR ( supertypes
[0] , klass
);
5498 mono_memory_barrier ();
5500 mono_loader_lock ();
5501 klass
->idepth
= idepth
;
5502 /* Needed so idepth is visible before supertypes is set */
5503 mono_memory_barrier ();
5504 klass
->supertypes
= supertypes
;
5505 mono_loader_unlock ();
5508 /* mono_class_setup_nested_types:
5510 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5512 * LOCKING: Acquires the loader lock.
5515 mono_class_setup_nested_types (MonoClass
*klass
)
5518 GList
*classes
, *nested_classes
, *l
;
5521 if (klass
->nested_classes_inited
)
5524 if (!klass
->type_token
) {
5525 mono_loader_lock ();
5526 klass
->nested_classes_inited
= TRUE
;
5527 mono_loader_unlock ();
5531 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, 1);
5535 guint32 cols
[MONO_NESTED_CLASS_SIZE
];
5536 mono_metadata_decode_row (&klass
->image
->tables
[MONO_TABLE_NESTEDCLASS
], i
- 1, cols
, MONO_NESTED_CLASS_SIZE
);
5537 nclass
= mono_class_create_from_typedef (klass
->image
, MONO_TOKEN_TYPE_DEF
| cols
[MONO_NESTED_CLASS_NESTED
], error
);
5538 if (!mono_error_ok (error
)) {
5539 /*FIXME don't swallow the error message*/
5540 mono_error_cleanup (error
);
5542 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, i
+ 1);
5546 classes
= g_list_prepend (classes
, nclass
);
5548 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, i
+ 1);
5551 nested_classes
= NULL
;
5552 for (l
= classes
; l
; l
= l
->next
)
5553 nested_classes
= mono_g_list_prepend_image (klass
->image
, nested_classes
, l
->data
);
5554 g_list_free (classes
);
5556 mono_loader_lock ();
5557 if (!klass
->nested_classes_inited
) {
5558 mono_class_set_nested_classes_property (klass
, nested_classes
);
5559 mono_memory_barrier ();
5560 klass
->nested_classes_inited
= TRUE
;
5562 mono_loader_unlock ();
5566 * mono_class_setup_runtime_info:
5567 * \param klass the class to setup
5568 * \param domain the domain of the \p vtable
5571 * Store \p vtable in \c klass->runtime_info.
5573 * Sets the following field in MonoClass:
5576 * LOCKING: domain lock and loaderlock must be held.
5579 mono_class_setup_runtime_info (MonoClass
*klass
, MonoDomain
*domain
, MonoVTable
*vtable
)
5581 MonoClassRuntimeInfo
*old_info
= m_class_get_runtime_info (klass
);
5582 if (old_info
&& old_info
->max_domain
>= domain
->domain_id
) {
5583 /* someone already created a large enough runtime info */
5584 old_info
->domain_vtables
[domain
->domain_id
] = vtable
;
5586 int new_size
= domain
->domain_id
;
5588 new_size
= MAX (new_size
, old_info
->max_domain
);
5590 /* make the new size a power of two */
5592 while (new_size
> i
)
5595 /* this is a bounded memory retention issue: may want to
5596 * handle it differently when we'll have a rcu-like system.
5598 MonoClassRuntimeInfo
*runtime_info
= (MonoClassRuntimeInfo
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_CLASS_RUNTIME_INFO
+ new_size
* sizeof (gpointer
));
5599 runtime_info
->max_domain
= new_size
- 1;
5600 /* copy the stuff from the older info */
5602 memcpy (runtime_info
->domain_vtables
, old_info
->domain_vtables
, (old_info
->max_domain
+ 1) * sizeof (gpointer
));
5604 runtime_info
->domain_vtables
[domain
->domain_id
] = vtable
;
5606 mono_memory_barrier ();
5607 klass
->runtime_info
= runtime_info
;
5612 * mono_class_create_array_fill_type:
5614 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5617 mono_class_create_array_fill_type (void)
5619 static MonoClass klass
;
5621 klass
.element_class
= mono_defaults
.int64_class
;
5623 klass
.instance_size
= MONO_SIZEOF_MONO_ARRAY
;
5624 klass
.sizes
.element_size
= 8;
5625 klass
.size_inited
= 1;
5626 klass
.name
= "array_filler_type";
5632 * mono_classes_init:
5634 * Initialize the resources used by this module.
5635 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5637 MONO_NO_SANITIZE_THREAD
5639 mono_classes_init (void)
5641 mono_os_mutex_init (&classes_mutex
);
5643 mono_native_tls_alloc (&setup_fields_tls_id
, NULL
);
5644 mono_native_tls_alloc (&init_pending_tls_id
, NULL
);
5646 mono_counters_register ("MonoClassDef count",
5647 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_def_count
);
5648 mono_counters_register ("MonoClassGtd count",
5649 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_gtd_count
);
5650 mono_counters_register ("MonoClassGenericInst count",
5651 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_ginst_count
);
5652 mono_counters_register ("MonoClassGenericParam count",
5653 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_gparam_count
);
5654 mono_counters_register ("MonoClassArray count",
5655 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_array_count
);
5656 mono_counters_register ("MonoClassPointer count",
5657 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_pointer_count
);
5658 mono_counters_register ("Inflated methods size",
5659 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mono_inflated_methods_size
);
5660 mono_counters_register ("Inflated classes size",
5661 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &inflated_classes_size
);
5662 mono_counters_register ("MonoClass size",
5663 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &classes_size
);
5667 * mono_classes_cleanup:
5669 * Free the resources used by this module.
5672 mono_classes_cleanup (void)
5674 mono_native_tls_free (setup_fields_tls_id
);
5675 mono_native_tls_free (init_pending_tls_id
);
5677 if (global_interface_bitset
)
5678 mono_bitset_free (global_interface_bitset
);
5679 global_interface_bitset
= NULL
;
5680 mono_os_mutex_destroy (&classes_mutex
);