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