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 g_assert (mono_class_get_field_count (klass
) == 0);
628 if (klass
->enumtype
) {
629 MonoType
*enum_basetype
= mono_class_find_enum_basetype (klass
, error
);
630 if (!enum_basetype
) {
631 /*set it to a default value as the whole runtime can't handle this to be null*/
632 klass
->cast_class
= klass
->element_class
= mono_defaults
.int32_class
;
633 mono_class_set_type_load_failure (klass
, "%s", mono_error_get_message (error
));
634 mono_loader_unlock ();
635 MONO_PROFILER_RAISE (class_failed
, (klass
));
638 klass
->cast_class
= klass
->element_class
= mono_class_from_mono_type_internal (enum_basetype
);
642 * If we're a generic type definition, load the constraints.
643 * We must do this after the class has been constructed to make certain recursive scenarios
646 if (mono_class_is_gtd (klass
) && !mono_metadata_load_generic_param_constraints_checked (image
, type_token
, mono_class_get_generic_container (klass
), error
)) {
647 mono_class_set_type_load_failure (klass
, "Could not load generic parameter constrains due to %s", mono_error_get_message (error
));
648 mono_loader_unlock ();
649 MONO_PROFILER_RAISE (class_failed
, (klass
));
653 if (klass
->image
->assembly_name
&& !strcmp (klass
->image
->assembly_name
, "Mono.Simd") && !strcmp (nspace
, "Mono.Simd")) {
654 if (!strncmp (name
, "Vector", 6))
655 klass
->simd_type
= !strcmp (name
+ 6, "2d") || !strcmp (name
+ 6, "2ul") || !strcmp (name
+ 6, "2l") || !strcmp (name
+ 6, "4f") || !strcmp (name
+ 6, "4ui") || !strcmp (name
+ 6, "4i") || !strcmp (name
+ 6, "8s") || !strcmp (name
+ 6, "8us") || !strcmp (name
+ 6, "16b") || !strcmp (name
+ 6, "16sb");
656 } else if (klass
->image
->assembly_name
&& !strcmp (klass
->image
->assembly_name
, "System.Numerics") && !strcmp (nspace
, "System.Numerics")) {
657 /* The JIT can't handle SIMD types with != 16 size yet */
658 //if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
659 if (!strcmp (name
, "Vector4"))
660 klass
->simd_type
= 1;
663 // compute is_byreflike
664 if (m_class_is_valuetype (klass
)) {
665 /* TypedReference and RuntimeArgumentHandle are byreflike by
666 * definition. Otherwise, look for IsByRefLikeAttribute.
668 if (mono_is_corlib_image (image
) &&
669 ((m_class_get_byval_arg (klass
)->type
== MONO_TYPE_TYPEDBYREF
) ||
670 (!strcmp (m_class_get_name_space (klass
), "System") &&
671 !strcmp (m_class_get_name (klass
), "RuntimeArgumentHandle"))))
672 klass
->is_byreflike
= 1;
673 else if (class_has_isbyreflike_attribute (klass
))
674 klass
->is_byreflike
= 1;
677 mono_loader_unlock ();
679 MONO_PROFILER_RAISE (class_loaded
, (klass
));
684 if (mono_class_is_gtd (klass
))
685 disable_gclass_recording (discard_gclass_due_to_failure
, klass
);
687 mono_class_setup_mono_type (klass
);
688 mono_loader_unlock ();
689 MONO_PROFILER_RAISE (class_failed
, (klass
));
695 mono_generic_class_setup_parent (MonoClass
*klass
, MonoClass
*gtd
)
699 MonoGenericClass
*gclass
= mono_class_get_generic_class (klass
);
701 klass
->parent
= mono_class_inflate_generic_class_checked (gtd
->parent
, mono_generic_class_get_context (gclass
), error
);
702 if (!mono_error_ok (error
)) {
703 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
704 klass
->parent
= mono_defaults
.object_class
;
705 mono_class_set_type_load_failure (klass
, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (error
));
706 mono_error_cleanup (error
);
711 mono_class_setup_parent (klass
, klass
->parent
);
713 if (klass
->enumtype
) {
714 klass
->cast_class
= gtd
->cast_class
;
715 klass
->element_class
= gtd
->element_class
;
717 mono_loader_unlock ();
720 struct HasIsByrefLikeUD
{
721 gboolean has_isbyreflike
;
725 has_isbyreflike_attribute_func (MonoImage
*image
, guint32 typeref_scope_token
, const char *nspace
, const char *name
, guint32 method_token
, gpointer user_data
)
727 struct HasIsByrefLikeUD
*has_isbyreflike
= (struct HasIsByrefLikeUD
*)user_data
;
728 if (!strcmp (name
, "IsByRefLikeAttribute") && !strcmp (nspace
, "System.Runtime.CompilerServices")) {
729 has_isbyreflike
->has_isbyreflike
= TRUE
;
736 class_has_isbyreflike_attribute (MonoClass
*klass
)
738 struct HasIsByrefLikeUD has_isbyreflike
;
739 has_isbyreflike
.has_isbyreflike
= FALSE
;
740 mono_class_metadata_foreach_custom_attr (klass
, has_isbyreflike_attribute_func
, &has_isbyreflike
);
741 return has_isbyreflike
.has_isbyreflike
;
746 check_valid_generic_inst_arguments (MonoGenericInst
*inst
, MonoError
*error
)
748 for (int i
= 0; i
< inst
->type_argc
; i
++) {
749 if (!mono_type_is_valid_generic_argument (inst
->type_argv
[i
])) {
750 char *type_name
= mono_type_full_name (inst
->type_argv
[i
]);
751 mono_error_set_invalid_program (error
, "generic type cannot be instantiated with type '%s'", type_name
);
760 * Create the `MonoClass' for an instantiation of a generic type.
761 * We only do this if we actually need it.
764 mono_class_create_generic_inst (MonoGenericClass
*gclass
)
766 MonoClass
*klass
, *gklass
;
768 if (gclass
->cached_class
)
769 return gclass
->cached_class
;
771 klass
= (MonoClass
*)mono_image_set_alloc0 (gclass
->owner
, sizeof (MonoClassGenericInst
));
773 gklass
= gclass
->container_class
;
775 if (gklass
->nested_in
) {
776 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
777 klass
->nested_in
= gklass
->nested_in
;
780 klass
->name
= gklass
->name
;
781 klass
->name_space
= gklass
->name_space
;
783 klass
->image
= gklass
->image
;
784 klass
->type_token
= gklass
->type_token
;
786 klass
->class_kind
= MONO_CLASS_GINST
;
788 ((MonoClassGenericInst
*)klass
)->generic_class
= gclass
;
790 klass
->_byval_arg
.type
= MONO_TYPE_GENERICINST
;
791 klass
->this_arg
.type
= m_class_get_byval_arg (klass
)->type
;
792 klass
->this_arg
.data
.generic_class
= klass
->_byval_arg
.data
.generic_class
= gclass
;
793 klass
->this_arg
.byref
= TRUE
;
794 klass
->enumtype
= gklass
->enumtype
;
795 klass
->valuetype
= gklass
->valuetype
;
798 if (gklass
->image
->assembly_name
&& !strcmp (gklass
->image
->assembly_name
, "System.Numerics.Vectors") && !strcmp (gklass
->name_space
, "System.Numerics") && !strcmp (gklass
->name
, "Vector`1")) {
799 g_assert (gclass
->context
.class_inst
);
800 g_assert (gclass
->context
.class_inst
->type_argc
> 0);
801 if (mono_type_is_primitive (gclass
->context
.class_inst
->type_argv
[0]))
802 klass
->simd_type
= 1;
804 klass
->is_array_special_interface
= gklass
->is_array_special_interface
;
806 klass
->cast_class
= klass
->element_class
= klass
;
808 if (m_class_is_valuetype (klass
)) {
809 klass
->is_byreflike
= gklass
->is_byreflike
;
812 if (gclass
->is_dynamic
) {
814 * We don't need to do any init workf with unbaked typebuilders. Generic instances created at this point will be later unregistered and/or fixed.
815 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
816 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
818 if (!gklass
->wastypebuilder
)
821 if (klass
->enumtype
) {
823 * For enums, gklass->fields might not been set, but instance_size etc. is
824 * already set in mono_reflection_create_internal_class (). For non-enums,
825 * these will be computed normally in mono_class_layout_fields ().
827 klass
->instance_size
= gklass
->instance_size
;
828 klass
->sizes
.class_size
= gklass
->sizes
.class_size
;
829 klass
->size_inited
= 1;
834 ERROR_DECL (error_inst
);
835 if (!check_valid_generic_inst_arguments (gclass
->context
.class_inst
, error_inst
)) {
836 char *gklass_name
= mono_type_get_full_name (gklass
);
837 mono_class_set_type_load_failure (klass
, "Could not instantiate %s due to %s", gklass_name
, mono_error_get_message (error_inst
));
838 g_free (gklass_name
);
839 mono_error_cleanup (error_inst
);
845 if (gclass
->cached_class
) {
846 mono_loader_unlock ();
847 return gclass
->cached_class
;
850 if (record_gclass_instantiation
> 0)
851 gclass_recorded_list
= g_slist_append (gclass_recorded_list
, klass
);
853 if (mono_class_is_nullable (klass
))
854 klass
->cast_class
= klass
->element_class
= mono_class_get_nullable_param (klass
);
856 MONO_PROFILER_RAISE (class_loading
, (klass
));
858 mono_generic_class_setup_parent (klass
, gklass
);
860 if (gclass
->is_dynamic
)
861 mono_class_setup_supertypes (klass
);
863 mono_memory_barrier ();
864 gclass
->cached_class
= klass
;
866 MONO_PROFILER_RAISE (class_loaded
, (klass
));
869 inflated_classes_size
+= sizeof (MonoClassGenericInst
);
871 mono_loader_unlock ();
877 class_kind_may_contain_generic_instances (MonoTypeKind kind
)
879 /* classes of type generic inst may contain generic arguments from other images,
880 * as well as arrays and pointers whose element types (recursively) may be a generic inst */
881 return (kind
== MONO_CLASS_GINST
|| kind
== MONO_CLASS_ARRAY
|| kind
== MONO_CLASS_POINTER
);
885 * mono_class_create_bounded_array:
886 * \param element_class element class
887 * \param rank the dimension of the array class
888 * \param bounded whenever the array has non-zero bounds
889 * \returns A class object describing the array with element type \p element_type and
893 mono_class_create_bounded_array (MonoClass
*eclass
, guint32 rank
, gboolean bounded
)
896 MonoClass
*klass
, *cached
, *k
;
897 MonoClass
*parent
= NULL
;
898 GSList
*list
, *rootlist
= NULL
;
901 MonoImageSet
* image_set
;
903 g_assert (rank
<= 255);
906 /* bounded only matters for one-dimensional arrays */
909 image
= eclass
->image
;
910 image_set
= class_kind_may_contain_generic_instances ((MonoTypeKind
)eclass
->class_kind
) ? mono_metadata_get_image_set_for_class (eclass
) : NULL
;
914 if (rank
== 1 && !bounded
) {
916 mono_image_set_lock (image_set
);
917 cached
= (MonoClass
*)g_hash_table_lookup (image_set
->szarray_cache
, eclass
);
918 mono_image_set_unlock (image_set
);
921 * This case is very frequent not just during compilation because of calls
922 * from mono_class_from_mono_type_internal (), mono_array_new (),
923 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
925 mono_os_mutex_lock (&image
->szarray_cache_lock
);
926 if (!image
->szarray_cache
)
927 image
->szarray_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
928 cached
= (MonoClass
*)g_hash_table_lookup (image
->szarray_cache
, eclass
);
929 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
933 mono_image_set_lock (image_set
);
934 rootlist
= (GSList
*)g_hash_table_lookup (image_set
->array_cache
, eclass
);
935 for (list
= rootlist
; list
; list
= list
->next
) {
936 k
= (MonoClass
*)list
->data
;
937 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
942 mono_image_set_unlock (image_set
);
945 if (!image
->array_cache
)
946 image
->array_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
947 rootlist
= (GSList
*)g_hash_table_lookup (image
->array_cache
, eclass
);
948 for (list
= rootlist
; list
; list
= list
->next
) {
949 k
= (MonoClass
*)list
->data
;
950 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
955 mono_loader_unlock ();
961 parent
= mono_defaults
.array_class
;
963 mono_class_init_internal (parent
);
965 klass
= image_set
? (MonoClass
*)mono_image_set_alloc0 (image_set
, sizeof (MonoClassArray
)) : (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassArray
));
967 klass
->image
= image
;
968 klass
->name_space
= eclass
->name_space
;
969 klass
->class_kind
= MONO_CLASS_ARRAY
;
971 nsize
= strlen (eclass
->name
);
972 name
= (char *)g_malloc (nsize
+ 2 + rank
+ 1);
973 memcpy (name
, eclass
->name
, nsize
);
976 memset (name
+ nsize
+ 1, ',', rank
- 1);
978 name
[nsize
+ rank
] = '*';
979 name
[nsize
+ rank
+ bounded
] = ']';
980 name
[nsize
+ rank
+ bounded
+ 1] = 0;
981 klass
->name
= image_set
? mono_image_set_strdup (image_set
, name
) : mono_image_strdup (image
, name
);
984 klass
->type_token
= 0;
985 klass
->parent
= parent
;
986 klass
->instance_size
= mono_class_instance_size (klass
->parent
);
988 if (m_class_get_byval_arg (eclass
)->type
== MONO_TYPE_TYPEDBYREF
) {
989 /*Arrays of those two types are invalid.*/
990 ERROR_DECL (prepared_error
);
991 mono_error_set_invalid_program (prepared_error
, "Arrays of System.TypedReference types are invalid.");
992 mono_class_set_failure (klass
, mono_error_box (prepared_error
, klass
->image
));
993 mono_error_cleanup (prepared_error
);
994 } else if (m_class_is_byreflike (eclass
)) {
995 /* .NET Core throws a type load exception: "Could not create array type 'fullname[]'" */
996 char *full_name
= mono_type_get_full_name (eclass
);
997 mono_class_set_type_load_failure (klass
, "Could not create array type '%s[]'", full_name
);
999 } else if (eclass
->enumtype
&& !mono_class_enum_basetype_internal (eclass
)) {
1000 guint32 ref_info_handle
= mono_class_get_ref_info_handle (eclass
);
1001 if (!ref_info_handle
|| eclass
->wastypebuilder
) {
1002 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
1003 g_assert (ref_info_handle
&& !eclass
->wastypebuilder
);
1005 /* element_size -1 is ok as this is not an instantitable type*/
1006 klass
->sizes
.element_size
= -1;
1008 klass
->sizes
.element_size
= -1;
1010 mono_class_setup_supertypes (klass
);
1012 if (mono_class_is_ginst (eclass
))
1013 mono_class_init_internal (eclass
);
1014 if (!eclass
->size_inited
)
1015 mono_class_setup_fields (eclass
);
1016 mono_class_set_type_load_failure_causedby_class (klass
, eclass
, "Could not load array element type");
1017 /*FIXME we fail the array type, but we have to let other fields be set.*/
1019 klass
->has_references
= MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (eclass
)) || m_class_has_references (eclass
)? TRUE
: FALSE
;
1023 if (eclass
->enumtype
)
1024 klass
->cast_class
= eclass
->element_class
;
1026 klass
->cast_class
= eclass
;
1028 switch (m_class_get_byval_arg (m_class_get_cast_class (klass
))->type
) {
1030 klass
->cast_class
= mono_defaults
.byte_class
;
1033 klass
->cast_class
= mono_defaults
.int16_class
;
1036 #if TARGET_SIZEOF_VOID_P == 4
1040 klass
->cast_class
= mono_defaults
.int32_class
;
1043 #if TARGET_SIZEOF_VOID_P == 8
1047 klass
->cast_class
= mono_defaults
.int64_class
;
1053 klass
->element_class
= eclass
;
1055 if ((rank
> 1) || bounded
) {
1056 MonoArrayType
*at
= image_set
? (MonoArrayType
*)mono_image_set_alloc0 (image_set
, sizeof (MonoArrayType
)) : (MonoArrayType
*)mono_image_alloc0 (image
, sizeof (MonoArrayType
));
1057 klass
->_byval_arg
.type
= MONO_TYPE_ARRAY
;
1058 klass
->_byval_arg
.data
.array
= at
;
1059 at
->eklass
= eclass
;
1061 /* FIXME: complete.... */
1063 klass
->_byval_arg
.type
= MONO_TYPE_SZARRAY
;
1064 klass
->_byval_arg
.data
.klass
= eclass
;
1066 klass
->this_arg
= klass
->_byval_arg
;
1067 klass
->this_arg
.byref
= 1;
1070 ERROR_DECL (prepared_error
);
1071 name
= mono_type_get_full_name (klass
);
1072 mono_error_set_type_load_class (prepared_error
, klass
, "%s has too many dimensions.", name
);
1073 mono_class_set_failure (klass
, mono_error_box (prepared_error
, klass
->image
));
1074 mono_error_cleanup (prepared_error
);
1078 mono_loader_lock ();
1080 /* Check cache again */
1082 if (rank
== 1 && !bounded
) {
1084 mono_image_set_lock (image_set
);
1085 cached
= (MonoClass
*)g_hash_table_lookup (image_set
->szarray_cache
, eclass
);
1086 mono_image_set_unlock (image_set
);
1088 mono_os_mutex_lock (&image
->szarray_cache_lock
);
1089 cached
= (MonoClass
*)g_hash_table_lookup (image
->szarray_cache
, eclass
);
1090 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
1094 mono_image_set_lock (image_set
);
1095 rootlist
= (GSList
*)g_hash_table_lookup (image_set
->array_cache
, eclass
);
1096 for (list
= rootlist
; list
; list
= list
->next
) {
1097 k
= (MonoClass
*)list
->data
;
1098 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
1103 mono_image_set_unlock (image_set
);
1105 rootlist
= (GSList
*)g_hash_table_lookup (image
->array_cache
, eclass
);
1106 for (list
= rootlist
; list
; list
= list
->next
) {
1107 k
= (MonoClass
*)list
->data
;
1108 if ((m_class_get_rank (k
) == rank
) && (m_class_get_byval_arg (k
)->type
== (((rank
> 1) || bounded
) ? MONO_TYPE_ARRAY
: MONO_TYPE_SZARRAY
))) {
1116 mono_loader_unlock ();
1120 MONO_PROFILER_RAISE (class_loading
, (klass
));
1122 UnlockedAdd (&classes_size
, sizeof (MonoClassArray
));
1123 ++class_array_count
;
1125 if (rank
== 1 && !bounded
) {
1127 mono_image_set_lock (image_set
);
1128 g_hash_table_insert (image_set
->szarray_cache
, eclass
, klass
);
1129 mono_image_set_unlock (image_set
);
1131 mono_os_mutex_lock (&image
->szarray_cache_lock
);
1132 g_hash_table_insert (image
->szarray_cache
, eclass
, klass
);
1133 mono_os_mutex_unlock (&image
->szarray_cache_lock
);
1137 mono_image_set_lock (image_set
);
1138 list
= g_slist_append (rootlist
, klass
);
1139 g_hash_table_insert (image_set
->array_cache
, eclass
, list
);
1140 mono_image_set_unlock (image_set
);
1142 list
= g_slist_append (rootlist
, klass
);
1143 g_hash_table_insert (image
->array_cache
, eclass
, list
);
1147 mono_loader_unlock ();
1149 MONO_PROFILER_RAISE (class_loaded
, (klass
));
1155 * mono_class_create_array:
1156 * \param element_class element class
1157 * \param rank the dimension of the array class
1158 * \returns A class object describing the array with element type \p element_type and
1159 * dimension \p rank.
1162 mono_class_create_array (MonoClass
*eclass
, guint32 rank
)
1164 return mono_class_create_bounded_array (eclass
, rank
, FALSE
);
1167 // This is called by mono_class_create_generic_parameter when a new class must be created.
1169 make_generic_param_class (MonoGenericParam
*param
)
1171 MonoClass
*klass
, **ptr
;
1173 MonoGenericParamInfo
*pinfo
= mono_generic_param_info (param
);
1174 MonoGenericContainer
*container
= mono_generic_param_owner (param
);
1175 g_assert_checked (container
);
1177 MonoImage
*image
= mono_get_image_for_generic_param (param
);
1178 gboolean is_mvar
= container
->is_method
;
1179 gboolean is_anonymous
= container
->is_anonymous
;
1181 klass
= (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassGenericParam
));
1182 klass
->class_kind
= MONO_CLASS_GPARAM
;
1183 UnlockedAdd (&classes_size
, sizeof (MonoClassGenericParam
));
1184 UnlockedIncrement (&class_gparam_count
);
1186 if (!is_anonymous
) {
1187 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name
, pinfo
->name
);
1189 int n
= mono_generic_param_num (param
);
1190 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->name
, mono_make_generic_name_string (image
, n
) );
1194 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, "" );
1195 } else if (is_mvar
) {
1196 MonoMethod
*omethod
= container
->owner
.method
;
1197 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, (omethod
&& omethod
->klass
) ? omethod
->klass
->name_space
: "" );
1199 MonoClass
*oklass
= container
->owner
.klass
;
1200 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->name_space
, oklass
? oklass
->name_space
: "" );
1203 MONO_PROFILER_RAISE (class_loading
, (klass
));
1205 // Count non-NULL items in pinfo->constraints
1208 for (ptr
= pinfo
->constraints
; ptr
&& *ptr
; ptr
++, count
++)
1212 if ((count
> 0) && !MONO_CLASS_IS_INTERFACE_INTERNAL (pinfo
->constraints
[0])) {
1213 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, pinfo
->constraints
[0] );
1215 } else if (pinfo
&& pinfo
->flags
& GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT
) {
1216 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, mono_class_load_from_name (mono_defaults
.corlib
, "System", "ValueType") );
1218 CHECKED_METADATA_WRITE_PTR ( klass
->parent
, mono_defaults
.object_class
);
1221 if (count
- pos
> 0) {
1222 klass
->interface_count
= count
- pos
;
1223 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->interfaces
, (MonoClass
**)mono_image_alloc0 (image
, sizeof (MonoClass
*) * (count
- pos
)) );
1224 klass
->interfaces_inited
= TRUE
;
1225 for (i
= pos
; i
< count
; i
++)
1226 CHECKED_METADATA_WRITE_PTR ( klass
->interfaces
[i
- pos
] , pinfo
->constraints
[i
] );
1229 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass
->image
, image
);
1231 klass
->inited
= TRUE
;
1232 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->cast_class
, klass
);
1233 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass
->element_class
, klass
);
1235 MonoTypeEnum t
= is_mvar
? MONO_TYPE_MVAR
: MONO_TYPE_VAR
;
1236 klass
->_byval_arg
.type
= t
;
1237 klass
->this_arg
.type
= t
;
1238 CHECKED_METADATA_WRITE_PTR ( klass
->this_arg
.data
.generic_param
, param
);
1239 CHECKED_METADATA_WRITE_PTR ( klass
->_byval_arg
.data
.generic_param
, param
);
1240 klass
->this_arg
.byref
= TRUE
;
1242 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
1243 klass
->sizes
.generic_param_token
= !is_anonymous
? pinfo
->token
: 0;
1245 /*Init these fields to sane values*/
1246 klass
->min_align
= 1;
1248 * This makes sure the the value size of this class is equal to the size of the types the gparam is
1249 * constrained to, the JIT depends on this.
1251 klass
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + mono_type_stack_size_internal (m_class_get_byval_arg (klass
), NULL
, TRUE
);
1252 mono_memory_barrier ();
1253 klass
->size_inited
= 1;
1255 mono_class_setup_supertypes (klass
);
1257 if (count
- pos
> 0) {
1258 mono_class_setup_vtable (klass
->parent
);
1259 if (mono_class_has_failure (klass
->parent
))
1260 mono_class_set_type_load_failure (klass
, "Failed to setup parent interfaces");
1262 setup_interface_offsets (klass
, klass
->parent
->vtable_size
, TRUE
);
1269 * LOCKING: Acquires the image lock (@image).
1272 mono_class_create_generic_parameter (MonoGenericParam
*param
)
1274 MonoImage
*image
= mono_get_image_for_generic_param (param
);
1275 MonoGenericParamInfo
*pinfo
= mono_generic_param_info (param
);
1276 MonoClass
*klass
, *klass2
;
1278 // If a klass already exists for this object and is cached, return it.
1279 klass
= pinfo
->pklass
;
1284 // Create a new klass
1285 klass
= make_generic_param_class (param
);
1287 // Now we need to cache the klass we created.
1288 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
1289 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
1290 // and allow our newly-created klass object to just leak.
1291 mono_memory_barrier ();
1293 mono_image_lock (image
);
1295 // Here "klass2" refers to the klass potentially created by the other thread.
1296 klass2
= pinfo
->pklass
;
1301 pinfo
->pklass
= klass
;
1303 mono_image_unlock (image
);
1305 /* FIXME: Should this go inside 'make_generic_param_klass'? */
1307 MONO_PROFILER_RAISE (class_failed
, (klass2
));
1309 MONO_PROFILER_RAISE (class_loaded
, (klass
));
1315 * mono_class_create_ptr:
1318 mono_class_create_ptr (MonoType
*type
)
1321 MonoClass
*el_class
;
1324 MonoImageSet
* image_set
;
1326 el_class
= mono_class_from_mono_type_internal (type
);
1327 image
= el_class
->image
;
1328 image_set
= class_kind_may_contain_generic_instances ((MonoTypeKind
)el_class
->class_kind
) ? mono_metadata_get_image_set_for_class (el_class
) : NULL
;
1331 mono_image_set_lock (image_set
);
1332 if (image_set
->ptr_cache
) {
1333 if ((result
= (MonoClass
*)g_hash_table_lookup (image_set
->ptr_cache
, el_class
))) {
1334 mono_image_set_unlock (image_set
);
1338 mono_image_set_unlock (image_set
);
1340 mono_image_lock (image
);
1341 if (image
->ptr_cache
) {
1342 if ((result
= (MonoClass
*)g_hash_table_lookup (image
->ptr_cache
, el_class
))) {
1343 mono_image_unlock (image
);
1347 mono_image_unlock (image
);
1350 result
= image_set
? (MonoClass
*)mono_image_set_alloc0 (image_set
, sizeof (MonoClassPointer
)) : (MonoClass
*)mono_image_alloc0 (image
, sizeof (MonoClassPointer
));
1352 UnlockedAdd (&classes_size
, sizeof (MonoClassPointer
));
1353 ++class_pointer_count
;
1355 result
->parent
= NULL
; /* no parent for PTR types */
1356 result
->name_space
= el_class
->name_space
;
1357 name
= g_strdup_printf ("%s*", el_class
->name
);
1358 result
->name
= image_set
? mono_image_set_strdup (image_set
, name
) : mono_image_strdup (image
, name
);
1359 result
->class_kind
= MONO_CLASS_POINTER
;
1362 MONO_PROFILER_RAISE (class_loading
, (result
));
1364 result
->image
= el_class
->image
;
1365 result
->inited
= TRUE
;
1366 result
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
1367 result
->min_align
= sizeof (gpointer
);
1368 result
->cast_class
= result
->element_class
= el_class
;
1369 result
->blittable
= TRUE
;
1371 result
->this_arg
.type
= result
->_byval_arg
.type
= MONO_TYPE_PTR
;
1372 result
->this_arg
.data
.type
= result
->_byval_arg
.data
.type
= m_class_get_byval_arg (el_class
);
1373 result
->this_arg
.byref
= TRUE
;
1375 mono_class_setup_supertypes (result
);
1378 mono_image_set_lock (image_set
);
1379 if (image_set
->ptr_cache
) {
1381 if ((result2
= (MonoClass
*)g_hash_table_lookup (image_set
->ptr_cache
, el_class
))) {
1382 mono_image_set_unlock (image_set
);
1383 MONO_PROFILER_RAISE (class_failed
, (result
));
1388 image_set
->ptr_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1390 g_hash_table_insert (image_set
->ptr_cache
, el_class
, result
);
1391 mono_image_set_unlock (image_set
);
1393 mono_image_lock (image
);
1394 if (image
->ptr_cache
) {
1396 if ((result2
= (MonoClass
*)g_hash_table_lookup (image
->ptr_cache
, el_class
))) {
1397 mono_image_unlock (image
);
1398 MONO_PROFILER_RAISE (class_failed
, (result
));
1402 image
->ptr_cache
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1404 g_hash_table_insert (image
->ptr_cache
, el_class
, result
);
1405 mono_image_unlock (image
);
1408 MONO_PROFILER_RAISE (class_loaded
, (result
));
1414 mono_class_create_fnptr (MonoMethodSignature
*sig
)
1416 MonoClass
*result
, *cached
;
1417 static GHashTable
*ptr_hash
= NULL
;
1419 /* FIXME: These should be allocate from a mempool as well, but which one ? */
1421 mono_loader_lock ();
1423 ptr_hash
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1424 cached
= (MonoClass
*)g_hash_table_lookup (ptr_hash
, sig
);
1425 mono_loader_unlock ();
1429 result
= g_new0 (MonoClass
, 1);
1431 result
->parent
= NULL
; /* no parent for PTR types */
1432 result
->name_space
= "System";
1433 result
->name
= "MonoFNPtrFakeClass";
1434 result
->class_kind
= MONO_CLASS_POINTER
;
1436 result
->image
= mono_defaults
.corlib
; /* need to fix... */
1437 result
->instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
1438 result
->min_align
= sizeof (gpointer
);
1439 result
->cast_class
= result
->element_class
= result
;
1440 result
->this_arg
.type
= result
->_byval_arg
.type
= MONO_TYPE_FNPTR
;
1441 result
->this_arg
.data
.method
= result
->_byval_arg
.data
.method
= sig
;
1442 result
->this_arg
.byref
= TRUE
;
1443 result
->blittable
= TRUE
;
1444 result
->inited
= TRUE
;
1446 mono_class_setup_supertypes (result
);
1448 mono_loader_lock ();
1450 cached
= (MonoClass
*)g_hash_table_lookup (ptr_hash
, sig
);
1453 mono_loader_unlock ();
1457 MONO_PROFILER_RAISE (class_loading
, (result
));
1459 UnlockedAdd (&classes_size
, sizeof (MonoClassPointer
));
1460 ++class_pointer_count
;
1462 g_hash_table_insert (ptr_hash
, sig
, result
);
1464 mono_loader_unlock ();
1466 MONO_PROFILER_RAISE (class_loaded
, (result
));
1473 print_implemented_interfaces (MonoClass
*klass
)
1477 GPtrArray
*ifaces
= NULL
;
1479 int ancestor_level
= 0;
1481 name
= mono_type_get_full_name (klass
);
1482 printf ("Packed interface table for class %s has size %d\n", name
, klass
->interface_offsets_count
);
1485 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
1486 char *ic_name
= mono_type_get_full_name (klass
->interfaces_packed
[i
]);
1487 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s\n", i
,
1488 klass
->interfaces_packed
[i
]->interface_id
,
1489 klass
->interface_offsets_packed
[i
],
1490 mono_class_get_method_count (klass
->interfaces_packed
[i
]),
1494 printf ("Interface flags: ");
1495 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
1496 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
1497 printf ("(%d,T)", i
);
1499 printf ("(%d,F)", i
);
1501 printf ("Dump interface flags:");
1502 #ifdef COMPRESSED_INTERFACE_BITMAP
1504 const uint8_t* p
= klass
->interface_bitmap
;
1505 i
= klass
->max_interface_id
;
1507 printf (" %d x 00 %02X", p
[0], p
[1]);
1513 for (i
= 0; i
< ((((klass
->max_interface_id
+ 1) >> 3)) + (((klass
->max_interface_id
+ 1) & 7)? 1 :0)); i
++)
1514 printf (" %02X", klass
->interface_bitmap
[i
]);
1517 while (klass
!= NULL
) {
1518 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level
, klass
->name
);
1519 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
1520 if (!mono_error_ok (error
)) {
1521 printf (" Type failed due to %s\n", mono_error_get_message (error
));
1522 mono_error_cleanup (error
);
1523 } else if (ifaces
) {
1524 for (i
= 0; i
< ifaces
->len
; i
++) {
1525 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1526 printf (" [UIID %d] interface %s\n", ic
->interface_id
, ic
->name
);
1527 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i
,
1529 mono_class_interface_offset (klass
, ic
),
1530 mono_class_get_method_count (ic
),
1534 g_ptr_array_free (ifaces
, TRUE
);
1537 klass
= klass
->parent
;
1542 * Return the number of virtual methods.
1543 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
1544 * Return -1 on failure.
1545 * FIXME It would be nice if this information could be cached somewhere.
1548 count_virtual_methods (MonoClass
*klass
)
1550 int i
, mcount
, vcount
= 0;
1552 klass
= mono_class_get_generic_type_definition (klass
); /*We can find this information by looking at the GTD*/
1554 if (klass
->methods
|| !MONO_CLASS_HAS_STATIC_METADATA (klass
)) {
1555 mono_class_setup_methods (klass
);
1556 if (mono_class_has_failure (klass
))
1559 mcount
= mono_class_get_method_count (klass
);
1560 for (i
= 0; i
< mcount
; ++i
) {
1561 flags
= klass
->methods
[i
]->flags
;
1562 if (flags
& METHOD_ATTRIBUTE_VIRTUAL
)
1566 int first_idx
= mono_class_get_first_method_idx (klass
);
1567 mcount
= mono_class_get_method_count (klass
);
1568 for (i
= 0; i
< mcount
; ++i
) {
1569 flags
= mono_metadata_decode_table_row_col (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
, MONO_METHOD_FLAGS
);
1571 if (flags
& METHOD_ATTRIBUTE_VIRTUAL
)
1579 find_interface (int num_ifaces
, MonoClass
**interfaces_full
, MonoClass
*ic
)
1587 m
= (l
+ num_ifaces
) / 2;
1588 if (interfaces_full
[m
] == ic
)
1590 if (l
== num_ifaces
)
1592 if (!interfaces_full
[m
] || interfaces_full
[m
]->interface_id
> ic
->interface_id
) {
1601 set_interface_and_offset (int num_ifaces
, MonoClass
**interfaces_full
, int *interface_offsets_full
, MonoClass
*ic
, int offset
, mono_bool force_set
)
1603 int i
= find_interface (num_ifaces
, interfaces_full
, ic
);
1607 interface_offsets_full
[i
] = offset
;
1610 for (i
= 0; i
< num_ifaces
; ++i
) {
1611 if (interfaces_full
[i
]) {
1613 if (interfaces_full
[i
]->interface_id
< ic
->interface_id
)
1616 while (end
< num_ifaces
&& interfaces_full
[end
]) end
++;
1617 memmove (interfaces_full
+ i
+ 1, interfaces_full
+ i
, sizeof (MonoClass
*) * (end
- i
));
1618 memmove (interface_offsets_full
+ i
+ 1, interface_offsets_full
+ i
, sizeof (int) * (end
- i
));
1620 interfaces_full
[i
] = ic
;
1621 interface_offsets_full
[i
] = offset
;
1627 #ifdef COMPRESSED_INTERFACE_BITMAP
1630 * Compressed interface bitmap design.
1632 * Interface bitmaps take a large amount of memory, because their size is
1633 * linear with the maximum interface id assigned in the process (each interface
1634 * is assigned a unique id as it is loaded). The number of interface classes
1635 * is high because of the many implicit interfaces implemented by arrays (we'll
1636 * need to lazy-load them in the future).
1637 * Most classes implement a very small number of interfaces, so the bitmap is
1638 * sparse. This bitmap needs to be checked by interface casts, so access to the
1639 * needed bit must be fast and doable with few jit instructions.
1641 * The current compression format is as follows:
1642 * *) it is a sequence of one or more two-byte elements
1643 * *) the first byte in the element is the count of empty bitmap bytes
1644 * at the current bitmap position
1645 * *) the second byte in the element is an actual bitmap byte at the current
1648 * As an example, the following compressed bitmap bytes:
1649 * 0x07 0x01 0x00 0x7
1650 * correspond to the following bitmap:
1651 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
1653 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
1654 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
1655 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
1659 * mono_compress_bitmap:
1660 * \param dest destination buffer
1661 * \param bitmap bitmap buffer
1662 * \param size size of \p bitmap in bytes
1664 * This is a mono internal function.
1665 * The \p bitmap data is compressed into a format that is small but
1666 * still searchable in few instructions by the JIT and runtime.
1667 * The compressed data is stored in the buffer pointed to by the
1668 * \p dest array. Passing a NULL value for \p dest allows to just compute
1669 * the size of the buffer.
1670 * This compression algorithm assumes the bits set in the bitmap are
1671 * few and far between, like in interface bitmaps.
1672 * \returns The size of the compressed bitmap in bytes.
1675 mono_compress_bitmap (uint8_t *dest
, const uint8_t *bitmap
, int size
)
1679 const uint8_t *end
= bitmap
+ size
;
1680 while (bitmap
< end
) {
1681 if (*bitmap
|| numz
== 255) {
1705 * mono_class_interface_match:
1706 * \param bitmap a compressed bitmap buffer
1707 * \param id the index to check in the bitmap
1709 * This is a mono internal function.
1710 * Checks if a bit is set in a compressed interface bitmap. \p id must
1711 * be already checked for being smaller than the maximum id encoded in the
1714 * \returns A non-zero value if bit \p id is set in the bitmap \p bitmap,
1718 mono_class_interface_match (const uint8_t *bitmap
, int id
)
1721 id
-= bitmap
[0] * 8;
1725 return bitmap
[1] & (1 << id
);
1736 int insertion_order
;
1740 compare_by_interface_id (const void *a
, const void *b
)
1742 const ClassAndOffset
*ca
= (const ClassAndOffset
*)a
;
1743 const ClassAndOffset
*cb
= (const ClassAndOffset
*)b
;
1745 /* Sort on interface_id, but keep equal elements in the same relative
1747 int primary_order
= ca
->ic
->interface_id
- cb
->ic
->interface_id
;
1748 if (primary_order
!= 0)
1749 return primary_order
;
1751 return ca
->insertion_order
- cb
->insertion_order
;
1755 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
1756 * LOCKING: Acquires the loader lock.
1759 setup_interface_offsets (MonoClass
*klass
, int cur_slot
, gboolean overwrite
)
1763 int i
, j
, num_ifaces
;
1765 MonoClass
**interfaces_full
= NULL
;
1766 int *interface_offsets_full
= NULL
;
1768 GPtrArray
**ifaces_array
= NULL
;
1769 int interface_offsets_count
;
1771 num_ifaces
= interface_offsets_count
= 0;
1773 mono_loader_lock ();
1775 mono_class_setup_supertypes (klass
);
1777 if (mono_class_is_ginst (klass
)) {
1778 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
1780 interface_offsets_count
= num_ifaces
= gklass
->interface_offsets_count
;
1781 interfaces_full
= (MonoClass
**)g_malloc (sizeof (MonoClass
*) * num_ifaces
);
1782 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
1783 ClassAndOffset
*co_pair
= (ClassAndOffset
*) g_malloc (sizeof (ClassAndOffset
) * num_ifaces
);
1786 for (int i
= 0; i
< num_ifaces
; ++i
) {
1787 MonoClass
*gklass_ic
= gklass
->interfaces_packed
[i
];
1788 MonoClass
*inflated
= mono_class_inflate_generic_class_checked (gklass_ic
, mono_class_get_context(klass
), error
);
1789 if (!is_ok (error
)) {
1790 char *name
= mono_type_get_full_name (gklass_ic
);
1791 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1797 mono_class_setup_interface_id_internal (inflated
);
1799 co_pair
[i
].ic
= inflated
;
1800 co_pair
[i
].offset
= gklass
->interface_offsets_packed
[i
];
1801 co_pair
[i
].insertion_order
= i
;
1803 int count
= count_virtual_methods (inflated
);
1805 char *name
= mono_type_get_full_name (inflated
);
1806 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1812 cur_slot
= MAX (cur_slot
, interface_offsets_full
[i
] + count
);
1813 max_iid
= MAX (max_iid
, inflated
->interface_id
);
1816 /* qsort() is not guaranteed to be a stable sort (elements with
1817 * equal keys stay in the same relative order). In practice,
1818 * qsort from MSVC isn't stable. So we add a
1819 * ClassAndOffset:insertion_order field and use it as a
1820 * secondary sorting key when the interface ids are equal. */
1821 qsort (co_pair
, num_ifaces
, sizeof (ClassAndOffset
), compare_by_interface_id
);
1822 for (int i
= 0; i
< num_ifaces
; ++i
) {
1823 interfaces_full
[i
] = co_pair
[i
].ic
;
1824 interface_offsets_full
[i
] = co_pair
[i
].offset
;
1826 g_assert (i
== 0 || interfaces_full
[i
]->interface_id
>= interfaces_full
[i
- 1]->interface_id
);
1832 /* compute maximum number of slots and maximum interface id */
1834 num_ifaces
= 0; /* this can include duplicated ones */
1835 ifaces_array
= g_new0 (GPtrArray
*, klass
->idepth
);
1836 for (j
= 0; j
< klass
->idepth
; j
++) {
1837 k
= klass
->supertypes
[j
];
1839 num_ifaces
+= k
->interface_count
;
1840 for (i
= 0; i
< k
->interface_count
; i
++) {
1841 ic
= k
->interfaces
[i
];
1843 /* A gparam does not have any interface_id set. */
1844 if (! mono_class_is_gparam (ic
))
1845 mono_class_setup_interface_id_internal (ic
);
1847 if (max_iid
< ic
->interface_id
)
1848 max_iid
= ic
->interface_id
;
1850 ifaces
= mono_class_get_implemented_interfaces (k
, error
);
1851 if (!mono_error_ok (error
)) {
1852 char *name
= mono_type_get_full_name (k
);
1853 mono_class_set_type_load_failure (klass
, "Error getting the interfaces of %s due to %s", name
, mono_error_get_message (error
));
1855 mono_error_cleanup (error
);
1860 num_ifaces
+= ifaces
->len
;
1861 for (i
= 0; i
< ifaces
->len
; ++i
) {
1862 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1863 if (max_iid
< ic
->interface_id
)
1864 max_iid
= ic
->interface_id
;
1866 ifaces_array
[j
] = ifaces
;
1870 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
1872 if (max_iid
< klass
->interface_id
)
1873 max_iid
= klass
->interface_id
;
1876 /* compute vtable offset for interfaces */
1877 interfaces_full
= (MonoClass
**)g_malloc0 (sizeof (MonoClass
*) * num_ifaces
);
1878 interface_offsets_full
= (int *)g_malloc (sizeof (int) * num_ifaces
);
1880 for (i
= 0; i
< num_ifaces
; i
++)
1881 interface_offsets_full
[i
] = -1;
1883 /* skip the current class */
1884 for (j
= 0; j
< klass
->idepth
- 1; j
++) {
1885 k
= klass
->supertypes
[j
];
1886 ifaces
= ifaces_array
[j
];
1889 for (i
= 0; i
< ifaces
->len
; ++i
) {
1891 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1893 /*Force the sharing of interface offsets between parent and subtypes.*/
1894 io
= mono_class_interface_offset (k
, ic
);
1895 g_assertf (io
>= 0, "class %s parent %s has no offset for iface %s",
1896 mono_type_get_full_name (klass
),
1897 mono_type_get_full_name (k
),
1898 mono_type_get_full_name (ic
));
1900 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, io
, TRUE
);
1905 g_assert (klass
== klass
->supertypes
[klass
->idepth
- 1]);
1906 ifaces
= ifaces_array
[klass
->idepth
- 1];
1908 for (i
= 0; i
< ifaces
->len
; ++i
) {
1910 ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
1911 if (set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, ic
, cur_slot
, FALSE
))
1913 count
= count_virtual_methods (ic
);
1915 char *name
= mono_type_get_full_name (ic
);
1916 mono_class_set_type_load_failure (klass
, "Error calculating interface offset of %s", name
);
1925 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
))
1926 set_interface_and_offset (num_ifaces
, interfaces_full
, interface_offsets_full
, klass
, cur_slot
, TRUE
);
1928 for (interface_offsets_count
= 0, i
= 0; i
< num_ifaces
; i
++) {
1929 if (interface_offsets_full
[i
] != -1)
1930 interface_offsets_count
++;
1934 /* Publish the data */
1935 klass
->max_interface_id
= max_iid
;
1937 * We might get called multiple times:
1938 * - mono_class_init_internal ()
1939 * - mono_class_setup_vtable ().
1940 * - mono_class_setup_interface_offsets ().
1941 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
1942 * means we have to overwrite those when called from other places (#4440).
1944 if (klass
->interfaces_packed
) {
1946 g_assert (klass
->interface_offsets_count
== interface_offsets_count
);
1950 klass
->interface_offsets_count
= interface_offsets_count
;
1951 klass
->interfaces_packed
= (MonoClass
**)mono_class_alloc (klass
, sizeof (MonoClass
*) * interface_offsets_count
);
1952 klass
->interface_offsets_packed
= (guint16
*)mono_class_alloc (klass
, sizeof (guint16
) * interface_offsets_count
);
1953 bsize
= (sizeof (guint8
) * ((max_iid
+ 1) >> 3)) + (((max_iid
+ 1) & 7)? 1 :0);
1954 #ifdef COMPRESSED_INTERFACE_BITMAP
1955 bitmap
= g_malloc0 (bsize
);
1957 bitmap
= (uint8_t *)mono_class_alloc0 (klass
, bsize
);
1959 for (i
= 0; i
< interface_offsets_count
; i
++) {
1960 guint32 id
= interfaces_full
[i
]->interface_id
;
1961 bitmap
[id
>> 3] |= (1 << (id
& 7));
1962 klass
->interfaces_packed
[i
] = interfaces_full
[i
];
1963 klass
->interface_offsets_packed
[i
] = interface_offsets_full
[i
];
1965 #ifdef COMPRESSED_INTERFACE_BITMAP
1966 i
= mono_compress_bitmap (NULL
, bitmap
, bsize
);
1967 klass
->interface_bitmap
= mono_class_alloc0 (klass
, i
);
1968 mono_compress_bitmap (klass
->interface_bitmap
, bitmap
, bsize
);
1971 klass
->interface_bitmap
= bitmap
;
1975 mono_loader_unlock ();
1977 g_free (interfaces_full
);
1978 g_free (interface_offsets_full
);
1980 for (i
= 0; i
< klass
->idepth
; i
++) {
1981 ifaces
= ifaces_array
[i
];
1983 g_ptr_array_free (ifaces
, TRUE
);
1985 g_free (ifaces_array
);
1988 //printf ("JUST DONE: ");
1989 //print_implemented_interfaces (klass);
1995 * Setup interface offsets for interfaces.
1997 * - klass->max_interface_id
1998 * - klass->interface_offsets_count
1999 * - klass->interfaces_packed
2000 * - klass->interface_offsets_packed
2001 * - klass->interface_bitmap
2003 * This function can fail @class.
2007 mono_class_setup_interface_offsets (MonoClass
*klass
)
2009 /* NOTE: This function is only correct for interfaces.
2011 * It assumes that klass's interfaces can be assigned offsets starting
2012 * from 0. That assumption is incorrect for classes and valuetypes.
2014 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) && !mono_class_is_ginst (klass
));
2015 setup_interface_offsets (klass
, 0, FALSE
);
2018 #define DEBUG_INTERFACE_VTABLE_CODE 0
2019 #define TRACE_INTERFACE_VTABLE_CODE 0
2020 #define VERIFY_INTERFACE_VTABLE_CODE 0
2021 #define VTABLE_SELECTOR (1)
2023 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2024 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
2025 if (!(VTABLE_SELECTOR)) break; \
2029 #define DEBUG_INTERFACE_VTABLE(stmt)
2032 #if TRACE_INTERFACE_VTABLE_CODE
2033 #define TRACE_INTERFACE_VTABLE(stmt) do {\
2034 if (!(VTABLE_SELECTOR)) break; \
2038 #define TRACE_INTERFACE_VTABLE(stmt)
2041 #if VERIFY_INTERFACE_VTABLE_CODE
2042 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
2043 if (!(VTABLE_SELECTOR)) break; \
2047 #define VERIFY_INTERFACE_VTABLE(stmt)
2051 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2053 mono_signature_get_full_desc (MonoMethodSignature
*sig
, gboolean include_namespace
)
2057 GString
*res
= g_string_new ("");
2059 g_string_append_c (res
, '(');
2060 for (i
= 0; i
< sig
->param_count
; ++i
) {
2062 g_string_append_c (res
, ',');
2063 mono_type_get_desc (res
, sig
->params
[i
], include_namespace
);
2065 g_string_append (res
, ")=>");
2066 if (sig
->ret
!= NULL
) {
2067 mono_type_get_desc (res
, sig
->ret
, include_namespace
);
2069 g_string_append (res
, "NULL");
2072 g_string_free (res
, FALSE
);
2076 print_method_signatures (MonoMethod
*im
, MonoMethod
*cm
) {
2077 char *im_sig
= mono_signature_get_full_desc (mono_method_signature_internal (im
), TRUE
);
2078 char *cm_sig
= mono_signature_get_full_desc (mono_method_signature_internal (cm
), TRUE
);
2079 printf ("(IM \"%s\", CM \"%s\")", im_sig
, cm_sig
);
2088 is_wcf_hack_disabled (void)
2090 static gboolean disabled
;
2091 static gboolean inited
= FALSE
;
2093 disabled
= g_hasenv ("MONO_DISABLE_WCF_HACK");
2100 check_interface_method_override (MonoClass
*klass
, MonoMethod
*im
, MonoMethod
*cm
, gboolean require_newslot
, gboolean interface_is_explicitly_implemented_by_class
, gboolean slot_is_empty
)
2102 MonoMethodSignature
*cmsig
, *imsig
;
2103 if (strcmp (im
->name
, cm
->name
) == 0) {
2104 if (! (cm
->flags
& METHOD_ATTRIBUTE_PUBLIC
)) {
2105 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
2108 if (! slot_is_empty
) {
2109 if (require_newslot
) {
2110 if (! interface_is_explicitly_implemented_by_class
) {
2111 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
2114 if (! (cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
2115 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
2119 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
2122 cmsig
= mono_method_signature_internal (cm
);
2123 imsig
= mono_method_signature_internal (im
);
2124 if (!cmsig
|| !imsig
) {
2125 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
2129 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
2130 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
2131 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
2132 TRACE_INTERFACE_VTABLE (printf ("]"));
2135 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
2136 if (mono_security_core_clr_enabled ())
2137 mono_security_core_clr_check_override (klass
, cm
, im
);
2139 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
2140 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
2141 char *body_name
= mono_method_full_name (cm
, TRUE
);
2142 char *decl_name
= mono_method_full_name (im
, TRUE
);
2143 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2151 MonoClass
*ic
= im
->klass
;
2152 const char *ic_name_space
= ic
->name_space
;
2153 const char *ic_name
= ic
->name
;
2156 if (! require_newslot
) {
2157 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
2160 if (cm
->klass
->rank
== 0) {
2161 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
2164 cmsig
= mono_method_signature_internal (cm
);
2165 imsig
= mono_method_signature_internal (im
);
2166 if (!cmsig
|| !imsig
) {
2167 mono_class_set_type_load_failure (klass
, "Could not resolve the signature of a virtual method");
2171 if (! mono_metadata_signature_equal (cmsig
, imsig
)) {
2172 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
2173 TRACE_INTERFACE_VTABLE (print_method_signatures (im
, cm
));
2174 TRACE_INTERFACE_VTABLE (printf ("]"));
2177 if (mono_class_get_image (ic
) != mono_defaults
.corlib
) {
2178 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
2181 if ((ic_name_space
== NULL
) || (strcmp (ic_name_space
, "System.Collections.Generic") != 0)) {
2182 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
2185 if ((ic_name
== NULL
) || ((strcmp (ic_name
, "IEnumerable`1") != 0) && (strcmp (ic_name
, "ICollection`1") != 0) && (strcmp (ic_name
, "IList`1") != 0) && (strcmp (ic_name
, "IReadOnlyList`1") != 0) && (strcmp (ic_name
, "IReadOnlyCollection`1") != 0))) {
2186 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
2190 subname
= (char*)strstr (cm
->name
, ic_name_space
);
2191 if (subname
!= cm
->name
) {
2192 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
2195 subname
+= strlen (ic_name_space
);
2196 if (subname
[0] != '.') {
2197 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
2201 if (strstr (subname
, ic_name
) != subname
) {
2202 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
2205 subname
+= strlen (ic_name
);
2206 if (subname
[0] != '.') {
2207 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
2211 if (strcmp (subname
, im
->name
) != 0) {
2212 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
2216 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
2217 if (mono_security_core_clr_enabled ())
2218 mono_security_core_clr_check_override (klass
, cm
, im
);
2220 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
2221 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, im
, NULL
)) {
2222 char *body_name
= mono_method_full_name (cm
, TRUE
);
2223 char *decl_name
= mono_method_full_name (im
, TRUE
);
2224 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2234 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
2236 foreach_override (gpointer key
, gpointer value
, gpointer user_data
) {
2237 MonoMethod
*method
= key
;
2238 MonoMethod
*override
= value
;
2239 MonoClass
*method_class
= mono_method_get_class (method
);
2240 MonoClass
*override_class
= mono_method_get_class (override
);
2242 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
2243 m_class_get_name_space (method_class
), m_class_get_name (method_class
), mono_method_get_name (method
),
2244 m_class_get_name_space (override_class
), m_class_get_name (override_class
), mono_method_get_name (override
));
2247 print_overrides (GHashTable
*override_map
, const char *message
) {
2249 printf ("Override map \"%s\" START:\n", message
);
2250 g_hash_table_foreach (override_map
, foreach_override
, NULL
);
2251 printf ("Override map \"%s\" END.\n", message
);
2253 printf ("Override map \"%s\" EMPTY.\n", message
);
2257 print_vtable_full (MonoClass
*klass
, MonoMethod
** vtable
, int size
, int first_non_interface_slot
, const char *message
, gboolean print_interfaces
) {
2258 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2262 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name
, message
, size
);
2264 if (print_interfaces
) {
2265 print_implemented_interfaces (klass
);
2266 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name
, size
);
2269 if (klass
->parent
) {
2270 parent_size
= klass
->parent
->vtable_size
;
2274 for (i
= 0; i
< size
; ++i
) {
2275 MonoMethod
*cm
= vtable
[i
];
2276 char *cm_name
= cm
? mono_method_full_name (cm
, TRUE
) : g_strdup ("nil");
2277 char newness
= (i
< parent_size
) ? 'O' : ((i
< first_non_interface_slot
) ? 'I' : 'N');
2279 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness
, i
, cm
? cm
->slot
: - 1, cm_name
, cm
);
2287 #if VERIFY_INTERFACE_VTABLE_CODE
2289 mono_method_try_get_vtable_index (MonoMethod
*method
)
2291 if (method
->is_inflated
&& (method
->flags
& METHOD_ATTRIBUTE_VIRTUAL
)) {
2292 MonoMethodInflated
*imethod
= (MonoMethodInflated
*)method
;
2293 if (imethod
->declaring
->is_generic
)
2294 return imethod
->declaring
->slot
;
2296 return method
->slot
;
2300 mono_class_verify_vtable (MonoClass
*klass
)
2303 char *full_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2305 printf ("*** Verifying VTable of class '%s' \n", full_name
);
2309 if (!klass
->methods
)
2312 count
= mono_class_get_method_count (klass
);
2313 for (i
= 0; i
< count
; ++i
) {
2314 MonoMethod
*cm
= klass
->methods
[i
];
2317 if (!(cm
->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2321 full_name
= mono_method_full_name (cm
, TRUE
);
2323 slot
= mono_method_try_get_vtable_index (cm
);
2325 if (slot
>= klass
->vtable_size
) {
2326 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name
, slot
, klass
->vtable_size
);
2330 if (slot
>= 0 && klass
->vtable
[slot
] != cm
&& (klass
->vtable
[slot
])) {
2331 char *other_name
= klass
->vtable
[slot
] ? mono_method_full_name (klass
->vtable
[slot
], TRUE
) : g_strdup ("[null value]");
2332 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name
, slot
, other_name
);
2333 g_free (other_name
);
2336 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name
);
2343 mono_method_get_method_definition (MonoMethod
*method
)
2345 while (method
->is_inflated
)
2346 method
= ((MonoMethodInflated
*)method
)->declaring
;
2351 verify_class_overrides (MonoClass
*klass
, MonoMethod
**overrides
, int onum
)
2355 for (i
= 0; i
< onum
; ++i
) {
2356 MonoMethod
*decl
= overrides
[i
* 2];
2357 MonoMethod
*body
= overrides
[i
* 2 + 1];
2359 if (mono_class_get_generic_type_definition (body
->klass
) != mono_class_get_generic_type_definition (klass
)) {
2360 mono_class_set_type_load_failure (klass
, "Method belongs to a different class than the declared one");
2364 if (!(body
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (body
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2365 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
2366 mono_class_set_type_load_failure (klass
, "Method must not be static to override a base type");
2368 mono_class_set_type_load_failure (klass
, "Method must be virtual to override a base type");
2372 if (!(decl
->flags
& METHOD_ATTRIBUTE_VIRTUAL
) || (decl
->flags
& METHOD_ATTRIBUTE_STATIC
)) {
2373 if (body
->flags
& METHOD_ATTRIBUTE_STATIC
)
2374 mono_class_set_type_load_failure (klass
, "Cannot override a static method in a base type");
2376 mono_class_set_type_load_failure (klass
, "Cannot override a non virtual method in a base type");
2380 if (!mono_class_is_assignable_from_slow (decl
->klass
, klass
)) {
2381 mono_class_set_type_load_failure (klass
, "Method overrides a class or interface that is not extended or implemented by this type");
2385 body
= mono_method_get_method_definition (body
);
2386 decl
= mono_method_get_method_definition (decl
);
2388 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body
, decl
, NULL
)) {
2389 char *body_name
= mono_method_full_name (body
, TRUE
);
2390 char *decl_name
= mono_method_full_name (decl
, TRUE
);
2391 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
2400 /*Checks if @klass has @parent as one of it's parents type gtd
2404 * Bar<T> : Foo<Bar<Bar<T>>>
2408 mono_class_has_gtd_parent (MonoClass
*klass
, MonoClass
*parent
)
2410 klass
= mono_class_get_generic_type_definition (klass
);
2411 parent
= mono_class_get_generic_type_definition (parent
);
2412 mono_class_setup_supertypes (klass
);
2413 mono_class_setup_supertypes (parent
);
2415 return klass
->idepth
>= parent
->idepth
&&
2416 mono_class_get_generic_type_definition (klass
->supertypes
[parent
->idepth
- 1]) == parent
;
2420 mono_class_check_vtable_constraints (MonoClass
*klass
, GList
*in_setup
)
2422 MonoGenericInst
*ginst
;
2425 if (!mono_class_is_ginst (klass
)) {
2426 mono_class_setup_vtable_full (klass
, in_setup
);
2427 return !mono_class_has_failure (klass
);
2430 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass
), in_setup
);
2431 if (mono_class_set_type_load_failure_causedby_class (klass
, mono_class_get_generic_class (klass
)->container_class
, "Failed to load generic definition vtable"))
2434 ginst
= mono_class_get_generic_class (klass
)->context
.class_inst
;
2435 for (i
= 0; i
< ginst
->type_argc
; ++i
) {
2437 if (ginst
->type_argv
[i
]->type
!= MONO_TYPE_GENERICINST
)
2439 arg
= mono_class_from_mono_type_internal (ginst
->type_argv
[i
]);
2440 /*Those 2 will be checked by mono_class_setup_vtable itself*/
2441 if (mono_class_has_gtd_parent (klass
, arg
) || mono_class_has_gtd_parent (arg
, klass
))
2443 if (!mono_class_check_vtable_constraints (arg
, in_setup
)) {
2444 mono_class_set_type_load_failure (klass
, "Failed to load generic parameter %d", i
);
2452 * mono_class_setup_vtable:
2454 * Creates the generic vtable of CLASS.
2455 * Initializes the following fields in MonoClass:
2458 * Plus all the fields initialized by setup_interface_offsets ().
2459 * If there is an error during vtable construction, klass->has_failure
2460 * is set and details are stored in a MonoErrorBoxed.
2462 * LOCKING: Acquires the loader lock.
2465 mono_class_setup_vtable (MonoClass
*klass
)
2467 mono_class_setup_vtable_full (klass
, NULL
);
2471 mono_class_setup_vtable_full (MonoClass
*klass
, GList
*in_setup
)
2474 MonoMethod
**overrides
= NULL
;
2475 MonoGenericContext
*context
;
2482 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
2483 /* This sets method->slot for all methods if this is an interface */
2484 mono_class_setup_methods (klass
);
2488 if (mono_class_has_failure (klass
))
2491 if (g_list_find (in_setup
, klass
))
2494 mono_loader_lock ();
2496 if (klass
->vtable
) {
2497 mono_loader_unlock ();
2501 UnlockedIncrement (&mono_stats
.generic_vtable_count
);
2502 in_setup
= g_list_prepend (in_setup
, klass
);
2504 if (mono_class_is_ginst (klass
)) {
2505 if (!mono_class_check_vtable_constraints (klass
, in_setup
)) {
2506 mono_loader_unlock ();
2507 g_list_remove (in_setup
, klass
);
2511 context
= mono_class_get_context (klass
);
2512 type_token
= mono_class_get_generic_class (klass
)->container_class
->type_token
;
2514 context
= (MonoGenericContext
*) mono_class_try_get_generic_container (klass
); //FIXME is this a case of a try?
2515 type_token
= klass
->type_token
;
2518 if (image_is_dynamic (klass
->image
)) {
2519 /* Generic instances can have zero method overrides without causing any harm.
2520 * This is true since we don't do layout all over again for them, we simply inflate
2521 * the layout of the parent.
2523 mono_reflection_get_dynamic_overrides (klass
, &overrides
, &onum
, error
);
2524 if (!is_ok (error
)) {
2525 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
2529 /* The following call fails if there are missing methods in the type */
2530 /* FIXME it's probably a good idea to avoid this for generic instances. */
2531 mono_class_get_overrides_full (klass
->image
, type_token
, &overrides
, &onum
, context
, error
);
2532 if (!is_ok (error
)) {
2533 mono_class_set_type_load_failure (klass
, "Could not load list of method overrides due to %s", mono_error_get_message (error
));
2538 mono_class_setup_vtable_general (klass
, overrides
, onum
, in_setup
);
2542 mono_error_cleanup (error
);
2544 mono_loader_unlock ();
2545 g_list_remove (in_setup
, klass
);
2551 mono_class_need_stelemref_method (MonoClass
*klass
)
2553 return klass
->rank
== 1 && MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass
)));
2557 apply_override (MonoClass
*klass
, MonoClass
*override_class
, MonoMethod
**vtable
, MonoMethod
*decl
, MonoMethod
*override
,
2558 GHashTable
**override_map
, GHashTable
**override_class_map
, GHashTable
**conflict_map
)
2561 dslot
= mono_method_get_vtable_slot (decl
);
2563 mono_class_set_type_load_failure (klass
, "");
2567 dslot
+= mono_class_interface_offset (klass
, decl
->klass
);
2568 vtable
[dslot
] = override
;
2569 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (override
->klass
)) {
2571 * If override from an interface, then it is an override of a default interface method,
2572 * don't override its slot.
2574 vtable
[dslot
]->slot
= dslot
;
2577 if (!*override_map
) {
2578 *override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2579 *override_class_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2581 GHashTable
*map
= *override_map
;
2582 GHashTable
*class_map
= *override_class_map
;
2584 MonoMethod
*prev_override
= (MonoMethod
*)g_hash_table_lookup (map
, decl
);
2585 MonoClass
*prev_override_class
= (MonoClass
*)g_hash_table_lookup (class_map
, decl
);
2587 g_hash_table_insert (map
, decl
, override
);
2588 g_hash_table_insert (class_map
, decl
, override_class
);
2590 /* Collect potentially conflicting overrides which are introduced by default interface methods */
2591 if (prev_override
) {
2595 * The override methods are part of the generic definition, need to inflate them so their
2596 * parent class becomes the actual interface/class containing the override, i.e.
2598 * class Foo<T> : IFace<T>
2599 * This is needed so the mono_class_is_assignable_from_internal () calls in the
2600 * conflict resolution work.
2602 if (mono_class_is_ginst (override_class
)) {
2603 override
= mono_class_inflate_generic_method_checked (override
, &mono_class_get_generic_class (override_class
)->context
, error
);
2604 mono_error_assert_ok (error
);
2607 if (mono_class_is_ginst (prev_override_class
)) {
2608 prev_override
= mono_class_inflate_generic_method_checked (prev_override
, &mono_class_get_generic_class (prev_override_class
)->context
, error
);
2609 mono_error_assert_ok (error
);
2613 *conflict_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
2614 GHashTable
*cmap
= *conflict_map
;
2615 GSList
*entries
= (GSList
*)g_hash_table_lookup (cmap
, decl
);
2616 if (!(decl
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
2617 entries
= g_slist_prepend (entries
, decl
);
2618 entries
= g_slist_prepend (entries
, prev_override
);
2619 entries
= g_slist_prepend (entries
, override
);
2621 g_hash_table_insert (cmap
, decl
, entries
);
2628 handle_dim_conflicts (MonoMethod
**vtable
, MonoClass
*klass
, GHashTable
*conflict_map
)
2630 GHashTableIter iter
;
2632 GSList
*entries
, *l
, *l2
;
2633 GSList
*dim_conflicts
= NULL
;
2635 g_hash_table_iter_init (&iter
, conflict_map
);
2636 while (g_hash_table_iter_next (&iter
, (gpointer
*)&decl
, (gpointer
*)&entries
)) {
2638 * Iterate over the candidate methods, remove ones whose class is less concrete than the
2639 * class of another one.
2641 /* This is O(n^2), but that shouldn't be a problem in practice */
2642 for (l
= entries
; l
; l
= l
->next
) {
2643 for (l2
= entries
; l2
; l2
= l2
->next
) {
2644 MonoMethod
*m1
= (MonoMethod
*)l
->data
;
2645 MonoMethod
*m2
= (MonoMethod
*)l2
->data
;
2646 if (!m1
|| !m2
|| m1
== m2
)
2648 if (mono_class_is_assignable_from_internal (m1
->klass
, m2
->klass
))
2650 else if (mono_class_is_assignable_from_internal (m2
->klass
, m1
->klass
))
2655 MonoMethod
*impl
= NULL
;
2656 for (l
= entries
; l
; l
= l
->next
) {
2659 impl
= (MonoMethod
*)l
->data
;
2663 /* If more than one method is left, we have a conflict */
2664 if (decl
->is_inflated
)
2665 decl
= ((MonoMethodInflated
*)decl
)->declaring
;
2666 dim_conflicts
= g_slist_prepend (dim_conflicts
, decl
);
2668 for (l = entries; l; l = l->next) {
2670 printf ("%s %s %s\n", mono_class_full_name (klass), mono_method_full_name (decl, TRUE), mono_method_full_name (l->data, TRUE));
2675 * Use the implementing method computed above instead of the already
2676 * computed one, which depends on interface ordering.
2678 int ic_offset
= mono_class_interface_offset (klass
, decl
->klass
);
2679 int im_slot
= ic_offset
+ decl
->slot
;
2680 vtable
[im_slot
] = impl
;
2682 g_slist_free (entries
);
2684 if (dim_conflicts
) {
2685 mono_loader_lock ();
2686 klass
->has_dim_conflicts
= 1;
2687 mono_loader_unlock ();
2690 * Exceptions are thrown at method call time and only for the methods which have
2691 * conflicts, so just save them in the class.
2694 /* Make a copy of the list from the class mempool */
2695 GSList
*conflicts
= (GSList
*)mono_class_alloc0 (klass
, g_slist_length (dim_conflicts
) * sizeof (GSList
));
2697 for (l
= dim_conflicts
; l
; l
= l
->next
) {
2698 conflicts
[i
].data
= l
->data
;
2699 conflicts
[i
].next
= &conflicts
[i
+ 1];
2702 conflicts
[i
- 1].next
= NULL
;
2704 mono_class_set_dim_conflicts (klass
, conflicts
);
2705 g_slist_free (dim_conflicts
);
2710 print_unimplemented_interface_method_info (MonoClass
*klass
, MonoClass
*ic
, MonoMethod
*im
, int im_slot
, MonoMethod
**overrides
, int onum
)
2713 char *method_signature
;
2716 for (index
= 0; index
< onum
; ++index
) {
2717 mono_trace_warning (MONO_TRACE_TYPE
, " at slot %d: %s (%d) overrides %s (%d)", im_slot
, overrides
[index
*2+1]->name
,
2718 overrides
[index
*2+1]->slot
, overrides
[index
*2]->name
, overrides
[index
*2]->slot
);
2720 method_signature
= mono_signature_get_desc (mono_method_signature_internal (im
), FALSE
);
2721 type_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
2722 mono_trace_warning (MONO_TRACE_TYPE
, "no implementation for interface method %s::%s(%s) in class %s",
2723 mono_type_get_name (m_class_get_byval_arg (ic
)), im
->name
, method_signature
, type_name
);
2724 g_free (method_signature
);
2726 mono_class_setup_methods (klass
);
2727 if (mono_class_has_failure (klass
)) {
2728 char *name
= mono_type_get_full_name (klass
);
2729 mono_trace_warning (MONO_TRACE_TYPE
, "CLASS %s failed to resolve methods", name
);
2733 mcount
= mono_class_get_method_count (klass
);
2734 for (index
= 0; index
< mcount
; ++index
) {
2735 MonoMethod
*cm
= klass
->methods
[index
];
2736 method_signature
= mono_signature_get_desc (mono_method_signature_internal (cm
), TRUE
);
2738 mono_trace_warning (MONO_TRACE_TYPE
, "METHOD %s(%s)", cm
->name
, method_signature
);
2739 g_free (method_signature
);
2744 * mono_class_get_virtual_methods:
2746 * Iterate over the virtual methods of KLASS.
2748 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
2751 mono_class_get_virtual_methods (MonoClass
* klass
, gpointer
*iter
)
2753 gboolean static_iter
= FALSE
;
2759 * If the lowest bit of the iterator is 1, this is an iterator for static metadata,
2760 * and the upper bits contain an index. Otherwise, the iterator is a pointer into
2763 if ((gsize
)(*iter
) & 1)
2765 /* Use the static metadata only if klass->methods is not yet initialized */
2766 if (!static_iter
&& !(klass
->methods
|| !MONO_CLASS_HAS_STATIC_METADATA (klass
)))
2770 MonoMethod
** methodptr
;
2773 mono_class_setup_methods (klass
);
2775 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
2776 * FIXME we should better report this error to the caller
2778 if (!klass
->methods
)
2780 /* start from the first */
2781 methodptr
= &klass
->methods
[0];
2783 methodptr
= (MonoMethod
**)*iter
;
2787 g_assert ((guint64
)(*iter
) > 0x100);
2788 int mcount
= mono_class_get_method_count (klass
);
2789 while (methodptr
< &klass
->methods
[mcount
]) {
2790 if (*methodptr
&& ((*methodptr
)->flags
& METHOD_ATTRIBUTE_VIRTUAL
))
2794 if (methodptr
< &klass
->methods
[mcount
]) {
2801 /* Search directly in metadata to avoid calling setup_methods () */
2802 MonoMethod
*res
= NULL
;
2808 start_index
= GPOINTER_TO_UINT (*iter
) >> 1;
2811 int first_idx
= mono_class_get_first_method_idx (klass
);
2812 int mcount
= mono_class_get_method_count (klass
);
2813 for (i
= start_index
; i
< mcount
; ++i
) {
2816 /* first_idx points into the methodptr table */
2817 flags
= mono_metadata_decode_table_row_col (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
, MONO_METHOD_FLAGS
);
2819 if (flags
& METHOD_ATTRIBUTE_VIRTUAL
)
2825 res
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| (first_idx
+ i
+ 1), klass
, NULL
, error
);
2826 mono_error_cleanup (error
); /* FIXME don't swallow the error */
2828 /* Add 1 here so the if (*iter) check fails */
2829 *iter
= GUINT_TO_POINTER (((i
+ 1) << 1) | 1);
2838 print_vtable_layout_result (MonoClass
*klass
, MonoMethod
**vtable
, int cur_slot
)
2842 print_implemented_interfaces (klass
);
2844 for (i
= 0; i
<= klass
->max_interface_id
; i
++)
2845 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass
, i
))
2848 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (m_class_get_byval_arg (klass
)),
2849 klass
->vtable_size
, icount
);
2851 for (i
= 0; i
< cur_slot
; ++i
) {
2856 printf (" slot assigned: %03d, slot index: %03d %s\n", i
, cm
->slot
,
2857 mono_method_full_name (cm
, TRUE
));
2859 printf (" slot assigned: %03d, <null>\n", i
);
2865 printf ("Interfaces %s.%s (max_iid = %d)\n", klass
->name_space
,
2866 klass
->name
, klass
->max_interface_id
);
2868 for (i
= 0; i
< klass
->interface_count
; i
++) {
2869 MonoClass
*ic
= klass
->interfaces
[i
];
2870 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
2871 mono_class_interface_offset (klass
, ic
),
2872 count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
2875 for (MonoClass
*k
= klass
->parent
; k
; k
= k
->parent
) {
2876 for (i
= 0; i
< k
->interface_count
; i
++) {
2877 MonoClass
*ic
= k
->interfaces
[i
];
2878 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
2879 mono_class_interface_offset (klass
, ic
),
2880 count_virtual_methods (ic
), ic
->interface_id
, mono_type_full_name (m_class_get_byval_arg (ic
)));
2887 * LOCKING: this is supposed to be called with the loader lock held.
2890 mono_class_setup_vtable_general (MonoClass
*klass
, MonoMethod
**overrides
, int onum
, GList
*in_setup
)
2894 MonoMethod
**vtable
= NULL
;
2895 int i
, max_vtsize
= 0, cur_slot
= 0;
2896 GPtrArray
*ifaces
= NULL
;
2897 GHashTable
*override_map
= NULL
;
2898 GHashTable
*override_class_map
= NULL
;
2899 GHashTable
*conflict_map
= NULL
;
2901 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
2902 int first_non_interface_slot
;
2904 GSList
*virt_methods
= NULL
, *l
;
2905 int stelemref_slot
= 0;
2912 if (overrides
&& !verify_class_overrides (klass
, overrides
, onum
))
2915 ifaces
= mono_class_get_implemented_interfaces (klass
, error
);
2916 if (!mono_error_ok (error
)) {
2917 char *name
= mono_type_get_full_name (klass
);
2918 mono_class_set_type_load_failure (klass
, "Could not resolve %s interfaces due to %s", name
, mono_error_get_message (error
));
2920 mono_error_cleanup (error
);
2922 } else if (ifaces
) {
2923 for (i
= 0; i
< ifaces
->len
; i
++) {
2924 MonoClass
*ic
= (MonoClass
*)g_ptr_array_index (ifaces
, i
);
2925 max_vtsize
+= mono_class_get_method_count (ic
);
2927 g_ptr_array_free (ifaces
, TRUE
);
2931 if (klass
->parent
) {
2932 mono_class_init_internal (klass
->parent
);
2933 mono_class_setup_vtable_full (klass
->parent
, in_setup
);
2935 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Parent class failed to load"))
2938 max_vtsize
+= klass
->parent
->vtable_size
;
2939 cur_slot
= klass
->parent
->vtable_size
;
2942 max_vtsize
+= mono_class_get_method_count (klass
);
2944 /*Array have a slot for stelemref*/
2945 if (mono_class_need_stelemref_method (klass
)) {
2946 stelemref_slot
= cur_slot
;
2951 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
2953 cur_slot
= setup_interface_offsets (klass
, cur_slot
, TRUE
);
2954 if (cur_slot
== -1) /*setup_interface_offsets fails the type.*/
2957 DEBUG_INTERFACE_VTABLE (first_non_interface_slot
= cur_slot
);
2959 /* Optimized version for generic instances */
2960 if (mono_class_is_ginst (klass
)) {
2962 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
2965 mono_class_setup_vtable_full (gklass
, in_setup
);
2966 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Could not load generic definition"))
2969 tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * gklass
->vtable_size
);
2970 klass
->vtable_size
= gklass
->vtable_size
;
2971 for (i
= 0; i
< gklass
->vtable_size
; ++i
)
2972 if (gklass
->vtable
[i
]) {
2973 MonoMethod
*inflated
= mono_class_inflate_generic_method_full_checked (gklass
->vtable
[i
], klass
, mono_class_get_context (klass
), error
);
2974 goto_if_nok (error
, fail
);
2976 tmp
[i
]->slot
= gklass
->vtable
[i
]->slot
;
2978 mono_memory_barrier ();
2979 klass
->vtable
= tmp
;
2981 mono_loader_lock ();
2982 klass
->has_dim_conflicts
= gklass
->has_dim_conflicts
;
2983 mono_loader_unlock ();
2985 /* Have to set method->slot for abstract virtual methods */
2986 if (klass
->methods
&& gklass
->methods
) {
2987 int mcount
= mono_class_get_method_count (klass
);
2988 for (i
= 0; i
< mcount
; ++i
)
2989 if (klass
->methods
[i
]->slot
== -1)
2990 klass
->methods
[i
]->slot
= gklass
->methods
[i
]->slot
;
2993 if (mono_print_vtable
)
2994 print_vtable_layout_result (klass
, klass
->vtable
, gklass
->vtable_size
);
2999 vtable
= (MonoMethod
**)g_malloc0 (sizeof (gpointer
) * max_vtsize
);
3001 if (klass
->parent
&& klass
->parent
->vtable_size
) {
3002 MonoClass
*parent
= klass
->parent
;
3005 memcpy (vtable
, parent
->vtable
, sizeof (gpointer
) * parent
->vtable_size
);
3007 // Also inherit parent interface vtables, just as a starting point.
3008 // This is needed otherwise bug-77127.exe fails when the property methods
3009 // have different names in the iterface and the class, because for child
3010 // classes the ".override" information is not used anymore.
3011 for (i
= 0; i
< parent
->interface_offsets_count
; i
++) {
3012 MonoClass
*parent_interface
= parent
->interfaces_packed
[i
];
3013 int interface_offset
= mono_class_interface_offset (klass
, parent_interface
);
3014 /*FIXME this is now dead code as this condition will never hold true.
3015 Since interface offsets are inherited then the offset of an interface implemented
3016 by a parent will never be the out of it's vtable boundary.
3018 if (interface_offset
>= parent
->vtable_size
) {
3019 int parent_interface_offset
= mono_class_interface_offset (parent
, parent_interface
);
3022 mono_class_setup_methods (parent_interface
); /*FIXME Just kill this whole chunk of dead code*/
3023 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface
->name_space
, parent_interface
->name
));
3024 int mcount
= mono_class_get_method_count (parent_interface
);
3025 for (j
= 0; j
< mcount
&& !mono_class_has_failure (klass
); j
++) {
3026 vtable
[interface_offset
+ j
] = parent
->vtable
[parent_interface_offset
+ j
];
3027 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
3028 parent_interface_offset
+ j
, parent_interface_offset
, j
,
3029 interface_offset
+ j
, interface_offset
, j
));
3036 /*Array have a slot for stelemref*/
3037 if (mono_class_need_stelemref_method (klass
)) {
3038 MonoMethod
*method
= mono_marshal_get_virtual_stelemref (klass
);
3040 method
->slot
= stelemref_slot
;
3042 g_assert (method
->slot
== stelemref_slot
);
3044 vtable
[stelemref_slot
] = method
;
3047 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER INHERITING PARENT VTABLE", TRUE
));
3049 /* Process overrides from interface default methods */
3050 // FIXME: Ordering between interfaces
3051 for (int ifindex
= 0; ifindex
< klass
->interface_offsets_count
; ifindex
++) {
3052 ic
= klass
->interfaces_packed
[ifindex
];
3054 mono_class_setup_methods (ic
);
3055 if (mono_class_has_failure (ic
))
3058 MonoMethod
**iface_overrides
;
3060 mono_class_get_overrides_full (ic
->image
, ic
->type_token
, &iface_overrides
, &iface_onum
, mono_class_get_context (ic
), error
);
3061 goto_if_nok (error
, fail
);
3062 for (int i
= 0; i
< iface_onum
; i
++) {
3063 MonoMethod
*decl
= iface_overrides
[i
*2];
3064 MonoMethod
*override
= iface_overrides
[i
*2 + 1];
3065 if (!apply_override (klass
, ic
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
3068 g_free (iface_overrides
);
3071 /* override interface methods */
3072 for (i
= 0; i
< onum
; i
++) {
3073 MonoMethod
*decl
= overrides
[i
*2];
3074 MonoMethod
*override
= overrides
[i
*2 + 1];
3075 if (MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
3076 if (!apply_override (klass
, klass
, vtable
, decl
, override
, &override_map
, &override_class_map
, &conflict_map
))
3081 TRACE_INTERFACE_VTABLE (print_overrides (override_map
, "AFTER OVERRIDING INTERFACE METHODS"));
3082 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER OVERRIDING INTERFACE METHODS", FALSE
));
3085 * Create a list of virtual methods to avoid calling
3086 * mono_class_get_virtual_methods () which is slow because of the metadata
3090 gpointer iter
= NULL
;
3093 virt_methods
= NULL
;
3094 while ((cm
= mono_class_get_virtual_methods (klass
, &iter
))) {
3095 virt_methods
= g_slist_prepend (virt_methods
, cm
);
3097 if (mono_class_has_failure (klass
))
3101 // Loop on all implemented interfaces...
3102 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
3103 MonoClass
*parent
= klass
->parent
;
3105 gboolean interface_is_explicitly_implemented_by_class
;
3108 ic
= klass
->interfaces_packed
[i
];
3109 ic_offset
= mono_class_interface_offset (klass
, ic
);
3111 mono_class_setup_methods (ic
);
3112 if (mono_class_has_failure (ic
))
3115 // Check if this interface is explicitly implemented (instead of just inherited)
3116 if (parent
!= NULL
) {
3117 int implemented_interfaces_index
;
3118 interface_is_explicitly_implemented_by_class
= FALSE
;
3119 for (implemented_interfaces_index
= 0; implemented_interfaces_index
< klass
->interface_count
; implemented_interfaces_index
++) {
3120 if (ic
== klass
->interfaces
[implemented_interfaces_index
]) {
3121 interface_is_explicitly_implemented_by_class
= TRUE
;
3126 interface_is_explicitly_implemented_by_class
= TRUE
;
3129 // Loop on all interface methods...
3130 int mcount
= mono_class_get_method_count (ic
);
3131 for (im_index
= 0; im_index
< mcount
; im_index
++) {
3132 MonoMethod
*im
= ic
->methods
[im_index
];
3133 int im_slot
= ic_offset
+ im
->slot
;
3134 MonoMethod
*override_im
= (override_map
!= NULL
) ? (MonoMethod
*)g_hash_table_lookup (override_map
, im
) : NULL
;
3136 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
3139 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im
,1)));
3141 // If there is an explicit implementation, just use it right away,
3142 // otherwise look for a matching method
3143 if (override_im
== NULL
) {
3147 // First look for a suitable method among the class methods
3148 for (l
= virt_methods
; l
; l
= l
->next
) {
3149 cm
= (MonoMethod
*)l
->data
;
3150 TRACE_INTERFACE_VTABLE (printf (" For slot %d ('%s'.'%s':'%s'), trying method '%s'.'%s':'%s'... [EXPLICIT IMPLEMENTATION = %d][SLOT IS NULL = %d]", im_slot
, ic
->name_space
, ic
->name
, im
->name
, cm
->klass
->name_space
, cm
->klass
->name
, cm
->name
, interface_is_explicitly_implemented_by_class
, (vtable
[im_slot
] == NULL
)));
3151 if (check_interface_method_override (klass
, im
, cm
, TRUE
, interface_is_explicitly_implemented_by_class
, (vtable
[im_slot
] == NULL
))) {
3152 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
3153 vtable
[im_slot
] = cm
;
3154 /* Why do we need this? */
3159 TRACE_INTERFACE_VTABLE (printf ("\n"));
3160 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
3164 // If the slot is still empty, look in all the inherited virtual methods...
3165 if ((vtable
[im_slot
] == NULL
) && klass
->parent
!= NULL
) {
3166 MonoClass
*parent
= klass
->parent
;
3167 // Reverse order, so that last added methods are preferred
3168 for (cm_index
= parent
->vtable_size
- 1; cm_index
>= 0; cm_index
--) {
3169 MonoMethod
*cm
= parent
->vtable
[cm_index
];
3171 TRACE_INTERFACE_VTABLE ((cm
!= NULL
) && printf (" For slot %d ('%s'.'%s':'%s'), trying (ancestor) method '%s'.'%s':'%s'... ", im_slot
, ic
->name_space
, ic
->name
, im
->name
, cm
->klass
->name_space
, cm
->klass
->name
, cm
->name
));
3172 if ((cm
!= NULL
) && check_interface_method_override (klass
, im
, cm
, FALSE
, FALSE
, TRUE
)) {
3173 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
3174 vtable
[im_slot
] = cm
;
3175 /* Why do we need this? */
3181 if (mono_class_has_failure (klass
)) /*Might be set by check_interface_method_override*/
3183 TRACE_INTERFACE_VTABLE ((cm
!= NULL
) && printf ("\n"));
3187 if (vtable
[im_slot
] == NULL
) {
3188 if (!(im
->flags
& METHOD_ATTRIBUTE_ABSTRACT
)) {
3189 TRACE_INTERFACE_VTABLE (printf (" Using default iface method %s.\n", mono_method_full_name (im
, 1)));
3190 vtable
[im_slot
] = im
;
3194 g_assert (vtable
[im_slot
] == override_im
);
3199 // If the class is not abstract, check that all its interface slots are full.
3200 // The check is done here and not directly at the end of the loop above because
3201 // it can happen (for injected generic array interfaces) that the same slot is
3202 // processed multiple times (those interfaces have overlapping slots), and it
3203 // will not always be the first pass the one that fills the slot.
3204 if (!mono_class_is_abstract (klass
)) {
3205 for (i
= 0; i
< klass
->interface_offsets_count
; i
++) {
3209 ic
= klass
->interfaces_packed
[i
];
3210 ic_offset
= mono_class_interface_offset (klass
, ic
);
3212 int mcount
= mono_class_get_method_count (ic
);
3213 for (im_index
= 0; im_index
< mcount
; im_index
++) {
3214 MonoMethod
*im
= ic
->methods
[im_index
];
3215 int im_slot
= ic_offset
+ im
->slot
;
3217 if (im
->flags
& METHOD_ATTRIBUTE_STATIC
)
3220 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
3221 im_slot
, ic
->name_space
, ic
->name
, im
->name
, (vtable
[im_slot
] == NULL
)));
3222 if (vtable
[im_slot
] == NULL
) {
3223 print_unimplemented_interface_method_info (klass
, ic
, im
, im_slot
, overrides
, onum
);
3230 TRACE_INTERFACE_VTABLE (print_vtable_full (klass
, vtable
, cur_slot
, first_non_interface_slot
, "AFTER SETTING UP INTERFACE METHODS", FALSE
));
3231 for (l
= virt_methods
; l
; l
= l
->next
) {
3232 cm
= (MonoMethod
*)l
->data
;
3234 * If the method is REUSE_SLOT, we must check in the
3235 * base class for a method to override.
3237 if (!(cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
)) {
3239 for (k
= klass
->parent
; k
; k
= k
->parent
) {
3244 while ((m1
= mono_class_get_virtual_methods (k
, &k_iter
))) {
3245 MonoMethodSignature
*cmsig
, *m1sig
;
3247 cmsig
= mono_method_signature_internal (cm
);
3248 m1sig
= mono_method_signature_internal (m1
);
3250 if (!cmsig
|| !m1sig
) /* FIXME proper error message, use signature_checked? */
3253 if (!strcmp(cm
->name
, m1
->name
) &&
3254 mono_metadata_signature_equal (cmsig
, m1sig
)) {
3256 if (mono_security_core_clr_enabled ())
3257 mono_security_core_clr_check_override (klass
, cm
, m1
);
3259 slot
= mono_method_get_vtable_slot (m1
);
3263 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm
, m1
, NULL
)) {
3264 char *body_name
= mono_method_full_name (cm
, TRUE
);
3265 char *decl_name
= mono_method_full_name (m1
, TRUE
);
3266 mono_class_set_type_load_failure (klass
, "Method %s overrides method '%s' which is not accessible", body_name
, decl_name
);
3272 g_assert (cm
->slot
< max_vtsize
);
3274 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3275 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
3276 mono_method_full_name (m1
, 1), m1
,
3277 mono_method_full_name (cm
, 1), cm
));
3278 g_hash_table_insert (override_map
, m1
, cm
);
3282 if (mono_class_has_failure (k
))
3292 /*Non final newslot methods must be given a non-interface vtable slot*/
3293 if ((cm
->flags
& METHOD_ATTRIBUTE_NEW_SLOT
) && !(cm
->flags
& METHOD_ATTRIBUTE_FINAL
) && cm
->slot
>= 0)
3297 cm
->slot
= cur_slot
++;
3299 if (!(cm
->flags
& METHOD_ATTRIBUTE_ABSTRACT
))
3300 vtable
[cm
->slot
] = cm
;
3303 /* override non interface methods */
3304 for (i
= 0; i
< onum
; i
++) {
3305 MonoMethod
*decl
= overrides
[i
*2];
3306 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (decl
->klass
)) {
3307 g_assert (decl
->slot
!= -1);
3308 vtable
[decl
->slot
] = overrides
[i
*2 + 1];
3309 overrides
[i
* 2 + 1]->slot
= decl
->slot
;
3311 override_map
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
3312 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
3313 mono_method_full_name (decl
, 1), decl
,
3314 mono_method_full_name (overrides
[i
* 2 + 1], 1), overrides
[i
* 2 + 1]));
3315 g_hash_table_insert (override_map
, decl
, overrides
[i
* 2 + 1]);
3317 if (mono_security_core_clr_enabled ())
3318 mono_security_core_clr_check_override (klass
, vtable
[decl
->slot
], decl
);
3323 * If a method occupies more than one place in the vtable, and it is
3324 * overriden, then change the other occurances too.
3329 for (i
= 0; i
< max_vtsize
; ++i
)
3331 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i
, mono_method_full_name (vtable
[i
], 1), vtable
[i
]));
3333 cm
= (MonoMethod
*)g_hash_table_lookup (override_map
, vtable
[i
]);
3338 g_hash_table_destroy (override_map
);
3339 override_map
= NULL
;
3342 if (override_class_map
)
3343 g_hash_table_destroy (override_class_map
);
3346 handle_dim_conflicts (vtable
, klass
, conflict_map
);
3347 g_hash_table_destroy (conflict_map
);
3350 g_slist_free (virt_methods
);
3351 virt_methods
= NULL
;
3353 g_assert (cur_slot
<= max_vtsize
);
3355 /* Ensure that all vtable slots are filled with concrete instance methods */
3356 if (!mono_class_is_abstract (klass
)) {
3357 for (i
= 0; i
< cur_slot
; ++i
) {
3358 if (vtable
[i
] == NULL
|| (vtable
[i
]->flags
& (METHOD_ATTRIBUTE_ABSTRACT
| METHOD_ATTRIBUTE_STATIC
))) {
3359 char *type_name
= mono_type_get_full_name (klass
);
3360 char *method_name
= vtable
[i
] ? mono_method_full_name (vtable
[i
], TRUE
) : g_strdup ("none");
3361 mono_class_set_type_load_failure (klass
, "Type %s has invalid vtable method slot %d with method %s", type_name
, i
, method_name
);
3363 g_free (method_name
);
3365 if (mono_print_vtable
)
3366 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3374 if (mono_class_is_ginst (klass
)) {
3375 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
3377 mono_class_init_internal (gklass
);
3379 klass
->vtable_size
= MAX (gklass
->vtable_size
, cur_slot
);
3381 /* Check that the vtable_size value computed in mono_class_init_internal () is correct */
3382 if (klass
->vtable_size
)
3383 g_assert (cur_slot
== klass
->vtable_size
);
3384 klass
->vtable_size
= cur_slot
;
3387 /* Try to share the vtable with our parent. */
3388 if (klass
->parent
&& (klass
->parent
->vtable_size
== klass
->vtable_size
) && (memcmp (klass
->parent
->vtable
, vtable
, sizeof (gpointer
) * klass
->vtable_size
) == 0)) {
3389 mono_memory_barrier ();
3390 klass
->vtable
= klass
->parent
->vtable
;
3392 MonoMethod
**tmp
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (gpointer
) * klass
->vtable_size
);
3393 memcpy (tmp
, vtable
, sizeof (gpointer
) * klass
->vtable_size
);
3394 mono_memory_barrier ();
3395 klass
->vtable
= tmp
;
3398 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass
, klass
->vtable
, klass
->vtable_size
, first_non_interface_slot
, "FINALLY", FALSE
));
3399 if (mono_print_vtable
)
3400 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3404 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass
));
3409 char *name
= mono_type_get_full_name (klass
);
3411 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed due to: %s", name
, mono_error_get_message (error
));
3413 mono_class_set_type_load_failure (klass
, "VTable setup of type %s failed", name
);
3414 mono_error_cleanup (error
);
3416 if (mono_print_vtable
)
3417 print_vtable_layout_result (klass
, vtable
, cur_slot
);
3422 g_hash_table_destroy (override_map
);
3424 g_slist_free (virt_methods
);
3429 concat_two_strings_with_zero (MonoImage
*image
, const char *s1
, const char *s2
)
3431 int null_length
= strlen ("(null)");
3432 int len
= (s1
? strlen (s1
) : null_length
) + (s2
? strlen (s2
) : null_length
) + 2;
3433 char *s
= (char *)mono_image_alloc (image
, len
);
3436 result
= g_snprintf (s
, len
, "%s%c%s", s1
? s1
: "(null)", '\0', s2
? s2
: "(null)");
3437 g_assert (result
== len
- 1);
3444 init_sizes_with_info (MonoClass
*klass
, MonoCachedClassInfo
*cached_info
)
3447 mono_loader_lock ();
3448 klass
->instance_size
= cached_info
->instance_size
;
3449 klass
->sizes
.class_size
= cached_info
->class_size
;
3450 klass
->packing_size
= cached_info
->packing_size
;
3451 klass
->min_align
= cached_info
->min_align
;
3452 klass
->blittable
= cached_info
->blittable
;
3453 klass
->has_references
= cached_info
->has_references
;
3454 klass
->has_static_refs
= cached_info
->has_static_refs
;
3455 klass
->no_special_static_fields
= cached_info
->no_special_static_fields
;
3456 klass
->has_weak_fields
= cached_info
->has_weak_fields
;
3457 mono_loader_unlock ();
3460 if (!klass
->size_inited
)
3461 mono_class_setup_fields (klass
);
3466 * mono_class_init_sizes:
3468 * Initializes the size related fields of @klass without loading all field data if possible.
3469 * Sets the following fields in @klass:
3471 * - sizes.class_size
3478 * Can fail the class.
3480 * LOCKING: Acquires the loader lock.
3483 mono_class_init_sizes (MonoClass
*klass
)
3485 MonoCachedClassInfo cached_info
;
3486 gboolean has_cached_info
;
3488 if (klass
->size_inited
)
3491 has_cached_info
= mono_class_get_cached_class_info (klass
, &cached_info
);
3493 init_sizes_with_info (klass
, has_cached_info
? &cached_info
: NULL
);
3498 class_has_references (MonoClass
*klass
)
3500 mono_class_init_sizes (klass
);
3503 * has_references is not set if this is called recursively, but this is not a problem since this is only used
3504 * during field layout, and instance fields are initialized before static fields, and instance fields can't
3507 return klass
->has_references
;
3511 type_has_references (MonoClass
*klass
, MonoType
*ftype
)
3513 if (MONO_TYPE_IS_REFERENCE (ftype
) || IS_GC_REFERENCE (klass
, ftype
) || ((MONO_TYPE_ISSTRUCT (ftype
) && class_has_references (mono_class_from_mono_type_internal (ftype
)))))
3515 if (!ftype
->byref
&& (ftype
->type
== MONO_TYPE_VAR
|| ftype
->type
== MONO_TYPE_MVAR
)) {
3516 MonoGenericParam
*gparam
= ftype
->data
.generic_param
;
3518 if (gparam
->gshared_constraint
)
3519 return class_has_references (mono_class_from_mono_type_internal (gparam
->gshared_constraint
));
3525 * mono_class_layout_fields:
3527 * @base_instance_size: base instance size
3530 * This contains the common code for computing the layout of classes and sizes.
3531 * This should only be called from mono_class_setup_fields () and
3532 * typebuilder_setup_fields ().
3534 * LOCKING: Acquires the loader lock
3537 mono_class_layout_fields (MonoClass
*klass
, int base_instance_size
, int packing_size
, int explicit_size
, gboolean sre
)
3540 const int top
= mono_class_get_field_count (klass
);
3541 guint32 layout
= mono_class_get_flags (klass
) & TYPE_ATTRIBUTE_LAYOUT_MASK
;
3542 guint32 pass
, passes
, real_size
;
3543 gboolean gc_aware_layout
= FALSE
;
3544 gboolean has_static_fields
= FALSE
;
3545 gboolean has_references
= FALSE
;
3546 gboolean has_static_refs
= FALSE
;
3547 MonoClassField
*field
;
3549 int instance_size
= base_instance_size
;
3550 int element_size
= -1;
3551 int class_size
, min_align
;
3553 gboolean
*fields_has_references
;
3556 * We want to avoid doing complicated work inside locks, so we compute all the required
3557 * information and write it to @klass inside a lock.
3559 if (klass
->fields_inited
)
3562 if ((packing_size
& 0xffffff00) != 0) {
3563 mono_class_set_type_load_failure (klass
, "Could not load struct '%s' with packing size %d >= 256", klass
->name
, packing_size
);
3567 if (klass
->parent
) {
3568 min_align
= klass
->parent
->min_align
;
3569 /* we use | since it may have been set already */
3570 has_references
= klass
->has_references
| klass
->parent
->has_references
;
3574 /* We can't really enable 16 bytes alignment until the GC supports it.
3575 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
3576 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
3577 Bug #506144 is an example of this issue.
3579 if (klass->simd_type)
3584 * When we do generic sharing we need to have layout
3585 * information for open generic classes (either with a generic
3586 * context containing type variables or with a generic
3587 * container), so we don't return in that case anymore.
3590 if (klass
->enumtype
) {
3591 for (i
= 0; i
< top
; i
++) {
3592 field
= &klass
->fields
[i
];
3593 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
3594 klass
->cast_class
= klass
->element_class
= mono_class_from_mono_type_internal (field
->type
);
3599 if (!mono_class_enum_basetype_internal (klass
)) {
3600 mono_class_set_type_load_failure (klass
, "The enumeration's base type is invalid.");
3606 * Enable GC aware auto layout: in this mode, reference
3607 * fields are grouped together inside objects, increasing collector
3609 * Requires that all classes whose layout is known to native code be annotated
3610 * with [StructLayout (LayoutKind.Sequential)]
3611 * Value types have gc_aware_layout disabled by default, as per
3612 * what the default is for other runtimes.
3614 /* corlib is missing [StructLayout] directives in many places */
3615 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
) {
3616 if (!klass
->valuetype
)
3617 gc_aware_layout
= TRUE
;
3620 /* Compute klass->blittable */
3623 blittable
= klass
->parent
->blittable
;
3624 if (layout
== TYPE_ATTRIBUTE_AUTO_LAYOUT
&& !(mono_is_corlib_image (klass
->image
) && !strcmp (klass
->name_space
, "System") && !strcmp (klass
->name
, "ValueType")) && top
)
3626 for (i
= 0; i
< top
; i
++) {
3627 field
= &klass
->fields
[i
];
3629 if (mono_field_is_deleted (field
))
3631 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3634 if (field
->type
->byref
|| MONO_TYPE_IS_REFERENCE (field
->type
)) {
3637 MonoClass
*field_class
= mono_class_from_mono_type_internal (field
->type
);
3639 mono_class_setup_fields (field_class
);
3640 if (mono_class_has_failure (field_class
)) {
3641 ERROR_DECL (field_error
);
3642 mono_error_set_for_class_failure (field_error
, field_class
);
3643 mono_class_set_type_load_failure (klass
, "Could not set up field '%s' due to: %s", field
->name
, mono_error_get_message (field_error
));
3644 mono_error_cleanup (field_error
);
3648 if (!field_class
|| !field_class
->blittable
)
3652 if (klass
->enumtype
)
3653 blittable
= klass
->element_class
->blittable
;
3655 if (mono_class_has_failure (klass
))
3657 if (klass
== mono_defaults
.string_class
)
3660 /* Compute klass->has_references */
3662 * Process non-static fields first, since static fields might recursively
3663 * refer to the class itself.
3665 for (i
= 0; i
< top
; i
++) {
3668 field
= &klass
->fields
[i
];
3670 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
3671 ftype
= mono_type_get_underlying_type (field
->type
);
3672 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3673 if (type_has_references (klass
, ftype
))
3674 has_references
= TRUE
;
3679 * Compute field layout and total size (not considering static fields)
3681 field_offsets
= g_new0 (int, top
);
3682 fields_has_references
= g_new0 (gboolean
, top
);
3683 int first_field_idx
= mono_class_has_static_metadata (klass
) ? mono_class_get_first_field_idx (klass
) : 0;
3685 case TYPE_ATTRIBUTE_AUTO_LAYOUT
:
3686 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT
:
3687 if (gc_aware_layout
)
3692 if (layout
!= TYPE_ATTRIBUTE_AUTO_LAYOUT
)
3695 if (klass
->parent
) {
3696 mono_class_setup_fields (klass
->parent
);
3697 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Cannot initialize parent class"))
3699 real_size
= klass
->parent
->instance_size
;
3701 real_size
= MONO_ABI_SIZEOF (MonoObject
);
3704 for (pass
= 0; pass
< passes
; ++pass
) {
3705 for (i
= 0; i
< top
; i
++){
3710 field
= &klass
->fields
[i
];
3712 if (mono_field_is_deleted (field
))
3714 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3717 ftype
= mono_type_get_underlying_type (field
->type
);
3718 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3719 if (gc_aware_layout
) {
3720 fields_has_references
[i
] = type_has_references (klass
, ftype
);
3721 if (fields_has_references
[i
]) {
3730 if ((top
== 1) && (instance_size
== MONO_ABI_SIZEOF (MonoObject
)) &&
3731 (strcmp (mono_field_get_name (field
), "$PRIVATE$") == 0)) {
3732 /* This field is a hack inserted by MCS to empty structures */
3736 size
= mono_type_size (field
->type
, &align
);
3738 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
3739 align
= packing_size
? MIN (packing_size
, align
): align
;
3740 /* if the field has managed references, we need to force-align it
3743 if (type_has_references (klass
, ftype
))
3744 align
= MAX (align
, TARGET_SIZEOF_VOID_P
);
3746 min_align
= MAX (align
, min_align
);
3747 field_offsets
[i
] = real_size
;
3749 field_offsets
[i
] += align
- 1;
3750 field_offsets
[i
] &= ~(align
- 1);
3752 /*TypeBuilders produce all sort of weird things*/
3753 g_assert (image_is_dynamic (klass
->image
) || field_offsets
[i
] > 0);
3754 real_size
= field_offsets
[i
] + size
;
3757 instance_size
= MAX (real_size
, instance_size
);
3759 if (instance_size
& (min_align
- 1)) {
3760 instance_size
+= min_align
- 1;
3761 instance_size
&= ~(min_align
- 1);
3765 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
: {
3769 for (i
= 0; i
< top
; i
++) {
3774 field
= &klass
->fields
[i
];
3777 * There must be info about all the fields in a type if it
3778 * uses explicit layout.
3780 if (mono_field_is_deleted (field
))
3782 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3785 size
= mono_type_size (field
->type
, &align
);
3786 align
= packing_size
? MIN (packing_size
, align
): align
;
3787 min_align
= MAX (align
, min_align
);
3790 /* Already set by typebuilder_setup_fields () */
3791 field_offsets
[i
] = field
->offset
+ MONO_ABI_SIZEOF (MonoObject
);
3793 int idx
= first_field_idx
+ i
;
3795 mono_metadata_field_info (klass
->image
, idx
, &offset
, NULL
, NULL
);
3796 field_offsets
[i
] = offset
+ MONO_ABI_SIZEOF (MonoObject
);
3798 ftype
= mono_type_get_underlying_type (field
->type
);
3799 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3800 if (type_has_references (klass
, ftype
)) {
3801 if (field_offsets
[i
] % TARGET_SIZEOF_VOID_P
) {
3802 mono_class_set_type_load_failure (klass
, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field
->name
);
3809 real_size
= MAX (real_size
, size
+ field_offsets
[i
]);
3812 if (klass
->has_references
) {
3813 ref_bitmap
= g_new0 (guint8
, real_size
/ TARGET_SIZEOF_VOID_P
);
3815 /* Check for overlapping reference and non-reference fields */
3816 for (i
= 0; i
< top
; i
++) {
3819 field
= &klass
->fields
[i
];
3821 if (mono_field_is_deleted (field
))
3823 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3825 ftype
= mono_type_get_underlying_type (field
->type
);
3826 if (MONO_TYPE_IS_REFERENCE (ftype
))
3827 ref_bitmap
[field_offsets
[i
] / TARGET_SIZEOF_VOID_P
] = 1;
3829 for (i
= 0; i
< top
; i
++) {
3830 field
= &klass
->fields
[i
];
3832 if (mono_field_is_deleted (field
))
3834 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
3837 // FIXME: Too much code does this
3839 if (!MONO_TYPE_IS_REFERENCE (field
->type
) && ref_bitmap
[field_offsets
[i
] / TARGET_SIZEOF_VOID_P
]) {
3840 mono_class_set_type_load_failure (klass
, "Could not load type '%s' because it contains an object field at offset %d that is incorrectly aligned or overlapped by a non-object field.", klass
->name
, field_offsets
[i
]);
3844 g_free (ref_bitmap
);
3847 instance_size
= MAX (real_size
, instance_size
);
3848 if (!((layout
== TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) && explicit_size
)) {
3849 if (instance_size
& (min_align
- 1)) {
3850 instance_size
+= min_align
- 1;
3851 instance_size
&= ~(min_align
- 1);
3858 if (layout
!= TYPE_ATTRIBUTE_EXPLICIT_LAYOUT
) {
3860 * This leads to all kinds of problems with nested structs, so only
3861 * enable it when a MONO_DEBUG property is set.
3863 * For small structs, set min_align to at least the struct size to improve
3864 * performance, and since the JIT memset/memcpy code assumes this and generates
3865 * unaligned accesses otherwise. See #78990 for a testcase.
3867 if (mono_align_small_structs
&& top
) {
3868 if (instance_size
<= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
))
3869 min_align
= MAX (min_align
, instance_size
- MONO_ABI_SIZEOF (MonoObject
));
3873 MonoType
*klass_byval_arg
= m_class_get_byval_arg (klass
);
3874 if (klass_byval_arg
->type
== MONO_TYPE_VAR
|| klass_byval_arg
->type
== MONO_TYPE_MVAR
)
3875 instance_size
= MONO_ABI_SIZEOF (MonoObject
) + mono_type_stack_size_internal (klass_byval_arg
, NULL
, TRUE
);
3876 else if (klass_byval_arg
->type
== MONO_TYPE_PTR
)
3877 instance_size
= MONO_ABI_SIZEOF (MonoObject
) + MONO_ABI_SIZEOF (gpointer
);
3879 if (klass_byval_arg
->type
== MONO_TYPE_SZARRAY
|| klass_byval_arg
->type
== MONO_TYPE_ARRAY
)
3880 element_size
= mono_class_array_element_size (klass
->element_class
);
3882 /* Publish the data */
3883 mono_loader_lock ();
3884 if (klass
->instance_size
&& !klass
->image
->dynamic
) {
3885 /* Might be already set using cached info */
3886 if (klass
->instance_size
!= instance_size
) {
3887 /* Emit info to help debugging */
3888 g_print ("%s\n", mono_class_full_name (klass
));
3889 g_print ("%d %d %d %d\n", klass
->instance_size
, instance_size
, klass
->blittable
, blittable
);
3890 g_print ("%d %d %d %d\n", klass
->has_references
, has_references
, klass
->packing_size
, packing_size
);
3891 g_print ("%d %d\n", klass
->min_align
, min_align
);
3892 for (i
= 0; i
< top
; ++i
) {
3893 field
= &klass
->fields
[i
];
3894 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3895 printf (" %s %d %d %d\n", klass
->fields
[i
].name
, klass
->fields
[i
].offset
, field_offsets
[i
], fields_has_references
[i
]);
3898 g_assert (klass
->instance_size
== instance_size
);
3900 klass
->instance_size
= instance_size
;
3902 klass
->blittable
= blittable
;
3903 klass
->has_references
= has_references
;
3904 klass
->packing_size
= packing_size
;
3905 klass
->min_align
= min_align
;
3906 for (i
= 0; i
< top
; ++i
) {
3907 field
= &klass
->fields
[i
];
3908 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
3909 klass
->fields
[i
].offset
= field_offsets
[i
];
3912 if (klass_byval_arg
->type
== MONO_TYPE_SZARRAY
|| klass_byval_arg
->type
== MONO_TYPE_ARRAY
)
3913 klass
->sizes
.element_size
= element_size
;
3915 mono_memory_barrier ();
3916 klass
->size_inited
= 1;
3917 mono_loader_unlock ();
3920 * Compute static field layout and size
3921 * Static fields can reference the class itself, so this has to be
3922 * done after instance_size etc. are initialized.
3925 for (i
= 0; i
< top
; i
++) {
3929 field
= &klass
->fields
[i
];
3931 if (!(field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) || field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
)
3933 if (mono_field_is_deleted (field
))
3936 if (mono_type_has_exceptions (field
->type
)) {
3937 mono_class_set_type_load_failure (klass
, "Field '%s' has an invalid type.", field
->name
);
3941 has_static_fields
= TRUE
;
3943 size
= mono_type_size (field
->type
, &align
);
3944 field_offsets
[i
] = class_size
;
3945 /*align is always non-zero here*/
3946 field_offsets
[i
] += align
- 1;
3947 field_offsets
[i
] &= ~(align
- 1);
3948 class_size
= field_offsets
[i
] + size
;
3951 if (has_static_fields
&& class_size
== 0)
3952 /* Simplify code which depends on class_size != 0 if the class has static fields */
3955 /* Compute klass->has_static_refs */
3956 has_static_refs
= FALSE
;
3957 for (i
= 0; i
< top
; i
++) {
3960 field
= &klass
->fields
[i
];
3962 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
) {
3963 ftype
= mono_type_get_underlying_type (field
->type
);
3964 ftype
= mono_type_get_basic_type_from_generic (ftype
);
3965 if (type_has_references (klass
, ftype
))
3966 has_static_refs
= TRUE
;
3970 /*valuetypes can't be neither bigger than 1Mb or empty. */
3971 if (klass
->valuetype
&& (klass
->instance_size
<= 0 || klass
->instance_size
> (0x100000 + MONO_ABI_SIZEOF (MonoObject
)))) {
3972 /* Special case compiler generated types */
3973 /* Hard to check for [CompilerGenerated] here */
3974 if (!strstr (klass
->name
, "StaticArrayInitTypeSize") && !strstr (klass
->name
, "$ArrayType"))
3975 mono_class_set_type_load_failure (klass
, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass
->instance_size
);
3978 // Weak field support
3981 // - generic instances
3982 // - Disallow on structs/static fields/nonref fields
3983 gboolean has_weak_fields
= FALSE
;
3985 if (mono_class_has_static_metadata (klass
)) {
3986 for (MonoClass
*p
= klass
; p
!= NULL
; p
= p
->parent
) {
3987 gpointer iter
= NULL
;
3988 guint32 first_field_idx
= mono_class_get_first_field_idx (p
);
3990 while ((field
= mono_class_get_fields_internal (p
, &iter
))) {
3991 guint32 field_idx
= first_field_idx
+ (field
- p
->fields
);
3992 if (MONO_TYPE_IS_REFERENCE (field
->type
) && mono_assembly_is_weak_field (p
->image
, field_idx
+ 1)) {
3993 has_weak_fields
= TRUE
;
3994 mono_trace_message (MONO_TRACE_TYPE
, "Field %s:%s at offset %x is weak.", field
->parent
->name
, field
->name
, field
->offset
);
4001 * Check that any fields of IsByRefLike type are instance
4002 * fields and only inside other IsByRefLike structs.
4004 * (Has to be done late because we call
4005 * mono_class_from_mono_type_internal which may recursively
4006 * refer to the current class)
4008 gboolean allow_isbyreflike_fields
= m_class_is_byreflike (klass
);
4009 for (i
= 0; i
< top
; i
++) {
4010 field
= &klass
->fields
[i
];
4012 if (mono_field_is_deleted (field
))
4014 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_LITERAL
))
4016 MonoClass
*field_class
= NULL
;
4017 /* have to be careful not to recursively invoke mono_class_init on a static field.
4018 * for example - if the field is an array of a subclass of klass, we can loop.
4020 switch (field
->type
->type
) {
4021 case MONO_TYPE_TYPEDBYREF
:
4022 case MONO_TYPE_VALUETYPE
:
4023 case MONO_TYPE_GENERICINST
:
4024 field_class
= mono_class_from_mono_type_internal (field
->type
);
4029 if (!field_class
|| !m_class_is_byreflike (field_class
))
4031 if ((field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)) {
4032 mono_class_set_type_load_failure (klass
, "Static ByRefLike field '%s' is not allowed", field
->name
);
4035 /* instance field */
4036 if (allow_isbyreflike_fields
)
4038 mono_class_set_type_load_failure (klass
, "Instance ByRefLike field '%s' not in a ref struct", field
->name
);
4043 /* Publish the data */
4044 mono_loader_lock ();
4046 klass
->sizes
.class_size
= class_size
;
4047 klass
->has_static_refs
= has_static_refs
;
4048 klass
->has_weak_fields
= has_weak_fields
;
4049 for (i
= 0; i
< top
; ++i
) {
4050 field
= &klass
->fields
[i
];
4052 if (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
)
4053 field
->offset
= field_offsets
[i
];
4055 mono_memory_barrier ();
4056 klass
->fields_inited
= 1;
4057 mono_loader_unlock ();
4059 g_free (field_offsets
);
4060 g_free (fields_has_references
);
4063 static MonoMethod
*default_ghc
= NULL
;
4064 static MonoMethod
*default_finalize
= NULL
;
4065 static int finalize_slot
= -1;
4066 static int ghc_slot
= -1;
4069 initialize_object_slots (MonoClass
*klass
)
4074 if (klass
== mono_defaults
.object_class
) {
4075 mono_class_setup_vtable (klass
);
4076 for (i
= 0; i
< klass
->vtable_size
; ++i
) {
4077 MonoMethod
*cm
= klass
->vtable
[i
];
4079 if (!strcmp (cm
->name
, "GetHashCode"))
4081 else if (!strcmp (cm
->name
, "Finalize"))
4085 g_assert (ghc_slot
> 0);
4086 default_ghc
= klass
->vtable
[ghc_slot
];
4088 g_assert (finalize_slot
> 0);
4089 default_finalize
= klass
->vtable
[finalize_slot
];
4094 mono_class_get_object_finalize_slot ()
4096 return finalize_slot
;
4100 mono_class_get_default_finalize_method ()
4102 return default_finalize
;
4106 MonoMethod
*array_method
;
4108 } GenericArrayMethodInfo
;
4110 static int generic_array_method_num
= 0;
4111 static GenericArrayMethodInfo
*generic_array_method_info
= NULL
;
4114 setup_generic_array_ifaces (MonoClass
*klass
, MonoClass
*iface
, MonoMethod
**methods
, int pos
, GHashTable
*cache
)
4116 MonoGenericContext tmp_context
;
4119 tmp_context
.class_inst
= NULL
;
4120 tmp_context
.method_inst
= mono_class_get_generic_class (iface
)->context
.class_inst
;
4121 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (m_class_get_byval_arg (iface), 0));
4123 for (i
= 0; i
< generic_array_method_num
; i
++) {
4125 MonoMethod
*m
= generic_array_method_info
[i
].array_method
;
4126 MonoMethod
*inflated
, *helper
;
4128 inflated
= mono_class_inflate_generic_method_checked (m
, &tmp_context
, error
);
4129 mono_error_assert_ok (error
);
4130 helper
= (MonoMethod
*)g_hash_table_lookup (cache
, inflated
);
4132 helper
= mono_marshal_get_generic_array_helper (klass
, generic_array_method_info
[i
].name
, inflated
);
4133 g_hash_table_insert (cache
, inflated
, helper
);
4135 methods
[pos
++] = helper
;
4140 generic_array_methods (MonoClass
*klass
)
4142 int i
, count_generic
= 0, mcount
;
4143 GList
*list
= NULL
, *tmp
;
4144 if (generic_array_method_num
)
4145 return generic_array_method_num
;
4146 mono_class_setup_methods (klass
->parent
); /*This is setting up System.Array*/
4147 g_assert (!mono_class_has_failure (klass
->parent
)); /*So hitting this assert is a huge problem*/
4148 mcount
= mono_class_get_method_count (klass
->parent
);
4149 for (i
= 0; i
< mcount
; i
++) {
4150 MonoMethod
*m
= klass
->parent
->methods
[i
];
4151 if (!strncmp (m
->name
, "InternalArray__", 15)) {
4153 list
= g_list_prepend (list
, m
);
4156 list
= g_list_reverse (list
);
4157 generic_array_method_info
= (GenericArrayMethodInfo
*)mono_image_alloc (mono_defaults
.corlib
, sizeof (GenericArrayMethodInfo
) * count_generic
);
4159 for (tmp
= list
; tmp
; tmp
= tmp
->next
) {
4160 const char *mname
, *iname
;
4162 MonoMethod
*m
= (MonoMethod
*)tmp
->data
;
4163 const char *ireadonlylist_prefix
= "InternalArray__IReadOnlyList_";
4164 const char *ireadonlycollection_prefix
= "InternalArray__IReadOnlyCollection_";
4166 generic_array_method_info
[i
].array_method
= m
;
4167 if (!strncmp (m
->name
, "InternalArray__ICollection_", 27)) {
4168 iname
= "System.Collections.Generic.ICollection`1.";
4169 mname
= m
->name
+ 27;
4170 } else if (!strncmp (m
->name
, "InternalArray__IEnumerable_", 27)) {
4171 iname
= "System.Collections.Generic.IEnumerable`1.";
4172 mname
= m
->name
+ 27;
4173 } else if (!strncmp (m
->name
, ireadonlylist_prefix
, strlen (ireadonlylist_prefix
))) {
4174 iname
= "System.Collections.Generic.IReadOnlyList`1.";
4175 mname
= m
->name
+ strlen (ireadonlylist_prefix
);
4176 } else if (!strncmp (m
->name
, ireadonlycollection_prefix
, strlen (ireadonlycollection_prefix
))) {
4177 iname
= "System.Collections.Generic.IReadOnlyCollection`1.";
4178 mname
= m
->name
+ strlen (ireadonlycollection_prefix
);
4179 } else if (!strncmp (m
->name
, "InternalArray__", 15)) {
4180 iname
= "System.Collections.Generic.IList`1.";
4181 mname
= m
->name
+ 15;
4183 g_assert_not_reached ();
4186 name
= (gchar
*)mono_image_alloc (mono_defaults
.corlib
, strlen (iname
) + strlen (mname
) + 1);
4187 strcpy (name
, iname
);
4188 strcpy (name
+ strlen (iname
), mname
);
4189 generic_array_method_info
[i
].name
= name
;
4192 /*g_print ("array generic methods: %d\n", count_generic);*/
4194 generic_array_method_num
= count_generic
;
4196 return generic_array_method_num
;
4200 * Global pool of interface IDs, represented as a bitset.
4201 * LOCKING: Protected by the classes lock.
4203 static MonoBitSet
*global_interface_bitset
= NULL
;
4206 * mono_unload_interface_ids:
4207 * @bitset: bit set of interface IDs
4209 * When an image is unloaded, the interface IDs associated with
4210 * the image are put back in the global pool of IDs so the numbers
4214 mono_unload_interface_ids (MonoBitSet
*bitset
)
4217 mono_bitset_sub (global_interface_bitset
, bitset
);
4222 mono_unload_interface_id (MonoClass
*klass
)
4224 if (global_interface_bitset
&& klass
->interface_id
) {
4226 mono_bitset_clear (global_interface_bitset
, klass
->interface_id
);
4232 * mono_get_unique_iid:
4233 * \param klass interface
4235 * Assign a unique integer ID to the interface represented by \p klass.
4236 * The ID will positive and as small as possible.
4237 * LOCKING: Acquires the classes lock.
4238 * \returns The new ID.
4241 mono_get_unique_iid (MonoClass
*klass
)
4245 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
));
4249 if (!global_interface_bitset
) {
4250 global_interface_bitset
= mono_bitset_new (128, 0);
4251 mono_bitset_set (global_interface_bitset
, 0); //don't let 0 be a valid iid
4254 iid
= mono_bitset_find_first_unset (global_interface_bitset
, -1);
4256 int old_size
= mono_bitset_size (global_interface_bitset
);
4257 MonoBitSet
*new_set
= mono_bitset_clone (global_interface_bitset
, old_size
* 2);
4258 mono_bitset_free (global_interface_bitset
);
4259 global_interface_bitset
= new_set
;
4262 mono_bitset_set (global_interface_bitset
, iid
);
4263 /* set the bit also in the per-image set */
4264 if (!mono_class_is_ginst (klass
)) {
4265 if (klass
->image
->interface_bitset
) {
4266 if (iid
>= mono_bitset_size (klass
->image
->interface_bitset
)) {
4267 MonoBitSet
*new_set
= mono_bitset_clone (klass
->image
->interface_bitset
, iid
+ 1);
4268 mono_bitset_free (klass
->image
->interface_bitset
);
4269 klass
->image
->interface_bitset
= new_set
;
4272 klass
->image
->interface_bitset
= mono_bitset_new (iid
+ 1, 0);
4274 mono_bitset_set (klass
->image
->interface_bitset
, iid
);
4279 #ifndef MONO_SMALL_CONFIG
4280 if (mono_print_vtable
) {
4282 char *type_name
= mono_type_full_name (m_class_get_byval_arg (klass
));
4283 MonoGenericClass
*gklass
= mono_class_try_get_generic_class (klass
);
4284 if (gklass
&& !gklass
->context
.class_inst
->is_open
) {
4285 generic_id
= gklass
->context
.class_inst
->id
;
4286 g_assert (generic_id
!= 0);
4290 printf ("Interface: assigned id %d to %s|%s|%d\n", iid
, klass
->image
->assembly_name
, type_name
, generic_id
);
4295 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
4296 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
4297 g_assert (iid
< INT_MAX
);
4302 * mono_class_init_internal:
4303 * \param klass the class to initialize
4305 * Compute the \c instance_size, \c class_size and other infos that cannot be
4306 * computed at \c mono_class_get time. Also compute vtable_size if possible.
4307 * Initializes the following fields in \p klass:
4308 * - all the fields initialized by \c mono_class_init_sizes
4313 * LOCKING: Acquires the loader lock.
4315 * \returns TRUE on success or FALSE if there was a problem in loading
4316 * the type (incorrect assemblies, missing assemblies, methods, etc).
4319 mono_class_init_internal (MonoClass
*klass
)
4321 int i
, vtable_size
= 0, array_method_count
= 0;
4322 MonoCachedClassInfo cached_info
;
4323 gboolean has_cached_info
;
4324 gboolean locked
= FALSE
;
4325 gboolean ghcimpl
= FALSE
;
4326 gboolean has_cctor
= FALSE
;
4327 int first_iface_slot
= 0;
4331 /* Double-checking locking pattern */
4332 if (klass
->inited
|| mono_class_has_failure (klass
))
4333 return !mono_class_has_failure (klass
);
4335 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4338 * This function can recursively call itself.
4340 GSList
*init_list
= (GSList
*)mono_native_tls_get_value (init_pending_tls_id
);
4341 if (g_slist_find (init_list
, klass
)) {
4342 mono_class_set_type_load_failure (klass
, "Recursive type definition detected %s.%s", klass
->name_space
, klass
->name
);
4343 goto leave_no_init_pending
;
4345 init_list
= g_slist_prepend (init_list
, klass
);
4346 mono_native_tls_set_value (init_pending_tls_id
, init_list
);
4349 * We want to avoid doing complicated work inside locks, so we compute all the required
4350 * information and write it to @klass inside a lock.
4353 if (mono_verifier_is_enabled_for_class (klass
) && !mono_verifier_verify_class (klass
)) {
4354 mono_class_set_type_load_failure (klass
, "%s", concat_two_strings_with_zero (klass
->image
, klass
->name
, klass
->image
->assembly_name
));
4358 MonoType
*klass_byval_arg
;
4359 klass_byval_arg
= m_class_get_byval_arg (klass
);
4360 if (klass_byval_arg
->type
== MONO_TYPE_ARRAY
|| klass_byval_arg
->type
== MONO_TYPE_SZARRAY
) {
4361 MonoClass
*element_class
= klass
->element_class
;
4362 MonoClass
*cast_class
= klass
->cast_class
;
4364 if (!element_class
->inited
)
4365 mono_class_init_internal (element_class
);
4366 if (mono_class_set_type_load_failure_causedby_class (klass
, element_class
, "Could not load array element class"))
4368 if (!cast_class
->inited
)
4369 mono_class_init_internal (cast_class
);
4370 if (mono_class_set_type_load_failure_causedby_class (klass
, cast_class
, "Could not load array cast class"))
4374 UnlockedIncrement (&mono_stats
.initialized_class_count
);
4376 if (mono_class_is_ginst (klass
) && !mono_class_get_generic_class (klass
)->is_dynamic
) {
4377 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4379 mono_class_init_internal (gklass
);
4380 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic Type Definition failed to init"))
4383 mono_class_setup_interface_id_internal (klass
);
4386 if (klass
->parent
&& !klass
->parent
->inited
)
4387 mono_class_init_internal (klass
->parent
);
4389 has_cached_info
= mono_class_get_cached_class_info (klass
, &cached_info
);
4391 /* Compute instance size etc. */
4392 init_sizes_with_info (klass
, has_cached_info
? &cached_info
: NULL
);
4393 if (mono_class_has_failure (klass
))
4396 mono_class_setup_supertypes (klass
);
4399 initialize_object_slots (klass
);
4402 * Initialize the rest of the data without creating a generic vtable if possible.
4403 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4404 * also avoid computing a generic vtable.
4406 if (has_cached_info
) {
4408 vtable_size
= cached_info
.vtable_size
;
4409 ghcimpl
= cached_info
.ghcimpl
;
4410 has_cctor
= cached_info
.has_cctor
;
4411 } else if (klass
->rank
== 1 && klass_byval_arg
->type
== MONO_TYPE_SZARRAY
) {
4412 /* SZARRAY can have 3 vtable layouts, with and without the stelemref method and enum element type
4413 * The first slot if for array with.
4415 static int szarray_vtable_size
[3] = { 0 };
4419 if (MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (m_class_get_element_class (klass
))))
4421 else if (klass
->element_class
->enumtype
)
4427 if (!szarray_vtable_size
[slot
]) {
4428 mono_class_setup_vtable (klass
);
4429 szarray_vtable_size
[slot
] = klass
->vtable_size
;
4430 vtable_size
= klass
->vtable_size
;
4432 vtable_size
= szarray_vtable_size
[slot
];
4434 } else if (mono_class_is_ginst (klass
) && !MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
4435 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4437 /* Generic instance case */
4438 ghcimpl
= gklass
->ghcimpl
;
4439 has_cctor
= gklass
->has_cctor
;
4441 mono_class_setup_vtable (gklass
);
4442 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to init"))
4445 vtable_size
= gklass
->vtable_size
;
4449 /* ghcimpl is not currently used
4451 if (klass->parent) {
4452 MonoMethod *cmethod = klass->vtable [ghc_slot];
4453 if (cmethod->is_inflated)
4454 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
4455 if (cmethod == default_ghc) {
4461 /* C# doesn't allow interfaces to have cctors */
4462 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || klass
->image
!= mono_defaults
.corlib
) {
4463 MonoMethod
*cmethod
= NULL
;
4465 if (mono_class_is_ginst (klass
)) {
4466 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4468 /* Generic instance case */
4469 ghcimpl
= gklass
->ghcimpl
;
4470 has_cctor
= gklass
->has_cctor
;
4471 } else if (klass
->type_token
&& !image_is_dynamic(klass
->image
)) {
4472 cmethod
= mono_find_method_in_metadata (klass
, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME
);
4473 /* The find_method function ignores the 'flags' argument */
4474 if (cmethod
&& (cmethod
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
))
4477 mono_class_setup_methods (klass
);
4478 if (mono_class_has_failure (klass
))
4481 int mcount
= mono_class_get_method_count (klass
);
4482 for (i
= 0; i
< mcount
; ++i
) {
4483 MonoMethod
*method
= klass
->methods
[i
];
4484 if ((method
->flags
& METHOD_ATTRIBUTE_SPECIAL_NAME
) &&
4485 (strcmp (".cctor", method
->name
) == 0)) {
4495 array_method_count
= 3 + (klass
->rank
> 1? 2: 1);
4497 if (klass
->interface_count
) {
4498 int count_generic
= generic_array_methods (klass
);
4499 array_method_count
+= klass
->interface_count
* count_generic
;
4503 if (klass
->parent
) {
4504 if (!klass
->parent
->vtable_size
)
4505 mono_class_setup_vtable (klass
->parent
);
4506 if (mono_class_set_type_load_failure_causedby_class (klass
, klass
->parent
, "Parent class vtable failed to initialize"))
4508 g_assert (klass
->parent
->vtable_size
);
4509 first_iface_slot
= klass
->parent
->vtable_size
;
4510 if (mono_class_need_stelemref_method (klass
))
4515 * Do the actual changes to @klass inside the loader lock
4517 mono_loader_lock ();
4520 if (klass
->inited
|| mono_class_has_failure (klass
)) {
4521 mono_loader_unlock ();
4522 /* Somebody might have gotten in before us */
4523 return !mono_class_has_failure (klass
);
4526 UnlockedIncrement (&mono_stats
.initialized_class_count
);
4528 if (mono_class_is_ginst (klass
) && !mono_class_get_generic_class (klass
)->is_dynamic
)
4529 UnlockedIncrement (&mono_stats
.generic_class_count
);
4531 if (mono_class_is_ginst (klass
) || image_is_dynamic (klass
->image
) || !klass
->type_token
|| (has_cached_info
&& !cached_info
.has_nested_classes
))
4532 klass
->nested_classes_inited
= TRUE
;
4533 klass
->ghcimpl
= ghcimpl
;
4534 klass
->has_cctor
= has_cctor
;
4536 klass
->vtable_size
= vtable_size
;
4537 if (has_cached_info
) {
4538 klass
->has_finalize
= cached_info
.has_finalize
;
4539 klass
->has_finalize_inited
= TRUE
;
4542 mono_class_set_method_count (klass
, array_method_count
);
4544 mono_loader_unlock ();
4547 setup_interface_offsets (klass
, first_iface_slot
, TRUE
);
4549 if (mono_security_core_clr_enabled ())
4550 mono_security_core_clr_check_inheritance (klass
);
4552 if (mono_class_is_ginst (klass
) && !mono_verifier_class_is_valid_generic_instantiation (klass
))
4553 mono_class_set_type_load_failure (klass
, "Invalid generic instantiation");
4558 init_list
= (GSList
*)mono_native_tls_get_value (init_pending_tls_id
);
4559 init_list
= g_slist_remove (init_list
, klass
);
4560 mono_native_tls_set_value (init_pending_tls_id
, init_list
);
4562 leave_no_init_pending
:
4564 mono_loader_unlock ();
4566 /* Leave this for last */
4567 mono_loader_lock ();
4569 mono_loader_unlock ();
4571 return !mono_class_has_failure (klass
);
4575 mono_class_init_checked (MonoClass
*klass
, MonoError
*error
)
4578 gboolean
const success
= mono_class_init_internal (klass
);
4580 mono_error_set_for_class_failure (error
, klass
);
4586 * COM initialization is delayed until needed.
4587 * However when a [ComImport] attribute is present on a type it will trigger
4588 * the initialization. This is not a problem unless the BCL being executed
4589 * lacks the types that COM depends on (e.g. Variant on Silverlight).
4592 init_com_from_comimport (MonoClass
*klass
)
4594 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
4595 if (mono_security_core_clr_enabled ()) {
4596 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
4597 if (!mono_security_core_clr_determine_platform_image (klass
->image
)) {
4598 /* but it can not be made available for application (i.e. user code) since all COM calls
4599 * are considered native calls. In this case we fail with a TypeLoadException (just like
4600 * Silverlight 2 does */
4601 mono_class_set_type_load_failure (klass
, "");
4606 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
4608 #endif /*DISABLE_COM*/
4611 * LOCKING: this assumes the loader lock is held
4614 mono_class_setup_parent (MonoClass
*klass
, MonoClass
*parent
)
4616 gboolean system_namespace
;
4617 gboolean is_corlib
= mono_is_corlib_image (klass
->image
);
4619 system_namespace
= !strcmp (klass
->name_space
, "System") && is_corlib
;
4621 /* if root of the hierarchy */
4622 if (system_namespace
&& !strcmp (klass
->name
, "Object")) {
4623 klass
->parent
= NULL
;
4624 klass
->instance_size
= MONO_ABI_SIZEOF (MonoObject
);
4627 if (!strcmp (klass
->name
, "<Module>")) {
4628 klass
->parent
= NULL
;
4629 klass
->instance_size
= 0;
4633 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
4634 /* Imported COM Objects always derive from __ComObject. */
4636 if (MONO_CLASS_IS_IMPORT (klass
)) {
4637 init_com_from_comimport (klass
);
4638 if (parent
== mono_defaults
.object_class
)
4639 parent
= mono_class_get_com_object_class ();
4643 /* set the parent to something useful and safe, but mark the type as broken */
4644 parent
= mono_defaults
.object_class
;
4645 mono_class_set_type_load_failure (klass
, "");
4649 klass
->parent
= parent
;
4651 if (mono_class_is_ginst (parent
) && !parent
->name
) {
4653 * If the parent is a generic instance, we may get
4654 * called before it is fully initialized, especially
4655 * before it has its name.
4660 #ifndef DISABLE_REMOTING
4661 klass
->marshalbyref
= parent
->marshalbyref
;
4662 klass
->contextbound
= parent
->contextbound
;
4665 klass
->delegate
= parent
->delegate
;
4667 if (MONO_CLASS_IS_IMPORT (klass
) || mono_class_is_com_object (parent
))
4668 mono_class_set_is_com_object (klass
);
4670 if (system_namespace
) {
4671 #ifndef DISABLE_REMOTING
4672 if (klass
->name
[0] == 'M' && !strcmp (klass
->name
, "MarshalByRefObject"))
4673 klass
->marshalbyref
= 1;
4675 if (klass
->name
[0] == 'C' && !strcmp (klass
->name
, "ContextBoundObject"))
4676 klass
->contextbound
= 1;
4678 if (klass
->name
[0] == 'D' && !strcmp (klass
->name
, "Delegate"))
4679 klass
->delegate
= 1;
4682 if (klass
->parent
->enumtype
|| (mono_is_corlib_image (klass
->parent
->image
) && (strcmp (klass
->parent
->name
, "ValueType") == 0) &&
4683 (strcmp (klass
->parent
->name_space
, "System") == 0)))
4684 klass
->valuetype
= 1;
4685 if (mono_is_corlib_image (klass
->parent
->image
) && ((strcmp (klass
->parent
->name
, "Enum") == 0) && (strcmp (klass
->parent
->name_space
, "System") == 0))) {
4686 klass
->valuetype
= klass
->enumtype
= 1;
4688 /*klass->enumtype = klass->parent->enumtype; */
4690 /* initialize com types if COM interfaces are present */
4692 if (MONO_CLASS_IS_IMPORT (klass
))
4693 init_com_from_comimport (klass
);
4695 klass
->parent
= NULL
;
4700 /* Locking: must be called with the loader lock held. */
4702 mono_class_setup_interface_id_internal (MonoClass
*klass
)
4704 if (!MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || klass
->interface_id
)
4706 klass
->interface_id
= mono_get_unique_iid (klass
);
4708 if (mono_is_corlib_image (klass
->image
) && !strcmp (m_class_get_name_space (klass
), "System.Collections.Generic")) {
4709 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
4710 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
4711 * MS returns diferrent types based on which instance is called. For example:
4712 * object obj = new byte[10][];
4713 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
4714 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
4717 const char *name
= m_class_get_name (klass
);
4718 if (!strcmp (name
, "IList`1") || !strcmp (name
, "ICollection`1") || !strcmp (name
, "IEnumerable`1") || !strcmp (name
, "IEnumerator`1"))
4719 klass
->is_array_special_interface
= 1;
4725 * LOCKING: this assumes the loader lock is held
4728 mono_class_setup_mono_type (MonoClass
*klass
)
4730 const char *name
= klass
->name
;
4731 const char *nspace
= klass
->name_space
;
4732 gboolean is_corlib
= mono_is_corlib_image (klass
->image
);
4734 klass
->this_arg
.byref
= 1;
4735 klass
->this_arg
.data
.klass
= klass
;
4736 klass
->this_arg
.type
= MONO_TYPE_CLASS
;
4737 klass
->_byval_arg
.data
.klass
= klass
;
4738 klass
->_byval_arg
.type
= MONO_TYPE_CLASS
;
4740 if (is_corlib
&& !strcmp (nspace
, "System")) {
4741 if (!strcmp (name
, "ValueType")) {
4743 * do not set the valuetype bit for System.ValueType.
4744 * klass->valuetype = 1;
4746 klass
->blittable
= TRUE
;
4747 } else if (!strcmp (name
, "Enum")) {
4749 * do not set the valuetype bit for System.Enum.
4750 * klass->valuetype = 1;
4752 klass
->valuetype
= 0;
4753 klass
->enumtype
= 0;
4754 } else if (!strcmp (name
, "Object")) {
4755 klass
->_byval_arg
.type
= MONO_TYPE_OBJECT
;
4756 klass
->this_arg
.type
= MONO_TYPE_OBJECT
;
4757 } else if (!strcmp (name
, "String")) {
4758 klass
->_byval_arg
.type
= MONO_TYPE_STRING
;
4759 klass
->this_arg
.type
= MONO_TYPE_STRING
;
4760 } else if (!strcmp (name
, "TypedReference")) {
4761 klass
->_byval_arg
.type
= MONO_TYPE_TYPEDBYREF
;
4762 klass
->this_arg
.type
= MONO_TYPE_TYPEDBYREF
;
4766 if (klass
->valuetype
) {
4767 int t
= MONO_TYPE_VALUETYPE
;
4769 if (is_corlib
&& !strcmp (nspace
, "System")) {
4772 if (!strcmp (name
, "Boolean")) {
4773 t
= MONO_TYPE_BOOLEAN
;
4774 } else if (!strcmp(name
, "Byte")) {
4776 klass
->blittable
= TRUE
;
4780 if (!strcmp (name
, "Char")) {
4785 if (!strcmp (name
, "Double")) {
4787 klass
->blittable
= TRUE
;
4791 if (!strcmp (name
, "Int32")) {
4793 klass
->blittable
= TRUE
;
4794 } else if (!strcmp(name
, "Int16")) {
4796 klass
->blittable
= TRUE
;
4797 } else if (!strcmp(name
, "Int64")) {
4799 klass
->blittable
= TRUE
;
4800 } else if (!strcmp(name
, "IntPtr")) {
4802 klass
->blittable
= TRUE
;
4806 if (!strcmp (name
, "Single")) {
4808 klass
->blittable
= TRUE
;
4809 } else if (!strcmp(name
, "SByte")) {
4811 klass
->blittable
= TRUE
;
4815 if (!strcmp (name
, "UInt32")) {
4817 klass
->blittable
= TRUE
;
4818 } else if (!strcmp(name
, "UInt16")) {
4820 klass
->blittable
= TRUE
;
4821 } else if (!strcmp(name
, "UInt64")) {
4823 klass
->blittable
= TRUE
;
4824 } else if (!strcmp(name
, "UIntPtr")) {
4826 klass
->blittable
= TRUE
;
4830 if (!strcmp (name
, "TypedReference")) {
4831 t
= MONO_TYPE_TYPEDBYREF
;
4832 klass
->blittable
= TRUE
;
4836 if (!strcmp (name
, "Void")) {
4844 klass
->_byval_arg
.type
= (MonoTypeEnum
)t
;
4845 klass
->this_arg
.type
= (MonoTypeEnum
)t
;
4848 mono_class_setup_interface_id_internal (klass
);
4852 create_array_method (MonoClass
*klass
, const char *name
, MonoMethodSignature
*sig
)
4856 method
= (MonoMethod
*) mono_image_alloc0 (klass
->image
, sizeof (MonoMethodPInvoke
));
4857 method
->klass
= klass
;
4858 method
->flags
= METHOD_ATTRIBUTE_PUBLIC
;
4859 method
->iflags
= METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL
;
4860 method
->signature
= sig
;
4861 method
->name
= name
;
4864 if (name
[0] == '.') {
4865 method
->flags
|= METHOD_ATTRIBUTE_RT_SPECIAL_NAME
| METHOD_ATTRIBUTE_SPECIAL_NAME
;
4867 method
->iflags
|= METHOD_IMPL_ATTRIBUTE_RUNTIME
;
4873 * mono_class_setup_methods:
4876 * Initializes the 'methods' array in CLASS.
4877 * Calling this method should be avoided if possible since it allocates a lot
4878 * of long-living MonoMethod structures.
4879 * Methods belonging to an interface are assigned a sequential slot starting
4882 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
4885 mono_class_setup_methods (MonoClass
*klass
)
4888 MonoMethod
**methods
;
4893 if (mono_class_is_ginst (klass
)) {
4895 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
4897 mono_class_init_internal (gklass
);
4898 if (!mono_class_has_failure (gklass
))
4899 mono_class_setup_methods (gklass
);
4900 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
4903 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
4904 count
= mono_class_get_method_count (gklass
);
4905 methods
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (MonoMethod
*) * (count
+ 1));
4907 for (i
= 0; i
< count
; i
++) {
4908 methods
[i
] = mono_class_inflate_generic_method_full_checked (
4909 gklass
->methods
[i
], klass
, mono_class_get_context (klass
), error
);
4910 if (!mono_error_ok (error
)) {
4911 char *method
= mono_method_full_name (gklass
->methods
[i
], TRUE
);
4912 mono_class_set_type_load_failure (klass
, "Could not inflate method %s due to %s", method
, mono_error_get_message (error
));
4915 mono_error_cleanup (error
);
4919 } else if (klass
->rank
) {
4921 MonoMethod
*amethod
;
4922 MonoMethodSignature
*sig
;
4923 int count_generic
= 0, first_generic
= 0;
4925 gboolean jagged_ctor
= FALSE
;
4927 count
= 3 + (klass
->rank
> 1? 2: 1);
4929 mono_class_setup_interfaces (klass
, error
);
4930 g_assert (mono_error_ok (error
)); /*FIXME can this fail for array types?*/
4932 if (klass
->rank
== 1 && klass
->element_class
->rank
) {
4937 if (klass
->interface_count
) {
4938 count_generic
= generic_array_methods (klass
);
4939 first_generic
= count
;
4940 count
+= klass
->interface_count
* count_generic
;
4943 methods
= (MonoMethod
**)mono_class_alloc0 (klass
, sizeof (MonoMethod
*) * count
);
4945 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
4946 sig
->ret
= mono_get_void_type ();
4947 sig
->pinvoke
= TRUE
;
4948 sig
->hasthis
= TRUE
;
4949 for (i
= 0; i
< klass
->rank
; ++i
)
4950 sig
->params
[i
] = mono_get_int32_type ();
4952 amethod
= create_array_method (klass
, ".ctor", sig
);
4953 methods
[method_num
++] = amethod
;
4954 if (klass
->rank
> 1) {
4955 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
* 2);
4956 sig
->ret
= mono_get_void_type ();
4957 sig
->pinvoke
= TRUE
;
4958 sig
->hasthis
= TRUE
;
4959 for (i
= 0; i
< klass
->rank
* 2; ++i
)
4960 sig
->params
[i
] = mono_get_int32_type ();
4962 amethod
= create_array_method (klass
, ".ctor", sig
);
4963 methods
[method_num
++] = amethod
;
4967 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
4968 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
+ 1);
4969 sig
->ret
= mono_get_void_type ();
4970 sig
->pinvoke
= TRUE
;
4971 sig
->hasthis
= TRUE
;
4972 for (i
= 0; i
< klass
->rank
+ 1; ++i
)
4973 sig
->params
[i
] = mono_get_int32_type ();
4974 amethod
= create_array_method (klass
, ".ctor", sig
);
4975 methods
[method_num
++] = amethod
;
4978 /* element Get (idx11, [idx2, ...]) */
4979 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
4980 sig
->ret
= m_class_get_byval_arg (m_class_get_element_class (klass
));
4981 sig
->pinvoke
= TRUE
;
4982 sig
->hasthis
= TRUE
;
4983 for (i
= 0; i
< klass
->rank
; ++i
)
4984 sig
->params
[i
] = mono_get_int32_type ();
4985 amethod
= create_array_method (klass
, "Get", sig
);
4986 methods
[method_num
++] = amethod
;
4987 /* element& Address (idx11, [idx2, ...]) */
4988 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
);
4989 sig
->ret
= &klass
->element_class
->this_arg
;
4990 sig
->pinvoke
= TRUE
;
4991 sig
->hasthis
= TRUE
;
4992 for (i
= 0; i
< klass
->rank
; ++i
)
4993 sig
->params
[i
] = mono_get_int32_type ();
4994 amethod
= create_array_method (klass
, "Address", sig
);
4995 methods
[method_num
++] = amethod
;
4996 /* void Set (idx11, [idx2, ...], element) */
4997 sig
= mono_metadata_signature_alloc (klass
->image
, klass
->rank
+ 1);
4998 sig
->ret
= mono_get_void_type ();
4999 sig
->pinvoke
= TRUE
;
5000 sig
->hasthis
= TRUE
;
5001 for (i
= 0; i
< klass
->rank
; ++i
)
5002 sig
->params
[i
] = mono_get_int32_type ();
5003 sig
->params
[i
] = m_class_get_byval_arg (m_class_get_element_class (klass
));
5004 amethod
= create_array_method (klass
, "Set", sig
);
5005 methods
[method_num
++] = amethod
;
5007 GHashTable
*cache
= g_hash_table_new (NULL
, NULL
);
5008 for (i
= 0; i
< klass
->interface_count
; i
++)
5009 setup_generic_array_ifaces (klass
, klass
->interfaces
[i
], methods
, first_generic
+ i
* count_generic
, cache
);
5010 g_hash_table_destroy (cache
);
5011 } else if (mono_class_has_static_metadata (klass
)) {
5013 int first_idx
= mono_class_get_first_method_idx (klass
);
5015 count
= mono_class_get_method_count (klass
);
5016 methods
= (MonoMethod
**)mono_class_alloc (klass
, sizeof (MonoMethod
*) * count
);
5017 for (i
= 0; i
< count
; ++i
) {
5018 int idx
= mono_metadata_translate_token_index (klass
->image
, MONO_TABLE_METHOD
, first_idx
+ i
+ 1);
5019 methods
[i
] = mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| idx
, klass
, NULL
, error
);
5021 mono_class_set_type_load_failure (klass
, "Could not load method %d due to %s", i
, mono_error_get_message (error
));
5022 mono_error_cleanup (error
);
5026 methods
= (MonoMethod
**)mono_class_alloc (klass
, sizeof (MonoMethod
*) * 1);
5030 if (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
)) {
5032 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
5033 for (i
= 0; i
< count
; ++i
) {
5034 if (methods
[i
]->flags
& METHOD_ATTRIBUTE_VIRTUAL
)
5035 methods
[i
]->slot
= slot
++;
5039 mono_image_lock (klass
->image
);
5041 if (!klass
->methods
) {
5042 mono_class_set_method_count (klass
, count
);
5044 /* Needed because of the double-checking locking pattern */
5045 mono_memory_barrier ();
5047 klass
->methods
= methods
;
5050 mono_image_unlock (klass
->image
);
5054 * mono_class_setup_properties:
5056 * Initialize klass->ext.property and klass->ext.properties.
5058 * This method can fail the class.
5061 mono_class_setup_properties (MonoClass
*klass
)
5063 guint startm
, endm
, i
, j
;
5064 guint32 cols
[MONO_PROPERTY_SIZE
];
5065 MonoTableInfo
*msemt
= &klass
->image
->tables
[MONO_TABLE_METHODSEMANTICS
];
5066 MonoProperty
*properties
;
5069 MonoClassPropertyInfo
*info
;
5071 info
= mono_class_get_property_info (klass
);
5075 if (mono_class_is_ginst (klass
)) {
5076 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5078 mono_class_init_internal (gklass
);
5079 mono_class_setup_properties (gklass
);
5080 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
5083 MonoClassPropertyInfo
*ginfo
= mono_class_get_property_info (gklass
);
5084 properties
= mono_class_new0 (klass
, MonoProperty
, ginfo
->count
+ 1);
5086 for (i
= 0; i
< ginfo
->count
; i
++) {
5088 MonoProperty
*prop
= &properties
[i
];
5090 *prop
= ginfo
->properties
[i
];
5093 prop
->get
= mono_class_inflate_generic_method_full_checked (
5094 prop
->get
, klass
, mono_class_get_context (klass
), error
);
5096 prop
->set
= mono_class_inflate_generic_method_full_checked (
5097 prop
->set
, klass
, mono_class_get_context (klass
), error
);
5099 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5100 prop
->parent
= klass
;
5103 first
= ginfo
->first
;
5104 count
= ginfo
->count
;
5106 first
= mono_metadata_properties_from_typedef (klass
->image
, mono_metadata_token_index (klass
->type_token
) - 1, &last
);
5107 count
= last
- first
;
5110 mono_class_setup_methods (klass
);
5111 if (mono_class_has_failure (klass
))
5115 properties
= (MonoProperty
*)mono_class_alloc0 (klass
, sizeof (MonoProperty
) * count
);
5116 for (i
= first
; i
< last
; ++i
) {
5117 mono_metadata_decode_table_row (klass
->image
, MONO_TABLE_PROPERTY
, i
, cols
, MONO_PROPERTY_SIZE
);
5118 properties
[i
- first
].parent
= klass
;
5119 properties
[i
- first
].attrs
= cols
[MONO_PROPERTY_FLAGS
];
5120 properties
[i
- first
].name
= mono_metadata_string_heap (klass
->image
, cols
[MONO_PROPERTY_NAME
]);
5122 startm
= mono_metadata_methods_from_property (klass
->image
, i
, &endm
);
5123 int first_idx
= mono_class_get_first_method_idx (klass
);
5124 for (j
= startm
; j
< endm
; ++j
) {
5127 mono_metadata_decode_row (msemt
, j
, cols
, MONO_METHOD_SEMA_SIZE
);
5129 if (klass
->image
->uncompressed_metadata
) {
5131 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5132 method
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| cols
[MONO_METHOD_SEMA_METHOD
], klass
, NULL
, error
);
5133 mono_error_cleanup (error
); /* FIXME don't swallow this error */
5135 method
= klass
->methods
[cols
[MONO_METHOD_SEMA_METHOD
] - 1 - first_idx
];
5138 switch (cols
[MONO_METHOD_SEMA_SEMANTICS
]) {
5139 case METHOD_SEMANTIC_SETTER
:
5140 properties
[i
- first
].set
= method
;
5142 case METHOD_SEMANTIC_GETTER
:
5143 properties
[i
- first
].get
= method
;
5152 info
= (MonoClassPropertyInfo
*)mono_class_alloc0 (klass
, sizeof (MonoClassPropertyInfo
));
5153 info
->first
= first
;
5154 info
->count
= count
;
5155 info
->properties
= properties
;
5156 mono_memory_barrier ();
5158 /* This might leak 'info' which was allocated from the image mempool */
5159 mono_class_set_property_info (klass
, info
);
5163 inflate_method_listz (MonoMethod
**methods
, MonoClass
*klass
, MonoGenericContext
*context
)
5165 MonoMethod
**om
, **retval
;
5168 for (om
= methods
, count
= 0; *om
; ++om
, ++count
)
5171 retval
= g_new0 (MonoMethod
*, count
+ 1);
5173 for (om
= methods
, count
= 0; *om
; ++om
, ++count
) {
5175 retval
[count
] = mono_class_inflate_generic_method_full_checked (*om
, klass
, context
, error
);
5176 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5182 /*This method can fail the class.*/
5184 mono_class_setup_events (MonoClass
*klass
)
5187 guint startm
, endm
, i
, j
;
5188 guint32 cols
[MONO_EVENT_SIZE
];
5189 MonoTableInfo
*msemt
= &klass
->image
->tables
[MONO_TABLE_METHODSEMANTICS
];
5193 MonoClassEventInfo
*info
= mono_class_get_event_info (klass
);
5197 if (mono_class_is_ginst (klass
)) {
5198 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5199 MonoGenericContext
*context
= NULL
;
5201 mono_class_setup_events (gklass
);
5202 if (mono_class_set_type_load_failure_causedby_class (klass
, gklass
, "Generic type definition failed to load"))
5205 MonoClassEventInfo
*ginfo
= mono_class_get_event_info (gklass
);
5206 first
= ginfo
->first
;
5207 count
= ginfo
->count
;
5209 events
= mono_class_new0 (klass
, MonoEvent
, count
);
5212 context
= mono_class_get_context (klass
);
5214 for (i
= 0; i
< count
; i
++) {
5216 MonoEvent
*event
= &events
[i
];
5217 MonoEvent
*gevent
= &ginfo
->events
[i
];
5219 error_init (error
); //since we do conditional calls, we must ensure the default value is ok
5221 event
->parent
= klass
;
5222 event
->name
= gevent
->name
;
5223 event
->add
= gevent
->add
? mono_class_inflate_generic_method_full_checked (gevent
->add
, klass
, context
, error
) : NULL
;
5224 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5225 event
->remove
= gevent
->remove
? mono_class_inflate_generic_method_full_checked (gevent
->remove
, klass
, context
, error
) : NULL
;
5226 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5227 event
->raise
= gevent
->raise
? mono_class_inflate_generic_method_full_checked (gevent
->raise
, klass
, context
, error
) : NULL
;
5228 g_assert (mono_error_ok (error
)); /*FIXME proper error handling*/
5230 #ifndef MONO_SMALL_CONFIG
5231 event
->other
= gevent
->other
? inflate_method_listz (gevent
->other
, klass
, context
) : NULL
;
5233 event
->attrs
= gevent
->attrs
;
5236 first
= mono_metadata_events_from_typedef (klass
->image
, mono_metadata_token_index (klass
->type_token
) - 1, &last
);
5237 count
= last
- first
;
5240 mono_class_setup_methods (klass
);
5241 if (mono_class_has_failure (klass
)) {
5246 events
= (MonoEvent
*)mono_class_alloc0 (klass
, sizeof (MonoEvent
) * count
);
5247 for (i
= first
; i
< last
; ++i
) {
5248 MonoEvent
*event
= &events
[i
- first
];
5250 mono_metadata_decode_table_row (klass
->image
, MONO_TABLE_EVENT
, i
, cols
, MONO_EVENT_SIZE
);
5251 event
->parent
= klass
;
5252 event
->attrs
= cols
[MONO_EVENT_FLAGS
];
5253 event
->name
= mono_metadata_string_heap (klass
->image
, cols
[MONO_EVENT_NAME
]);
5255 startm
= mono_metadata_methods_from_event (klass
->image
, i
, &endm
);
5256 int first_idx
= mono_class_get_first_method_idx (klass
);
5257 for (j
= startm
; j
< endm
; ++j
) {
5260 mono_metadata_decode_row (msemt
, j
, cols
, MONO_METHOD_SEMA_SIZE
);
5262 if (klass
->image
->uncompressed_metadata
) {
5264 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
5265 method
= mono_get_method_checked (klass
->image
, MONO_TOKEN_METHOD_DEF
| cols
[MONO_METHOD_SEMA_METHOD
], klass
, NULL
, error
);
5266 mono_error_cleanup (error
); /* FIXME don't swallow this error */
5268 method
= klass
->methods
[cols
[MONO_METHOD_SEMA_METHOD
] - 1 - first_idx
];
5271 switch (cols
[MONO_METHOD_SEMA_SEMANTICS
]) {
5272 case METHOD_SEMANTIC_ADD_ON
:
5273 event
->add
= method
;
5275 case METHOD_SEMANTIC_REMOVE_ON
:
5276 event
->remove
= method
;
5278 case METHOD_SEMANTIC_FIRE
:
5279 event
->raise
= method
;
5281 case METHOD_SEMANTIC_OTHER
: {
5282 #ifndef MONO_SMALL_CONFIG
5285 if (event
->other
== NULL
) {
5286 event
->other
= g_new0 (MonoMethod
*, 2);
5288 while (event
->other
[n
])
5290 event
->other
= (MonoMethod
**)g_realloc (event
->other
, (n
+ 2) * sizeof (MonoMethod
*));
5292 event
->other
[n
] = method
;
5293 /* NULL terminated */
5294 event
->other
[n
+ 1] = NULL
;
5305 info
= (MonoClassEventInfo
*)mono_class_alloc0 (klass
, sizeof (MonoClassEventInfo
));
5306 info
->events
= events
;
5307 info
->first
= first
;
5308 info
->count
= count
;
5310 mono_memory_barrier ();
5312 mono_class_set_event_info (klass
, info
);
5317 * mono_class_setup_interface_id:
5319 * Initializes MonoClass::interface_id if required.
5321 * LOCKING: Acquires the loader lock.
5324 mono_class_setup_interface_id (MonoClass
*klass
)
5326 g_assert (MONO_CLASS_IS_INTERFACE_INTERNAL (klass
));
5327 mono_loader_lock ();
5328 mono_class_setup_interface_id_internal (klass
);
5329 mono_loader_unlock ();
5333 * mono_class_setup_interfaces:
5335 * Initialize klass->interfaces/interfaces_count.
5336 * LOCKING: Acquires the loader lock.
5337 * This function can fail the type.
5340 mono_class_setup_interfaces (MonoClass
*klass
, MonoError
*error
)
5342 int i
, interface_count
;
5343 MonoClass
**interfaces
;
5347 if (klass
->interfaces_inited
)
5350 if (klass
->rank
== 1 && m_class_get_byval_arg (klass
)->type
!= MONO_TYPE_ARRAY
) {
5353 /* IList and IReadOnlyList -> 2x if enum*/
5354 interface_count
= klass
->element_class
->enumtype
? 4 : 2;
5355 interfaces
= (MonoClass
**)mono_image_alloc0 (klass
->image
, sizeof (MonoClass
*) * interface_count
);
5357 args
[0] = m_class_get_byval_arg (m_class_get_element_class (klass
));
5358 interfaces
[0] = mono_class_bind_generic_parameters (
5359 mono_defaults
.generic_ilist_class
, 1, args
, FALSE
);
5360 interfaces
[1] = mono_class_bind_generic_parameters (
5361 mono_defaults
.generic_ireadonlylist_class
, 1, args
, FALSE
);
5362 if (klass
->element_class
->enumtype
) {
5363 args
[0] = mono_class_enum_basetype_internal (klass
->element_class
);
5364 interfaces
[2] = mono_class_bind_generic_parameters (
5365 mono_defaults
.generic_ilist_class
, 1, args
, FALSE
);
5366 interfaces
[3] = mono_class_bind_generic_parameters (
5367 mono_defaults
.generic_ireadonlylist_class
, 1, args
, FALSE
);
5369 } else if (mono_class_is_ginst (klass
)) {
5370 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5372 mono_class_setup_interfaces (gklass
, error
);
5373 if (!mono_error_ok (error
)) {
5374 mono_class_set_type_load_failure (klass
, "Could not setup the interfaces");
5378 interface_count
= gklass
->interface_count
;
5379 interfaces
= mono_class_new0 (klass
, MonoClass
*, interface_count
);
5380 for (i
= 0; i
< interface_count
; i
++) {
5381 interfaces
[i
] = mono_class_inflate_generic_class_checked (gklass
->interfaces
[i
], mono_generic_class_get_context (mono_class_get_generic_class (klass
)), error
);
5382 if (!mono_error_ok (error
)) {
5383 mono_class_set_type_load_failure (klass
, "Could not setup the interfaces");
5388 interface_count
= 0;
5392 mono_loader_lock ();
5393 if (!klass
->interfaces_inited
) {
5394 klass
->interface_count
= interface_count
;
5395 klass
->interfaces
= interfaces
;
5397 mono_memory_barrier ();
5399 klass
->interfaces_inited
= TRUE
;
5401 mono_loader_unlock ();
5406 * mono_class_setup_has_finalizer:
5408 * Initialize klass->has_finalizer if it isn't already initialized.
5410 * LOCKING: Acquires the loader lock.
5413 mono_class_setup_has_finalizer (MonoClass
*klass
)
5415 gboolean has_finalize
= FALSE
;
5417 if (m_class_is_has_finalize_inited (klass
))
5420 /* Interfaces and valuetypes are not supposed to have finalizers */
5421 if (!(MONO_CLASS_IS_INTERFACE_INTERNAL (klass
) || m_class_is_valuetype (klass
))) {
5422 MonoMethod
*cmethod
= NULL
;
5424 if (m_class_get_rank (klass
) == 1 && m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
) {
5425 } else if (mono_class_is_ginst (klass
)) {
5426 MonoClass
*gklass
= mono_class_get_generic_class (klass
)->container_class
;
5428 has_finalize
= mono_class_has_finalizer (gklass
);
5429 } else if (m_class_get_parent (klass
) && m_class_has_finalize (m_class_get_parent (klass
))) {
5430 has_finalize
= TRUE
;
5432 if (m_class_get_parent (klass
)) {
5434 * Can't search in metadata for a method named Finalize, because that
5435 * ignores overrides.
5437 mono_class_setup_vtable (klass
);
5438 if (mono_class_has_failure (klass
))
5441 cmethod
= m_class_get_vtable (klass
) [mono_class_get_object_finalize_slot ()];
5445 g_assert (m_class_get_vtable_size (klass
) > mono_class_get_object_finalize_slot ());
5447 if (m_class_get_parent (klass
)) {
5448 if (cmethod
->is_inflated
)
5449 cmethod
= ((MonoMethodInflated
*)cmethod
)->declaring
;
5450 if (cmethod
!= mono_class_get_default_finalize_method ())
5451 has_finalize
= TRUE
;
5457 mono_loader_lock ();
5458 if (!m_class_is_has_finalize_inited (klass
)) {
5459 klass
->has_finalize
= has_finalize
? 1 : 0;
5461 mono_memory_barrier ();
5462 klass
->has_finalize_inited
= TRUE
;
5464 mono_loader_unlock ();
5468 * mono_class_setup_supertypes:
5471 * Build the data structure needed to make fast type checks work.
5472 * This currently sets two fields in @class:
5473 * - idepth: distance between @class and System.Object in the type
5475 * - supertypes: array of classes: each element has a class in the hierarchy
5476 * starting from @class up to System.Object
5478 * LOCKING: Acquires the loader lock.
5481 mono_class_setup_supertypes (MonoClass
*klass
)
5484 MonoClass
**supertypes
;
5486 mono_atomic_load_acquire (supertypes
, MonoClass
**, &klass
->supertypes
);
5490 if (klass
->parent
&& !klass
->parent
->supertypes
)
5491 mono_class_setup_supertypes (klass
->parent
);
5493 idepth
= klass
->parent
->idepth
+ 1;
5497 ms
= MAX (MONO_DEFAULT_SUPERTABLE_SIZE
, idepth
);
5498 supertypes
= (MonoClass
**)mono_class_alloc0 (klass
, sizeof (MonoClass
*) * ms
);
5500 if (klass
->parent
) {
5501 CHECKED_METADATA_WRITE_PTR ( supertypes
[idepth
- 1] , klass
);
5504 for (supertype_idx
= 0; supertype_idx
< klass
->parent
->idepth
; supertype_idx
++)
5505 CHECKED_METADATA_WRITE_PTR ( supertypes
[supertype_idx
] , klass
->parent
->supertypes
[supertype_idx
] );
5507 CHECKED_METADATA_WRITE_PTR ( supertypes
[0] , klass
);
5510 mono_memory_barrier ();
5512 mono_loader_lock ();
5513 klass
->idepth
= idepth
;
5514 /* Needed so idepth is visible before supertypes is set */
5515 mono_memory_barrier ();
5516 klass
->supertypes
= supertypes
;
5517 mono_loader_unlock ();
5520 /* mono_class_setup_nested_types:
5522 * Initialize the nested_classes property for the given MonoClass if it hasn't already been initialized.
5524 * LOCKING: Acquires the loader lock.
5527 mono_class_setup_nested_types (MonoClass
*klass
)
5530 GList
*classes
, *nested_classes
, *l
;
5533 if (klass
->nested_classes_inited
)
5536 if (!klass
->type_token
) {
5537 mono_loader_lock ();
5538 klass
->nested_classes_inited
= TRUE
;
5539 mono_loader_unlock ();
5543 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, 1);
5547 guint32 cols
[MONO_NESTED_CLASS_SIZE
];
5548 mono_metadata_decode_row (&klass
->image
->tables
[MONO_TABLE_NESTEDCLASS
], i
- 1, cols
, MONO_NESTED_CLASS_SIZE
);
5549 nclass
= mono_class_create_from_typedef (klass
->image
, MONO_TOKEN_TYPE_DEF
| cols
[MONO_NESTED_CLASS_NESTED
], error
);
5550 if (!mono_error_ok (error
)) {
5551 /*FIXME don't swallow the error message*/
5552 mono_error_cleanup (error
);
5554 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, i
+ 1);
5558 classes
= g_list_prepend (classes
, nclass
);
5560 i
= mono_metadata_nesting_typedef (klass
->image
, klass
->type_token
, i
+ 1);
5563 nested_classes
= NULL
;
5564 for (l
= classes
; l
; l
= l
->next
)
5565 nested_classes
= mono_g_list_prepend_image (klass
->image
, nested_classes
, l
->data
);
5566 g_list_free (classes
);
5568 mono_loader_lock ();
5569 if (!klass
->nested_classes_inited
) {
5570 mono_class_set_nested_classes_property (klass
, nested_classes
);
5571 mono_memory_barrier ();
5572 klass
->nested_classes_inited
= TRUE
;
5574 mono_loader_unlock ();
5578 * mono_class_setup_runtime_info:
5579 * \param klass the class to setup
5580 * \param domain the domain of the \p vtable
5583 * Store \p vtable in \c klass->runtime_info.
5585 * Sets the following field in MonoClass:
5588 * LOCKING: domain lock and loaderlock must be held.
5591 mono_class_setup_runtime_info (MonoClass
*klass
, MonoDomain
*domain
, MonoVTable
*vtable
)
5593 MonoClassRuntimeInfo
*old_info
= m_class_get_runtime_info (klass
);
5594 if (old_info
&& old_info
->max_domain
>= domain
->domain_id
) {
5595 /* someone already created a large enough runtime info */
5596 old_info
->domain_vtables
[domain
->domain_id
] = vtable
;
5598 int new_size
= domain
->domain_id
;
5600 new_size
= MAX (new_size
, old_info
->max_domain
);
5602 /* make the new size a power of two */
5604 while (new_size
> i
)
5607 /* this is a bounded memory retention issue: may want to
5608 * handle it differently when we'll have a rcu-like system.
5610 MonoClassRuntimeInfo
*runtime_info
= (MonoClassRuntimeInfo
*)mono_image_alloc0 (m_class_get_image (klass
), MONO_SIZEOF_CLASS_RUNTIME_INFO
+ new_size
* sizeof (gpointer
));
5611 runtime_info
->max_domain
= new_size
- 1;
5612 /* copy the stuff from the older info */
5614 memcpy (runtime_info
->domain_vtables
, old_info
->domain_vtables
, (old_info
->max_domain
+ 1) * sizeof (gpointer
));
5616 runtime_info
->domain_vtables
[domain
->domain_id
] = vtable
;
5618 mono_memory_barrier ();
5619 klass
->runtime_info
= runtime_info
;
5624 * mono_class_create_array_fill_type:
5626 * Returns a \c MonoClass that is used by SGen to fill out nursery fragments before a collection.
5629 mono_class_create_array_fill_type (void)
5631 static MonoClass klass
;
5632 static gboolean inited
= FALSE
;
5635 klass
.element_class
= mono_defaults
.int64_class
;
5637 klass
.instance_size
= MONO_SIZEOF_MONO_ARRAY
;
5638 klass
.sizes
.element_size
= 8;
5639 klass
.size_inited
= 1;
5640 klass
.name
= "array_filler_type";
5648 * mono_classes_init:
5650 * Initialize the resources used by this module.
5651 * Known racy counters: `class_gparam_count`, `classes_size` and `mono_inflated_methods_size`
5653 MONO_NO_SANITIZE_THREAD
5655 mono_classes_init (void)
5657 mono_os_mutex_init (&classes_mutex
);
5659 mono_native_tls_alloc (&setup_fields_tls_id
, NULL
);
5660 mono_native_tls_alloc (&init_pending_tls_id
, NULL
);
5662 mono_counters_register ("MonoClassDef count",
5663 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_def_count
);
5664 mono_counters_register ("MonoClassGtd count",
5665 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_gtd_count
);
5666 mono_counters_register ("MonoClassGenericInst count",
5667 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_ginst_count
);
5668 mono_counters_register ("MonoClassGenericParam count",
5669 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_gparam_count
);
5670 mono_counters_register ("MonoClassArray count",
5671 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_array_count
);
5672 mono_counters_register ("MonoClassPointer count",
5673 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &class_pointer_count
);
5674 mono_counters_register ("Inflated methods size",
5675 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &mono_inflated_methods_size
);
5676 mono_counters_register ("Inflated classes size",
5677 MONO_COUNTER_GENERICS
| MONO_COUNTER_INT
, &inflated_classes_size
);
5678 mono_counters_register ("MonoClass size",
5679 MONO_COUNTER_METADATA
| MONO_COUNTER_INT
, &classes_size
);
5683 * mono_classes_cleanup:
5685 * Free the resources used by this module.
5688 mono_classes_cleanup (void)
5690 mono_native_tls_free (setup_fields_tls_id
);
5691 mono_native_tls_free (init_pending_tls_id
);
5693 if (global_interface_bitset
)
5694 mono_bitset_free (global_interface_bitset
);
5695 global_interface_bitset
= NULL
;
5696 mono_os_mutex_destroy (&classes_mutex
);