Improve "Could not resolve type with token" exception message
[mono-project.git] / mono / metadata / class.c
blobc9ca58da07aebde97f4c27656c5090054fb4d52c
1 /*
2 * class.c: Class management for the Mono runtime
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 #include <config.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16 #include <glib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <mono/metadata/image.h>
21 #include <mono/metadata/image-internals.h>
22 #include <mono/metadata/assembly.h>
23 #include <mono/metadata/assembly-internals.h>
24 #include <mono/metadata/metadata.h>
25 #include <mono/metadata/metadata-internals.h>
26 #include <mono/metadata/profiler-private.h>
27 #include <mono/metadata/tabledefs.h>
28 #include <mono/metadata/tokentype.h>
29 #include <mono/metadata/class-internals.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/appdomain.h>
32 #include <mono/metadata/mono-endian.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/reflection.h>
35 #include <mono/metadata/exception.h>
36 #include <mono/metadata/security-manager.h>
37 #include <mono/metadata/security-core-clr.h>
38 #include <mono/metadata/attrdefs.h>
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/mono-debug.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-string.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-logger-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/atomic.h>
48 #include <mono/utils/bsearch.h>
49 #include <mono/utils/checked-build.h>
51 MonoStats mono_stats;
53 gboolean mono_print_vtable = FALSE;
54 gboolean mono_align_small_structs = FALSE;
56 /* Statistics */
57 guint32 inflated_classes_size, inflated_methods_size;
58 guint32 classes_size, class_ext_size, class_ext_count;
59 guint32 class_def_count, class_gtd_count, class_ginst_count, class_gparam_count, class_array_count, class_pointer_count;
61 /* Low level lock which protects data structures in this module */
62 static mono_mutex_t classes_mutex;
64 /* Function supplied by the runtime to find classes by name using information from the AOT file */
65 static MonoGetClassFromName get_class_from_name = NULL;
67 static MonoClass * mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error);
68 static gboolean mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res);
69 static gboolean can_access_type (MonoClass *access_klass, MonoClass *member_klass);
70 static MonoMethod* find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags);
71 static int generic_array_methods (MonoClass *klass);
72 static void setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos);
74 static MonoMethod* mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter);
75 static char* mono_assembly_name_from_token (MonoImage *image, guint32 type_token);
76 static void mono_field_resolve_type (MonoClassField *field, MonoError *error);
77 static guint32 mono_field_resolve_flags (MonoClassField *field);
78 static void mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup);
79 static void mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gklass);
81 static gboolean mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error);
85 We use gclass recording to allow recursive system f types to be referenced by a parent.
87 Given the following type hierarchy:
89 class TextBox : TextBoxBase<TextBox> {}
90 class TextBoxBase<T> : TextInput<TextBox> where T : TextBoxBase<T> {}
91 class TextInput<T> : Input<T> where T: TextInput<T> {}
92 class Input<T> {}
94 The runtime tries to load TextBoxBase<>.
95 To load TextBoxBase<> to do so it must resolve the parent which is TextInput<TextBox>.
96 To instantiate TextInput<TextBox> it must resolve TextInput<> and TextBox.
97 To load TextBox it must resolve the parent which is TextBoxBase<TextBox>.
99 At this point the runtime must instantiate TextBoxBase<TextBox>. Both types are partially loaded
100 at this point, iow, both are registered in the type map and both and a NULL parent. This means
101 that the resulting generic instance will have a NULL parent, which is wrong and will cause breakage.
103 To fix that what we do is to record all generic instantes created while resolving the parent of
104 any generic type definition and, after resolved, correct the parent field if needed.
107 static int record_gclass_instantiation;
108 static GSList *gclass_recorded_list;
109 typedef gboolean (*gclass_record_func) (MonoClass*, void*);
111 /* This TLS variable points to a GSList of classes which have setup_fields () executing */
112 static MonoNativeTlsKey setup_fields_tls_id;
114 static MonoNativeTlsKey init_pending_tls_id;
116 static inline void
117 classes_lock (void)
119 mono_locks_os_acquire (&classes_mutex, ClassesLock);
122 static inline void
123 classes_unlock (void)
125 mono_locks_os_release (&classes_mutex, ClassesLock);
129 * LOCKING: loader lock must be held until pairing disable_gclass_recording is called.
131 static void
132 enable_gclass_recording (void)
134 ++record_gclass_instantiation;
138 * LOCKING: loader lock must be held since pairing enable_gclass_recording was called.
140 static void
141 disable_gclass_recording (gclass_record_func func, void *user_data)
143 GSList **head = &gclass_recorded_list;
145 g_assert (record_gclass_instantiation > 0);
146 --record_gclass_instantiation;
148 while (*head) {
149 GSList *node = *head;
150 if (func ((MonoClass*)node->data, user_data)) {
151 *head = node->next;
152 g_slist_free_1 (node);
153 } else {
154 head = &node->next;
158 /* We automatically discard all recorded gclasses when disabled. */
159 if (!record_gclass_instantiation && gclass_recorded_list) {
160 g_slist_free (gclass_recorded_list);
161 gclass_recorded_list = NULL;
166 * mono_class_from_typeref:
167 * @image: a MonoImage
168 * @type_token: a TypeRef token
170 * Creates the MonoClass* structure representing the type defined by
171 * the typeref token valid inside @image.
172 * Returns: The MonoClass* representing the typeref token, NULL ifcould
173 * not be loaded.
175 MonoClass *
176 mono_class_from_typeref (MonoImage *image, guint32 type_token)
178 MonoError error;
179 MonoClass *klass = mono_class_from_typeref_checked (image, type_token, &error);
180 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
181 return klass;
185 * mono_class_from_typeref_checked:
186 * @image: a MonoImage
187 * @type_token: a TypeRef token
188 * @error: error return code, if any.
190 * Creates the MonoClass* structure representing the type defined by
191 * the typeref token valid inside @image.
193 * Returns: The MonoClass* representing the typeref token, NULL if it could
194 * not be loaded with the @error value filled with the information about the
195 * error.
197 MonoClass *
198 mono_class_from_typeref_checked (MonoImage *image, guint32 type_token, MonoError *error)
200 guint32 cols [MONO_TYPEREF_SIZE];
201 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
202 guint32 idx;
203 const char *name, *nspace;
204 MonoClass *res = NULL;
205 MonoImage *module;
207 mono_error_init (error);
209 if (!mono_verifier_verify_typeref_row (image, (type_token & 0xffffff) - 1, error))
210 return NULL;
212 mono_metadata_decode_row (t, (type_token&0xffffff)-1, cols, MONO_TYPEREF_SIZE);
214 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
215 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
217 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
218 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
219 case MONO_RESOLUTION_SCOPE_MODULE:
221 LAMESPEC The spec says that a null module resolution scope should go through the exported type table.
222 This is not the observed behavior of existing implementations.
223 The defacto behavior is that it's just a typedef in disguise.
225 /* a typedef in disguise */
226 res = mono_class_from_name_checked (image, nspace, name, error);
227 goto done;
229 case MONO_RESOLUTION_SCOPE_MODULEREF:
230 module = mono_image_load_module_checked (image, idx, error);
231 if (module)
232 res = mono_class_from_name_checked (module, nspace, name, error);
233 goto done;
235 case MONO_RESOLUTION_SCOPE_TYPEREF: {
236 MonoClass *enclosing;
237 GList *tmp;
239 if (idx == mono_metadata_token_index (type_token)) {
240 mono_error_set_bad_image (error, image, "Image with self-referencing typeref token %08x.", type_token);
241 return NULL;
244 enclosing = mono_class_from_typeref_checked (image, MONO_TOKEN_TYPE_REF | idx, error);
245 return_val_if_nok (error, NULL);
247 GList *nested_classes = mono_class_get_nested_classes_property (enclosing);
248 if (enclosing->nested_classes_inited && nested_classes) {
249 /* Micro-optimization: don't scan the metadata tables if enclosing is already inited */
250 for (tmp = nested_classes; tmp; tmp = tmp->next) {
251 res = (MonoClass *)tmp->data;
252 if (strcmp (res->name, name) == 0)
253 return res;
255 } else {
256 /* Don't call mono_class_init as we might've been called by it recursively */
257 int i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, 1);
258 while (i) {
259 guint32 class_nested = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, MONO_NESTED_CLASS_NESTED);
260 guint32 string_offset = mono_metadata_decode_row_col (&enclosing->image->tables [MONO_TABLE_TYPEDEF], class_nested - 1, MONO_TYPEDEF_NAME);
261 const char *nname = mono_metadata_string_heap (enclosing->image, string_offset);
263 if (strcmp (nname, name) == 0)
264 return mono_class_create_from_typedef (enclosing->image, MONO_TOKEN_TYPE_DEF | class_nested, error);
266 i = mono_metadata_nesting_typedef (enclosing->image, enclosing->type_token, i + 1);
269 g_warning ("TypeRef ResolutionScope not yet handled (%d) for %s.%s in image %s", idx, nspace, name, image->name);
270 goto done;
272 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
273 break;
276 if (idx > image->tables [MONO_TABLE_ASSEMBLYREF].rows) {
277 mono_error_set_bad_image (error, image, "Image with invalid assemblyref token %08x.", idx);
278 return NULL;
281 if (!image->references || !image->references [idx - 1])
282 mono_assembly_load_reference (image, idx - 1);
283 g_assert (image->references [idx - 1]);
285 /* If the assembly did not load, register this as a type load exception */
286 if (image->references [idx - 1] == REFERENCE_MISSING){
287 MonoAssemblyName aname;
288 char *human_name;
290 mono_assembly_get_assemblyref (image, idx - 1, &aname);
291 human_name = mono_stringify_assembly_name (&aname);
292 mono_error_set_assembly_load_simple (error, human_name, image->assembly ? image->assembly->ref_only : FALSE);
293 return NULL;
296 res = mono_class_from_name_checked (image->references [idx - 1]->image, nspace, name, error);
298 done:
299 /* Generic case, should be avoided for when a better error is possible. */
300 if (!res && mono_error_ok (error)) {
301 char *name = mono_class_name_from_token (image, type_token);
302 char *assembly = mono_assembly_name_from_token (image, type_token);
303 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x (from typeref, class/assembly %s, %s)", type_token, name, assembly);
305 return res;
309 static void *
310 mono_image_memdup (MonoImage *image, void *data, guint size)
312 void *res = mono_image_alloc (image, size);
313 memcpy (res, data, size);
314 return res;
317 /* Copy everything mono_metadata_free_array free. */
318 MonoArrayType *
319 mono_dup_array_type (MonoImage *image, MonoArrayType *a)
321 if (image) {
322 a = (MonoArrayType *)mono_image_memdup (image, a, sizeof (MonoArrayType));
323 if (a->sizes)
324 a->sizes = (int *)mono_image_memdup (image, a->sizes, a->numsizes * sizeof (int));
325 if (a->lobounds)
326 a->lobounds = (int *)mono_image_memdup (image, a->lobounds, a->numlobounds * sizeof (int));
327 } else {
328 a = (MonoArrayType *)g_memdup (a, sizeof (MonoArrayType));
329 if (a->sizes)
330 a->sizes = (int *)g_memdup (a->sizes, a->numsizes * sizeof (int));
331 if (a->lobounds)
332 a->lobounds = (int *)g_memdup (a->lobounds, a->numlobounds * sizeof (int));
334 return a;
337 /* Copy everything mono_metadata_free_method_signature free. */
338 MonoMethodSignature*
339 mono_metadata_signature_deep_dup (MonoImage *image, MonoMethodSignature *sig)
341 int i;
343 sig = mono_metadata_signature_dup_full (image, sig);
345 sig->ret = mono_metadata_type_dup (image, sig->ret);
346 for (i = 0; i < sig->param_count; ++i)
347 sig->params [i] = mono_metadata_type_dup (image, sig->params [i]);
349 return sig;
352 static void
353 _mono_type_get_assembly_name (MonoClass *klass, GString *str)
355 MonoAssembly *ta = klass->image->assembly;
356 char *name;
358 name = mono_stringify_assembly_name (&ta->aname);
359 g_string_append_printf (str, ", %s", name);
360 g_free (name);
363 static inline void
364 mono_type_name_check_byref (MonoType *type, GString *str)
366 if (type->byref)
367 g_string_append_c (str, '&');
371 * mono_identifier_escape_type_name_chars:
372 * @str: a destination string
373 * @identifier: an IDENTIFIER in internal form
375 * Returns: str.
377 * The displayed form of the identifier is appended to str.
379 * The displayed form of an identifier has the characters ,+&*[]\
380 * that have special meaning in type names escaped with a preceeding
381 * backslash (\) character.
383 static GString*
384 mono_identifier_escape_type_name_chars (GString* str, const char* identifier)
386 if (!identifier)
387 return str;
389 size_t n = str->len;
390 // reserve space for common case: there will be no escaped characters.
391 g_string_set_size(str, n + strlen(identifier));
392 g_string_set_size(str, n);
394 for (const char* s = identifier; *s != 0 ; s++) {
395 switch (*s) {
396 case ',':
397 case '+':
398 case '&':
399 case '*':
400 case '[':
401 case ']':
402 case '\\':
403 g_string_append_c (str, '\\');
404 g_string_append_c (str, *s);
405 break;
406 default:
407 g_string_append_c (str, *s);
408 break;
411 return str;
414 static void
415 mono_type_get_name_recurse (MonoType *type, GString *str, gboolean is_recursed,
416 MonoTypeNameFormat format)
418 MonoClass *klass;
420 switch (type->type) {
421 case MONO_TYPE_ARRAY: {
422 int i, rank = type->data.array->rank;
423 MonoTypeNameFormat nested_format;
425 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
426 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
428 mono_type_get_name_recurse (
429 &type->data.array->eklass->byval_arg, str, FALSE, nested_format);
430 g_string_append_c (str, '[');
431 if (rank == 1)
432 g_string_append_c (str, '*');
433 for (i = 1; i < rank; i++)
434 g_string_append_c (str, ',');
435 g_string_append_c (str, ']');
437 mono_type_name_check_byref (type, str);
439 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
440 _mono_type_get_assembly_name (type->data.array->eklass, str);
441 break;
443 case MONO_TYPE_SZARRAY: {
444 MonoTypeNameFormat nested_format;
446 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
447 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
449 mono_type_get_name_recurse (
450 &type->data.klass->byval_arg, str, FALSE, nested_format);
451 g_string_append (str, "[]");
453 mono_type_name_check_byref (type, str);
455 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
456 _mono_type_get_assembly_name (type->data.klass, str);
457 break;
459 case MONO_TYPE_PTR: {
460 MonoTypeNameFormat nested_format;
462 nested_format = format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED ?
463 MONO_TYPE_NAME_FORMAT_FULL_NAME : format;
465 mono_type_get_name_recurse (
466 type->data.type, str, FALSE, nested_format);
467 g_string_append_c (str, '*');
469 mono_type_name_check_byref (type, str);
471 if (format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)
472 _mono_type_get_assembly_name (mono_class_from_mono_type (type->data.type), str);
473 break;
475 case MONO_TYPE_VAR:
476 case MONO_TYPE_MVAR:
477 if (!mono_generic_param_info (type->data.generic_param))
478 g_string_append_printf (str, "%s%d", type->type == MONO_TYPE_VAR ? "!" : "!!", type->data.generic_param->num);
479 else
480 g_string_append (str, mono_generic_param_info (type->data.generic_param)->name);
482 mono_type_name_check_byref (type, str);
484 break;
485 default:
486 klass = mono_class_from_mono_type (type);
487 if (klass->nested_in) {
488 mono_type_get_name_recurse (
489 &klass->nested_in->byval_arg, str, TRUE, format);
490 if (format == MONO_TYPE_NAME_FORMAT_IL)
491 g_string_append_c (str, '.');
492 else
493 g_string_append_c (str, '+');
494 } else if (*klass->name_space) {
495 if (format == MONO_TYPE_NAME_FORMAT_IL)
496 g_string_append (str, klass->name_space);
497 else
498 mono_identifier_escape_type_name_chars (str, klass->name_space);
499 g_string_append_c (str, '.');
501 if (format == MONO_TYPE_NAME_FORMAT_IL) {
502 char *s = strchr (klass->name, '`');
503 int len = s ? s - klass->name : strlen (klass->name);
504 g_string_append_len (str, klass->name, len);
505 } else {
506 mono_identifier_escape_type_name_chars (str, klass->name);
508 if (is_recursed)
509 break;
510 if (mono_class_is_ginst (klass)) {
511 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
512 MonoGenericInst *inst = gclass->context.class_inst;
513 MonoTypeNameFormat nested_format;
514 int i;
516 nested_format = format == MONO_TYPE_NAME_FORMAT_FULL_NAME ?
517 MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED : format;
519 if (format == MONO_TYPE_NAME_FORMAT_IL)
520 g_string_append_c (str, '<');
521 else
522 g_string_append_c (str, '[');
523 for (i = 0; i < inst->type_argc; i++) {
524 MonoType *t = inst->type_argv [i];
526 if (i)
527 g_string_append_c (str, ',');
528 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
529 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
530 g_string_append_c (str, '[');
531 mono_type_get_name_recurse (inst->type_argv [i], str, FALSE, nested_format);
532 if ((nested_format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
533 (t->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
534 g_string_append_c (str, ']');
536 if (format == MONO_TYPE_NAME_FORMAT_IL)
537 g_string_append_c (str, '>');
538 else
539 g_string_append_c (str, ']');
540 } else if (mono_class_is_gtd (klass) &&
541 (format != MONO_TYPE_NAME_FORMAT_FULL_NAME) &&
542 (format != MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED)) {
543 int i;
545 if (format == MONO_TYPE_NAME_FORMAT_IL)
546 g_string_append_c (str, '<');
547 else
548 g_string_append_c (str, '[');
549 for (i = 0; i < mono_class_get_generic_container (klass)->type_argc; i++) {
550 if (i)
551 g_string_append_c (str, ',');
552 g_string_append (str, mono_generic_container_get_param_info (mono_class_get_generic_container (klass), i)->name);
554 if (format == MONO_TYPE_NAME_FORMAT_IL)
555 g_string_append_c (str, '>');
556 else
557 g_string_append_c (str, ']');
560 mono_type_name_check_byref (type, str);
562 if ((format == MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED) &&
563 (type->type != MONO_TYPE_VAR) && (type->type != MONO_TYPE_MVAR))
564 _mono_type_get_assembly_name (klass, str);
565 break;
570 * mono_type_get_name_full:
571 * @type: a type
572 * @format: the format for the return string.
575 * Returns: The string representation in a number of formats:
577 * if format is MONO_TYPE_NAME_FORMAT_REFLECTION, the return string is
578 * returned in the formatrequired by System.Reflection, this is the
579 * inverse of mono_reflection_parse_type ().
581 * if format is MONO_TYPE_NAME_FORMAT_IL, it returns a syntax that can
582 * be used by the IL assembler.
584 * if format is MONO_TYPE_NAME_FORMAT_FULL_NAME
586 * if format is MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED
588 char*
589 mono_type_get_name_full (MonoType *type, MonoTypeNameFormat format)
591 GString* result;
593 result = g_string_new ("");
595 mono_type_get_name_recurse (type, result, FALSE, format);
597 return g_string_free (result, FALSE);
601 * mono_type_get_full_name:
602 * @class: a class
604 * Returns: The string representation for type as required by System.Reflection.
605 * The inverse of mono_reflection_parse_type ().
607 char *
608 mono_type_get_full_name (MonoClass *klass)
610 return mono_type_get_name_full (mono_class_get_type (klass), MONO_TYPE_NAME_FORMAT_REFLECTION);
614 * mono_type_get_name:
615 * @type: a type
617 * Returns: The string representation for type as it would be represented in IL code.
619 char*
620 mono_type_get_name (MonoType *type)
622 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL);
626 * mono_type_get_underlying_type:
627 * @type: a type
629 * Returns: The MonoType for the underlying integer type if @type
630 * is an enum and byref is false, otherwise the type itself.
632 MonoType*
633 mono_type_get_underlying_type (MonoType *type)
635 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype && !type->byref)
636 return mono_class_enum_basetype (type->data.klass);
637 if (type->type == MONO_TYPE_GENERICINST && type->data.generic_class->container_class->enumtype && !type->byref)
638 return mono_class_enum_basetype (type->data.generic_class->container_class);
639 return type;
643 * mono_class_is_open_constructed_type:
644 * @type: a type
646 * Returns: TRUE if type represents a generics open constructed type.
647 * IOW, not all type parameters required for the instantiation have
648 * been provided or it's a generic type definition.
650 * An open constructed type means it's a non realizable type. Not to
651 * be mixed up with an abstract type - we can't cast or dispatch to
652 * an open type, for example.
654 gboolean
655 mono_class_is_open_constructed_type (MonoType *t)
657 switch (t->type) {
658 case MONO_TYPE_VAR:
659 case MONO_TYPE_MVAR:
660 return TRUE;
661 case MONO_TYPE_SZARRAY:
662 return mono_class_is_open_constructed_type (&t->data.klass->byval_arg);
663 case MONO_TYPE_ARRAY:
664 return mono_class_is_open_constructed_type (&t->data.array->eklass->byval_arg);
665 case MONO_TYPE_PTR:
666 return mono_class_is_open_constructed_type (t->data.type);
667 case MONO_TYPE_GENERICINST:
668 return t->data.generic_class->context.class_inst->is_open;
669 case MONO_TYPE_CLASS:
670 case MONO_TYPE_VALUETYPE:
671 return mono_class_is_gtd (t->data.klass);
672 default:
673 return FALSE;
678 This is a simple function to catch the most common bad instances of generic types.
679 Specially those that might lead to further failures in the runtime.
681 static gboolean
682 is_valid_generic_argument (MonoType *type)
684 switch (type->type) {
685 case MONO_TYPE_VOID:
686 //case MONO_TYPE_TYPEDBYREF:
687 return FALSE;
688 default:
689 return TRUE;
693 static MonoType*
694 inflate_generic_type (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
696 mono_error_init (error);
698 switch (type->type) {
699 case MONO_TYPE_MVAR: {
700 MonoType *nt;
701 int num = mono_type_get_generic_param_num (type);
702 MonoGenericInst *inst = context->method_inst;
703 if (!inst)
704 return NULL;
705 if (num >= inst->type_argc) {
706 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
707 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded in this context with %d instantiations",
708 num, info ? info->name : "", inst->type_argc);
709 return NULL;
712 if (!is_valid_generic_argument (inst->type_argv [num])) {
713 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
714 mono_error_set_bad_image (error, image, "MVAR %d (%s) cannot be expanded with type 0x%x",
715 num, info ? info->name : "", inst->type_argv [num]->type);
716 return NULL;
719 * Note that the VAR/MVAR cases are different from the rest. The other cases duplicate @type,
720 * while the VAR/MVAR duplicates a type from the context. So, we need to ensure that the
721 * ->byref and ->attrs from @type are propagated to the returned type.
723 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
724 nt->byref = type->byref;
725 nt->attrs = type->attrs;
726 return nt;
728 case MONO_TYPE_VAR: {
729 MonoType *nt;
730 int num = mono_type_get_generic_param_num (type);
731 MonoGenericInst *inst = context->class_inst;
732 if (!inst)
733 return NULL;
734 if (num >= inst->type_argc) {
735 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
736 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded in this context with %d instantiations",
737 num, info ? info->name : "", inst->type_argc);
738 return NULL;
740 if (!is_valid_generic_argument (inst->type_argv [num])) {
741 MonoGenericParamInfo *info = mono_generic_param_info (type->data.generic_param);
742 mono_error_set_bad_image (error, image, "VAR %d (%s) cannot be expanded with type 0x%x",
743 num, info ? info->name : "", inst->type_argv [num]->type);
744 return NULL;
746 nt = mono_metadata_type_dup (image, inst->type_argv [num]);
747 nt->byref = type->byref;
748 nt->attrs = type->attrs;
749 return nt;
751 case MONO_TYPE_SZARRAY: {
752 MonoClass *eclass = type->data.klass;
753 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
754 if (!inflated || !mono_error_ok (error))
755 return NULL;
756 nt = mono_metadata_type_dup (image, type);
757 nt->data.klass = mono_class_from_mono_type (inflated);
758 mono_metadata_free_type (inflated);
759 return nt;
761 case MONO_TYPE_ARRAY: {
762 MonoClass *eclass = type->data.array->eklass;
763 MonoType *nt, *inflated = inflate_generic_type (NULL, &eclass->byval_arg, context, error);
764 if (!inflated || !mono_error_ok (error))
765 return NULL;
766 nt = mono_metadata_type_dup (image, type);
767 nt->data.array->eklass = mono_class_from_mono_type (inflated);
768 mono_metadata_free_type (inflated);
769 return nt;
771 case MONO_TYPE_GENERICINST: {
772 MonoGenericClass *gclass = type->data.generic_class;
773 MonoGenericInst *inst;
774 MonoType *nt;
775 if (!gclass->context.class_inst->is_open)
776 return NULL;
778 inst = mono_metadata_inflate_generic_inst (gclass->context.class_inst, context, error);
779 return_val_if_nok (error, NULL);
781 if (inst != gclass->context.class_inst)
782 gclass = mono_metadata_lookup_generic_class (gclass->container_class, inst, gclass->is_dynamic);
784 if (gclass == type->data.generic_class)
785 return NULL;
787 nt = mono_metadata_type_dup (image, type);
788 nt->data.generic_class = gclass;
789 return nt;
791 case MONO_TYPE_CLASS:
792 case MONO_TYPE_VALUETYPE: {
793 MonoClass *klass = type->data.klass;
794 MonoGenericContainer *container = mono_class_try_get_generic_container (klass);
795 MonoGenericInst *inst;
796 MonoGenericClass *gclass = NULL;
797 MonoType *nt;
799 if (!container)
800 return NULL;
802 /* We can't use context->class_inst directly, since it can have more elements */
803 inst = mono_metadata_inflate_generic_inst (container->context.class_inst, context, error);
804 return_val_if_nok (error, NULL);
806 if (inst == container->context.class_inst)
807 return NULL;
809 gclass = mono_metadata_lookup_generic_class (klass, inst, image_is_dynamic (klass->image));
811 nt = mono_metadata_type_dup (image, type);
812 nt->type = MONO_TYPE_GENERICINST;
813 nt->data.generic_class = gclass;
814 return nt;
816 default:
817 return NULL;
819 return NULL;
822 MonoGenericContext *
823 mono_generic_class_get_context (MonoGenericClass *gclass)
825 return &gclass->context;
828 MonoGenericContext *
829 mono_class_get_context (MonoClass *klass)
831 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
832 return gklass ? mono_generic_class_get_context (gklass) : NULL;
836 * mono_class_inflate_generic_type_with_mempool:
837 * @mempool: a mempool
838 * @type: a type
839 * @context: a generics context
840 * @error: error context
842 * The same as mono_class_inflate_generic_type, but allocates the MonoType
843 * from mempool if it is non-NULL. If it is NULL, the MonoType is
844 * allocated on the heap and is owned by the caller.
845 * The returned type can potentially be the same as TYPE, so it should not be
846 * modified by the caller, and it should be freed using mono_metadata_free_type ().
848 MonoType*
849 mono_class_inflate_generic_type_with_mempool (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
851 MonoType *inflated = NULL;
852 mono_error_init (error);
854 if (context)
855 inflated = inflate_generic_type (image, type, context, error);
856 return_val_if_nok (error, NULL);
858 if (!inflated) {
859 MonoType *shared = mono_metadata_get_shared_type (type);
861 if (shared) {
862 return shared;
863 } else {
864 return mono_metadata_type_dup (image, type);
868 mono_stats.inflated_type_count++;
869 return inflated;
873 * mono_class_inflate_generic_type:
874 * @type: a type
875 * @context: a generics context
877 * If @type is a generic type and @context is not NULL, instantiate it using the
878 * generics context @context.
880 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
881 * on the heap and is owned by the caller. Returns NULL on error.
883 * @deprecated Please use mono_class_inflate_generic_type_checked instead
885 MonoType*
886 mono_class_inflate_generic_type (MonoType *type, MonoGenericContext *context)
888 MonoError error;
889 MonoType *result;
890 result = mono_class_inflate_generic_type_checked (type, context, &error);
891 mono_error_cleanup (&error);
892 return result;
896 * mono_class_inflate_generic_type:
897 * @type: a type
898 * @context: a generics context
899 * @error: error context to use
901 * If @type is a generic type and @context is not NULL, instantiate it using the
902 * generics context @context.
904 * Returns: The instantiated type or a copy of @type. The returned MonoType is allocated
905 * on the heap and is owned by the caller.
907 MonoType*
908 mono_class_inflate_generic_type_checked (MonoType *type, MonoGenericContext *context, MonoError *error)
910 return mono_class_inflate_generic_type_with_mempool (NULL, type, context, error);
914 * mono_class_inflate_generic_type_no_copy:
916 * Same as inflate_generic_type_with_mempool, but return TYPE if no inflation
917 * was done.
919 static MonoType*
920 mono_class_inflate_generic_type_no_copy (MonoImage *image, MonoType *type, MonoGenericContext *context, MonoError *error)
922 MonoType *inflated = NULL;
924 mono_error_init (error);
925 if (context) {
926 inflated = inflate_generic_type (image, type, context, error);
927 return_val_if_nok (error, NULL);
930 if (!inflated)
931 return type;
933 mono_stats.inflated_type_count++;
934 return inflated;
938 * mono_class_inflate_generic_class:
940 * Inflate the class @gklass with @context. Set @error on failure.
942 MonoClass*
943 mono_class_inflate_generic_class_checked (MonoClass *gklass, MonoGenericContext *context, MonoError *error)
945 MonoClass *res;
946 MonoType *inflated;
948 inflated = mono_class_inflate_generic_type_checked (&gklass->byval_arg, context, error);
949 return_val_if_nok (error, NULL);
951 res = mono_class_from_mono_type (inflated);
952 mono_metadata_free_type (inflated);
954 return res;
957 static MonoGenericContext
958 inflate_generic_context (MonoGenericContext *context, MonoGenericContext *inflate_with, MonoError *error)
960 MonoGenericInst *class_inst = NULL;
961 MonoGenericInst *method_inst = NULL;
962 MonoGenericContext res = { NULL, NULL };
964 mono_error_init (error);
966 if (context->class_inst) {
967 class_inst = mono_metadata_inflate_generic_inst (context->class_inst, inflate_with, error);
968 if (!mono_error_ok (error))
969 goto fail;
972 if (context->method_inst) {
973 method_inst = mono_metadata_inflate_generic_inst (context->method_inst, inflate_with, error);
974 if (!mono_error_ok (error))
975 goto fail;
978 res.class_inst = class_inst;
979 res.method_inst = method_inst;
980 fail:
981 return res;
985 * mono_class_inflate_generic_method:
986 * @method: a generic method
987 * @context: a generics context
989 * Instantiate the generic method @method using the generics context @context.
991 * Returns: The new instantiated method
993 MonoMethod *
994 mono_class_inflate_generic_method (MonoMethod *method, MonoGenericContext *context)
996 return mono_class_inflate_generic_method_full (method, NULL, context);
999 MonoMethod *
1000 mono_class_inflate_generic_method_checked (MonoMethod *method, MonoGenericContext *context, MonoError *error)
1002 return mono_class_inflate_generic_method_full_checked (method, NULL, context, error);
1006 * mono_class_inflate_generic_method_full:
1008 * Instantiate method @method with the generic context @context.
1009 * BEWARE: All non-trivial fields are invalid, including klass, signature, and header.
1010 * Use mono_method_signature () and mono_method_get_header () to get the correct values.
1012 MonoMethod*
1013 mono_class_inflate_generic_method_full (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context)
1015 MonoError error;
1016 MonoMethod *res = mono_class_inflate_generic_method_full_checked (method, klass_hint, context, &error);
1017 if (!mono_error_ok (&error))
1018 /*FIXME do proper error handling - on this case, kill this function. */
1019 g_error ("Could not inflate generic method due to %s", mono_error_get_message (&error));
1021 return res;
1025 * mono_class_inflate_generic_method_full_checked:
1026 * Same as mono_class_inflate_generic_method_full but return failure using @error.
1028 MonoMethod*
1029 mono_class_inflate_generic_method_full_checked (MonoMethod *method, MonoClass *klass_hint, MonoGenericContext *context, MonoError *error)
1031 MonoMethod *result;
1032 MonoMethodInflated *iresult, *cached;
1033 MonoMethodSignature *sig;
1034 MonoGenericContext tmp_context;
1036 mono_error_init (error);
1038 /* The `method' has already been instantiated before => we need to peel out the instantiation and create a new context */
1039 while (method->is_inflated) {
1040 MonoGenericContext *method_context = mono_method_get_context (method);
1041 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1043 tmp_context = inflate_generic_context (method_context, context, error);
1044 return_val_if_nok (error, NULL);
1046 context = &tmp_context;
1048 if (mono_metadata_generic_context_equal (method_context, context))
1049 return method;
1051 method = imethod->declaring;
1055 * A method only needs to be inflated if the context has argument for which it is
1056 * parametric. Eg:
1058 * class Foo<T> { void Bar(); } - doesn't need to be inflated if only mvars' are supplied
1059 * class Foo { void Bar<T> (); } - doesn't need to be if only vars' are supplied
1062 if (!((method->is_generic && context->method_inst) ||
1063 (mono_class_is_gtd (method->klass) && context->class_inst)))
1064 return method;
1066 iresult = g_new0 (MonoMethodInflated, 1);
1067 iresult->context = *context;
1068 iresult->declaring = method;
1070 if (!context->method_inst && method->is_generic)
1071 iresult->context.method_inst = mono_method_get_generic_container (method)->context.method_inst;
1073 if (!context->class_inst) {
1074 g_assert (!mono_class_is_ginst (iresult->declaring->klass));
1075 if (mono_class_is_gtd (iresult->declaring->klass))
1076 iresult->context.class_inst = mono_class_get_generic_container (iresult->declaring->klass)->context.class_inst;
1078 /* This can happen with some callers like mono_object_get_virtual_method () */
1079 if (!mono_class_is_gtd (iresult->declaring->klass) && !mono_class_is_ginst (iresult->declaring->klass))
1080 iresult->context.class_inst = NULL;
1082 MonoImageSet *set = mono_metadata_get_image_set_for_method (iresult);
1084 // check cache
1085 mono_image_set_lock (set);
1086 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1087 mono_image_set_unlock (set);
1089 if (cached) {
1090 g_free (iresult);
1091 return (MonoMethod*)cached;
1094 mono_stats.inflated_method_count++;
1096 inflated_methods_size += sizeof (MonoMethodInflated);
1098 sig = mono_method_signature (method);
1099 if (!sig) {
1100 char *name = mono_type_get_full_name (method->klass);
1101 mono_error_set_bad_image (error, method->klass->image, "Could not resolve signature of method %s:%s", name, method->name);
1102 g_free (name);
1103 goto fail;
1106 if (sig->pinvoke) {
1107 memcpy (&iresult->method.pinvoke, method, sizeof (MonoMethodPInvoke));
1108 } else {
1109 memcpy (&iresult->method.method, method, sizeof (MonoMethod));
1112 result = (MonoMethod *) iresult;
1113 result->is_inflated = TRUE;
1114 result->is_generic = FALSE;
1115 result->sre_method = FALSE;
1116 result->signature = NULL;
1118 if (method->wrapper_type) {
1119 MonoMethodWrapper *mw = (MonoMethodWrapper*)method;
1120 MonoMethodWrapper *resw = (MonoMethodWrapper*)result;
1121 int len = GPOINTER_TO_INT (((void**)mw->method_data) [0]);
1123 resw->method_data = (void **)g_malloc (sizeof (gpointer) * (len + 1));
1124 memcpy (resw->method_data, mw->method_data, sizeof (gpointer) * (len + 1));
1127 if (iresult->context.method_inst) {
1128 /* Set the generic_container of the result to the generic_container of method */
1129 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
1131 if (generic_container && iresult->context.method_inst == generic_container->context.method_inst) {
1132 result->is_generic = 1;
1133 mono_method_set_generic_container (result, generic_container);
1137 if (klass_hint) {
1138 MonoGenericClass *gklass_hint = mono_class_try_get_generic_class (klass_hint);
1139 if (gklass_hint && (gklass_hint->container_class != method->klass || gklass_hint->context.class_inst != context->class_inst))
1140 klass_hint = NULL;
1143 if (mono_class_is_gtd (method->klass))
1144 result->klass = klass_hint;
1146 if (!result->klass) {
1147 MonoType *inflated = inflate_generic_type (NULL, &method->klass->byval_arg, context, error);
1148 if (!mono_error_ok (error))
1149 goto fail;
1151 result->klass = inflated ? mono_class_from_mono_type (inflated) : method->klass;
1152 if (inflated)
1153 mono_metadata_free_type (inflated);
1157 * FIXME: This should hold, but it doesn't:
1159 * if (result->is_inflated && mono_method_get_context (result)->method_inst &&
1160 * mono_method_get_context (result)->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)result)->declaring)->context.method_inst) {
1161 * g_assert (result->is_generic);
1164 * Fixing this here causes other things to break, hence a very
1165 * ugly hack in mini-trampolines.c - see
1166 * is_generic_method_definition().
1169 // check cache
1170 mono_image_set_lock (set);
1171 cached = (MonoMethodInflated *)g_hash_table_lookup (set->gmethod_cache, iresult);
1172 if (!cached) {
1173 g_hash_table_insert (set->gmethod_cache, iresult, iresult);
1174 iresult->owner = set;
1175 cached = iresult;
1177 mono_image_set_unlock (set);
1179 return (MonoMethod*)cached;
1181 fail:
1182 g_free (iresult);
1183 return NULL;
1187 * mono_get_inflated_method:
1189 * Obsolete. We keep it around since it's mentioned in the public API.
1191 MonoMethod*
1192 mono_get_inflated_method (MonoMethod *method)
1194 return method;
1198 * mono_method_get_context_general:
1199 * @method: a method
1200 * @uninflated: handle uninflated methods?
1202 * Returns the generic context of a method or NULL if it doesn't have
1203 * one. For an inflated method that's the context stored in the
1204 * method. Otherwise it's in the method's generic container or in the
1205 * generic container of the method's class.
1207 MonoGenericContext*
1208 mono_method_get_context_general (MonoMethod *method, gboolean uninflated)
1210 if (method->is_inflated) {
1211 MonoMethodInflated *imethod = (MonoMethodInflated *) method;
1212 return &imethod->context;
1214 if (!uninflated)
1215 return NULL;
1216 if (method->is_generic)
1217 return &(mono_method_get_generic_container (method)->context);
1218 if (mono_class_is_gtd (method->klass))
1219 return &mono_class_get_generic_container (method->klass)->context;
1220 return NULL;
1224 * mono_method_get_context:
1225 * @method: a method
1227 * Returns the generic context for method if it's inflated, otherwise
1228 * NULL.
1230 MonoGenericContext*
1231 mono_method_get_context (MonoMethod *method)
1233 return mono_method_get_context_general (method, FALSE);
1237 * mono_method_get_generic_container:
1239 * Returns the generic container of METHOD, which should be a generic method definition.
1240 * Returns NULL if METHOD is not a generic method definition.
1241 * LOCKING: Acquires the loader lock.
1243 MonoGenericContainer*
1244 mono_method_get_generic_container (MonoMethod *method)
1246 MonoGenericContainer *container;
1248 if (!method->is_generic)
1249 return NULL;
1251 container = (MonoGenericContainer *)mono_image_property_lookup (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER);
1252 g_assert (container);
1254 return container;
1258 * mono_method_set_generic_container:
1260 * Sets the generic container of METHOD to CONTAINER.
1261 * LOCKING: Acquires the image lock.
1263 void
1264 mono_method_set_generic_container (MonoMethod *method, MonoGenericContainer* container)
1266 g_assert (method->is_generic);
1268 mono_image_property_insert (method->klass->image, method, MONO_METHOD_PROP_GENERIC_CONTAINER, container);
1271 /**
1272 * mono_class_find_enum_basetype:
1273 * @class: The enum class
1275 * Determine the basetype of an enum by iterating through its fields. We do this
1276 * in a separate function since it is cheaper than calling mono_class_setup_fields.
1278 static MonoType*
1279 mono_class_find_enum_basetype (MonoClass *klass, MonoError *error)
1281 MonoGenericContainer *container = NULL;
1282 MonoImage *m = klass->image;
1283 const int top = mono_class_get_field_count (klass);
1284 int i, first_field_idx;
1286 g_assert (klass->enumtype);
1288 mono_error_init (error);
1290 container = mono_class_try_get_generic_container (klass);
1291 if (mono_class_is_ginst (klass)) {
1292 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
1294 container = mono_class_get_generic_container (gklass);
1295 g_assert (container);
1299 * Fetch all the field information.
1301 first_field_idx = mono_class_get_first_field_idx (klass);
1302 for (i = 0; i < top; i++){
1303 const char *sig;
1304 guint32 cols [MONO_FIELD_SIZE];
1305 int idx = first_field_idx + i;
1306 MonoType *ftype;
1308 /* first_field_idx and idx points into the fieldptr table */
1309 mono_metadata_decode_table_row (m, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
1311 if (cols [MONO_FIELD_FLAGS] & FIELD_ATTRIBUTE_STATIC) //no need to decode static fields
1312 continue;
1314 if (!mono_verifier_verify_field_signature (klass->image, cols [MONO_FIELD_SIGNATURE], NULL)) {
1315 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x", cols [MONO_FIELD_SIGNATURE]);
1316 goto fail;
1319 sig = mono_metadata_blob_heap (m, cols [MONO_FIELD_SIGNATURE]);
1320 mono_metadata_decode_value (sig, &sig);
1321 /* FIELD signature == 0x06 */
1322 if (*sig != 0x06) {
1323 mono_error_set_bad_image (error, klass->image, "Invalid field signature %x, expected 0x6 but got %x", cols [MONO_FIELD_SIGNATURE], *sig);
1324 goto fail;
1327 ftype = mono_metadata_parse_type_checked (m, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
1328 if (!ftype)
1329 goto fail;
1331 if (mono_class_is_ginst (klass)) {
1332 //FIXME do we leak here?
1333 ftype = mono_class_inflate_generic_type_checked (ftype, mono_class_get_context (klass), error);
1334 if (!mono_error_ok (error))
1335 goto fail;
1336 ftype->attrs = cols [MONO_FIELD_FLAGS];
1339 return ftype;
1341 mono_error_set_type_load_class (error, klass, "Could not find base type");
1343 fail:
1344 return NULL;
1348 * Checks for MonoClass::has_failure without resolving all MonoType's into MonoClass'es
1350 static gboolean
1351 mono_type_has_exceptions (MonoType *type)
1353 switch (type->type) {
1354 case MONO_TYPE_CLASS:
1355 case MONO_TYPE_VALUETYPE:
1356 case MONO_TYPE_SZARRAY:
1357 return mono_class_has_failure (type->data.klass);
1358 case MONO_TYPE_ARRAY:
1359 return mono_class_has_failure (type->data.array->eklass);
1360 case MONO_TYPE_GENERICINST:
1361 return mono_class_has_failure (mono_generic_class_get_class (type->data.generic_class));
1362 default:
1363 return FALSE;
1367 void
1368 mono_error_set_for_class_failure (MonoError *oerror, const MonoClass *klass)
1370 g_assert (mono_class_has_failure (klass));
1371 MonoErrorBoxed *box = mono_class_get_exception_data ((MonoClass*)klass);
1372 mono_error_set_from_boxed (oerror, box);
1376 * mono_class_alloc:
1378 * Allocate memory for some data belonging to CLASS, either from its image's mempool,
1379 * or from the heap.
1381 gpointer
1382 mono_class_alloc (MonoClass *klass, int size)
1384 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1385 if (gklass)
1386 return mono_image_set_alloc (gklass->owner, size);
1387 else
1388 return mono_image_alloc (klass->image, size);
1391 gpointer
1392 mono_class_alloc0 (MonoClass *klass, int size)
1394 gpointer res;
1396 res = mono_class_alloc (klass, size);
1397 memset (res, 0, size);
1398 return res;
1401 #define mono_class_new0(klass,struct_type, n_structs) \
1402 ((struct_type *) mono_class_alloc0 ((klass), ((gsize) sizeof (struct_type)) * ((gsize) (n_structs))))
1405 * mono_class_setup_basic_field_info:
1406 * @class: The class to initialize
1408 * Initializes the following fields in MonoClass:
1409 * * klass->fields (only field->parent and field->name)
1410 * * klass->field.count
1411 * * klass->first_field_idx
1412 * LOCKING: Acquires the loader lock
1414 static void
1415 mono_class_setup_basic_field_info (MonoClass *klass)
1417 MonoGenericClass *gklass;
1418 MonoClassField *field;
1419 MonoClassField *fields;
1420 MonoClass *gtd;
1421 MonoImage *image;
1422 int i, top;
1424 if (klass->fields)
1425 return;
1427 gklass = mono_class_try_get_generic_class (klass);
1428 gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
1429 image = klass->image;
1432 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
1434 * This happens when a generic instance of an unfinished generic typebuilder
1435 * is used as an element type for creating an array type. We can't initialize
1436 * the fields of this class using the fields of gklass, since gklass is not
1437 * finished yet, fields could be added to it later.
1439 return;
1442 if (gtd) {
1443 mono_class_setup_basic_field_info (gtd);
1445 mono_loader_lock ();
1446 mono_class_set_field_count (klass, mono_class_get_field_count (gtd));
1447 mono_loader_unlock ();
1450 top = mono_class_get_field_count (klass);
1452 fields = (MonoClassField *)mono_class_alloc0 (klass, sizeof (MonoClassField) * top);
1455 * Fetch all the field information.
1457 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1458 for (i = 0; i < top; i++) {
1459 field = &fields [i];
1460 field->parent = klass;
1462 if (gtd) {
1463 field->name = mono_field_get_name (&gtd->fields [i]);
1464 } else {
1465 int idx = first_field_idx + i;
1466 /* first_field_idx and idx points into the fieldptr table */
1467 guint32 name_idx = mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_NAME);
1468 /* The name is needed for fieldrefs */
1469 field->name = mono_metadata_string_heap (image, name_idx);
1473 mono_memory_barrier ();
1475 mono_loader_lock ();
1476 if (!klass->fields)
1477 klass->fields = fields;
1478 mono_loader_unlock ();
1482 * mono_class_set_failure_causedby_class:
1483 * @klass: the class that is failing
1484 * @caused_by: the class that caused the failure
1485 * @msg: Why @klass is failing.
1487 * If @caused_by has a failure, sets a TypeLoadException failure on
1488 * @klass with message "@msg, due to: {@caused_by message}".
1490 * Returns: TRUE if a failiure was set, or FALSE if @caused_by doesn't have a failure.
1492 static gboolean
1493 mono_class_set_type_load_failure_causedby_class (MonoClass *klass, const MonoClass *caused_by, const gchar* msg)
1495 if (mono_class_has_failure (caused_by)) {
1496 MonoError cause_error;
1497 mono_error_init (&cause_error);
1498 mono_error_set_for_class_failure (&cause_error, caused_by);
1499 mono_class_set_type_load_failure (klass, "%s, due to: %s", msg, mono_error_get_message (&cause_error));
1500 mono_error_cleanup (&cause_error);
1501 return TRUE;
1502 } else {
1503 return FALSE;
1508 /**
1509 * mono_class_setup_fields:
1510 * @klass: The class to initialize
1512 * Initializes klass->fields, computes class layout and sizes.
1513 * typebuilder_setup_fields () is the corresponding function for dynamic classes.
1514 * Sets the following fields in @klass:
1515 * - all the fields initialized by mono_class_init_sizes ()
1516 * - element_class/cast_class (for enums)
1517 * - field->type/offset for all fields
1518 * - fields_inited
1520 * LOCKING: Acquires the loader lock.
1522 void
1523 mono_class_setup_fields (MonoClass *klass)
1525 MonoError error;
1526 MonoImage *m = klass->image;
1527 int top;
1528 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
1529 int i;
1530 guint32 real_size = 0;
1531 guint32 packing_size = 0;
1532 int instance_size;
1533 gboolean explicit_size;
1534 MonoClassField *field;
1535 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
1536 MonoClass *gtd = gklass ? mono_class_get_generic_type_definition (klass) : NULL;
1538 if (klass->fields_inited)
1539 return;
1541 if (gklass && image_is_dynamic (gklass->container_class->image) && !gklass->container_class->wastypebuilder) {
1543 * This happens when a generic instance of an unfinished generic typebuilder
1544 * is used as an element type for creating an array type. We can't initialize
1545 * the fields of this class using the fields of gklass, since gklass is not
1546 * finished yet, fields could be added to it later.
1548 return;
1551 mono_class_setup_basic_field_info (klass);
1552 top = mono_class_get_field_count (klass);
1554 if (gtd) {
1555 mono_class_setup_fields (gtd);
1556 if (mono_class_set_type_load_failure_causedby_class (klass, gtd, "Generic type definition failed"))
1557 return;
1560 instance_size = 0;
1561 if (klass->parent) {
1562 /* For generic instances, klass->parent might not have been initialized */
1563 mono_class_init (klass->parent);
1564 mono_class_setup_fields (klass->parent);
1565 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Could not set up parent class"))
1566 return;
1567 instance_size = klass->parent->instance_size;
1568 } else {
1569 instance_size = sizeof (MonoObject);
1572 /* Get the real size */
1573 explicit_size = mono_metadata_packing_from_typedef (klass->image, klass->type_token, &packing_size, &real_size);
1574 if (explicit_size)
1575 instance_size += real_size;
1578 * This function can recursively call itself.
1579 * Prevent infinite recursion by using a list in TLS.
1581 GSList *init_list = (GSList *)mono_native_tls_get_value (setup_fields_tls_id);
1582 if (g_slist_find (init_list, klass))
1583 return;
1584 init_list = g_slist_prepend (init_list, klass);
1585 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1588 * Fetch all the field information.
1590 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1591 for (i = 0; i < top; i++) {
1592 int idx = first_field_idx + i;
1593 field = &klass->fields [i];
1595 if (!field->type) {
1596 mono_field_resolve_type (field, &error);
1597 if (!mono_error_ok (&error)) {
1598 /*mono_field_resolve_type already failed class*/
1599 mono_error_cleanup (&error);
1600 break;
1602 if (!field->type)
1603 g_error ("could not resolve %s:%s\n", mono_type_get_full_name(klass), field->name);
1604 g_assert (field->type);
1607 if (mono_field_is_deleted (field))
1608 continue;
1609 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
1610 guint32 uoffset;
1611 mono_metadata_field_info (m, idx, &uoffset, NULL, NULL);
1612 int offset = uoffset;
1614 if (offset == (guint32)-1 && !(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1615 mono_class_set_type_load_failure (klass, "Missing field layout info for %s", field->name);
1616 break;
1618 if (offset < -1) { /*-1 is used to encode special static fields */
1619 mono_class_set_type_load_failure (klass, "Field '%s' has a negative offset %d", field->name, offset);
1620 break;
1622 if (mono_class_is_gtd (klass)) {
1623 mono_class_set_type_load_failure (klass, "Generic class cannot have explicit layout.");
1624 break;
1627 if (mono_type_has_exceptions (field->type)) {
1628 char *class_name = mono_type_get_full_name (klass);
1629 char *type_name = mono_type_full_name (field->type);
1631 mono_class_set_type_load_failure (klass, "");
1632 g_warning ("Invalid type %s for instance field %s:%s", type_name, class_name, field->name);
1633 g_free (class_name);
1634 g_free (type_name);
1635 break;
1637 /* The def_value of fields is compute lazily during vtable creation */
1640 if (!mono_class_has_failure (klass)) {
1641 mono_loader_lock ();
1642 mono_class_layout_fields (klass, instance_size, packing_size, FALSE);
1643 mono_loader_unlock ();
1646 init_list = g_slist_remove (init_list, klass);
1647 mono_native_tls_set_value (setup_fields_tls_id, init_list);
1650 static void
1651 init_sizes_with_info (MonoClass *klass, MonoCachedClassInfo *cached_info)
1653 if (cached_info) {
1654 mono_loader_lock ();
1655 klass->instance_size = cached_info->instance_size;
1656 klass->sizes.class_size = cached_info->class_size;
1657 klass->packing_size = cached_info->packing_size;
1658 klass->min_align = cached_info->min_align;
1659 klass->blittable = cached_info->blittable;
1660 klass->has_references = cached_info->has_references;
1661 klass->has_static_refs = cached_info->has_static_refs;
1662 klass->no_special_static_fields = cached_info->no_special_static_fields;
1663 mono_loader_unlock ();
1665 else {
1666 if (!klass->size_inited)
1667 mono_class_setup_fields (klass);
1672 * mono_class_init_sizes:
1674 * Initializes the size related fields of @klass without loading all field data if possible.
1675 * Sets the following fields in @klass:
1676 * - instance_size
1677 * - sizes.class_size
1678 * - packing_size
1679 * - min_align
1680 * - blittable
1681 * - has_references
1682 * - has_static_refs
1683 * - size_inited
1684 * Can fail the class.
1686 * LOCKING: Acquires the loader lock.
1688 static void
1689 mono_class_init_sizes (MonoClass *klass)
1691 MonoCachedClassInfo cached_info;
1692 gboolean has_cached_info;
1694 if (klass->size_inited)
1695 return;
1697 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
1699 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
1703 * mono_type_get_basic_type_from_generic:
1704 * @type: a type
1706 * Returns a closed type corresponding to the possibly open type
1707 * passed to it.
1709 MonoType*
1710 mono_type_get_basic_type_from_generic (MonoType *type)
1712 /* When we do generic sharing we let type variables stand for reference/primitive types. */
1713 if (!type->byref && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) &&
1714 (!type->data.generic_param->gshared_constraint || type->data.generic_param->gshared_constraint->type == MONO_TYPE_OBJECT))
1715 return &mono_defaults.object_class->byval_arg;
1716 return type;
1719 static gboolean
1720 class_has_references (MonoClass *klass)
1722 mono_class_init_sizes (klass);
1725 * has_references is not set if this is called recursively, but this is not a problem since this is only used
1726 * during field layout, and instance fields are initialized before static fields, and instance fields can't
1727 * embed themselves.
1729 return klass->has_references;
1732 static gboolean
1733 type_has_references (MonoClass *klass, MonoType *ftype)
1735 if (MONO_TYPE_IS_REFERENCE (ftype) || IS_GC_REFERENCE (klass, ftype) || ((MONO_TYPE_ISSTRUCT (ftype) && class_has_references (mono_class_from_mono_type (ftype)))))
1736 return TRUE;
1737 if (!ftype->byref && (ftype->type == MONO_TYPE_VAR || ftype->type == MONO_TYPE_MVAR)) {
1738 MonoGenericParam *gparam = ftype->data.generic_param;
1740 if (gparam->gshared_constraint)
1741 return class_has_references (mono_class_from_mono_type (gparam->gshared_constraint));
1743 return FALSE;
1747 * mono_class_layout_fields:
1748 * @class: a class
1749 * @base_instance_size: base instance size
1750 * @packing_size:
1752 * This contains the common code for computing the layout of classes and sizes.
1753 * This should only be called from mono_class_setup_fields () and
1754 * typebuilder_setup_fields ().
1756 * LOCKING: Acquires the loader lock
1758 void
1759 mono_class_layout_fields (MonoClass *klass, int base_instance_size, int packing_size, gboolean sre)
1761 int i;
1762 const int top = mono_class_get_field_count (klass);
1763 guint32 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
1764 guint32 pass, passes, real_size;
1765 gboolean gc_aware_layout = FALSE;
1766 gboolean has_static_fields = FALSE;
1767 gboolean has_references = FALSE;
1768 gboolean has_static_refs = FALSE;
1769 MonoClassField *field;
1770 gboolean blittable;
1771 int instance_size = base_instance_size;
1772 int class_size, min_align;
1773 int *field_offsets;
1774 gboolean *fields_has_references;
1777 * We want to avoid doing complicated work inside locks, so we compute all the required
1778 * information and write it to @klass inside a lock.
1780 if (klass->fields_inited)
1781 return;
1783 if ((packing_size & 0xffffff00) != 0) {
1784 mono_class_set_type_load_failure (klass, "Could not load struct '%s' with packing size %d >= 256", klass->name, packing_size);
1785 return;
1788 if (klass->parent) {
1789 min_align = klass->parent->min_align;
1790 /* we use | since it may have been set already */
1791 has_references = klass->has_references | klass->parent->has_references;
1792 } else {
1793 min_align = 1;
1795 /* We can't really enable 16 bytes alignment until the GC supports it.
1796 The whole layout/instance size code must be reviewed because we do alignment calculation in terms of the
1797 boxed instance, which leads to unexplainable holes at the beginning of an object embedding a simd type.
1798 Bug #506144 is an example of this issue.
1800 if (klass->simd_type)
1801 min_align = 16;
1805 * When we do generic sharing we need to have layout
1806 * information for open generic classes (either with a generic
1807 * context containing type variables or with a generic
1808 * container), so we don't return in that case anymore.
1811 if (klass->enumtype) {
1812 for (i = 0; i < top; i++) {
1813 field = &klass->fields [i];
1814 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1815 klass->cast_class = klass->element_class = mono_class_from_mono_type (field->type);
1816 break;
1820 if (!mono_class_enum_basetype (klass)) {
1821 mono_class_set_type_load_failure (klass, "The enumeration's base type is invalid.");
1822 return;
1827 * Enable GC aware auto layout: in this mode, reference
1828 * fields are grouped together inside objects, increasing collector
1829 * performance.
1830 * Requires that all classes whose layout is known to native code be annotated
1831 * with [StructLayout (LayoutKind.Sequential)]
1832 * Value types have gc_aware_layout disabled by default, as per
1833 * what the default is for other runtimes.
1835 /* corlib is missing [StructLayout] directives in many places */
1836 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
1837 if (!klass->valuetype)
1838 gc_aware_layout = TRUE;
1841 /* Compute klass->blittable */
1842 blittable = TRUE;
1843 if (klass->parent)
1844 blittable = klass->parent->blittable;
1845 if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT && !(mono_is_corlib_image (klass->image) && !strcmp (klass->name_space, "System") && !strcmp (klass->name, "ValueType")) && top)
1846 blittable = FALSE;
1847 for (i = 0; i < top; i++) {
1848 field = &klass->fields [i];
1850 if (mono_field_is_deleted (field))
1851 continue;
1852 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1853 continue;
1854 if (blittable) {
1855 if (field->type->byref || MONO_TYPE_IS_REFERENCE (field->type)) {
1856 blittable = FALSE;
1857 } else {
1858 MonoClass *field_class = mono_class_from_mono_type (field->type);
1859 if (field_class) {
1860 mono_class_setup_fields (field_class);
1861 if (mono_class_has_failure (field_class)) {
1862 MonoError field_error;
1863 mono_error_init (&field_error);
1864 mono_error_set_for_class_failure (&field_error, field_class);
1865 mono_class_set_type_load_failure (klass, "Could not set up field '%s' due to: %s", field->name, mono_error_get_message (&field_error));
1866 mono_error_cleanup (&field_error);
1867 break;
1870 if (!field_class || !field_class->blittable)
1871 blittable = FALSE;
1874 if (klass->enumtype)
1875 blittable = klass->element_class->blittable;
1877 if (mono_class_has_failure (klass))
1878 return;
1879 if (klass == mono_defaults.string_class)
1880 blittable = FALSE;
1882 /* Compute klass->has_references */
1884 * Process non-static fields first, since static fields might recursively
1885 * refer to the class itself.
1887 for (i = 0; i < top; i++) {
1888 MonoType *ftype;
1890 field = &klass->fields [i];
1892 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
1893 ftype = mono_type_get_underlying_type (field->type);
1894 ftype = mono_type_get_basic_type_from_generic (ftype);
1895 if (type_has_references (klass, ftype))
1896 has_references = TRUE;
1901 * Compute field layout and total size (not considering static fields)
1903 field_offsets = g_new0 (int, top);
1904 fields_has_references = g_new0 (gboolean, top);
1905 int first_field_idx = mono_class_has_static_metadata (klass) ? mono_class_get_first_field_idx (klass) : 0;
1906 switch (layout) {
1907 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
1908 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
1909 if (gc_aware_layout)
1910 passes = 2;
1911 else
1912 passes = 1;
1914 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT)
1915 passes = 1;
1917 if (klass->parent) {
1918 mono_class_setup_fields (klass->parent);
1919 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Cannot initialize parent class"))
1920 return;
1921 real_size = klass->parent->instance_size;
1922 } else {
1923 real_size = sizeof (MonoObject);
1926 for (pass = 0; pass < passes; ++pass) {
1927 for (i = 0; i < top; i++){
1928 gint32 align;
1929 guint32 size;
1930 MonoType *ftype;
1932 field = &klass->fields [i];
1934 if (mono_field_is_deleted (field))
1935 continue;
1936 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1937 continue;
1939 ftype = mono_type_get_underlying_type (field->type);
1940 ftype = mono_type_get_basic_type_from_generic (ftype);
1941 if (gc_aware_layout) {
1942 fields_has_references [i] = type_has_references (klass, ftype);
1943 if (fields_has_references [i]) {
1944 if (pass == 1)
1945 continue;
1946 } else {
1947 if (pass == 0)
1948 continue;
1952 if ((top == 1) && (instance_size == sizeof (MonoObject)) &&
1953 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
1954 /* This field is a hack inserted by MCS to empty structures */
1955 continue;
1958 size = mono_type_size (field->type, &align);
1960 /* FIXME (LAMESPEC): should we also change the min alignment according to pack? */
1961 align = packing_size ? MIN (packing_size, align): align;
1962 /* if the field has managed references, we need to force-align it
1963 * see bug #77788
1965 if (type_has_references (klass, ftype))
1966 align = MAX (align, sizeof (gpointer));
1968 min_align = MAX (align, min_align);
1969 field_offsets [i] = real_size;
1970 if (align) {
1971 field_offsets [i] += align - 1;
1972 field_offsets [i] &= ~(align - 1);
1974 /*TypeBuilders produce all sort of weird things*/
1975 g_assert (image_is_dynamic (klass->image) || field_offsets [i] > 0);
1976 real_size = field_offsets [i] + size;
1979 /* Make SIMD types as big as a SIMD register since they can be stored into using simd stores */
1980 if (klass->simd_type)
1981 real_size = MAX (real_size, sizeof (MonoObject) + 16);
1982 instance_size = MAX (real_size, instance_size);
1984 if (instance_size & (min_align - 1)) {
1985 instance_size += min_align - 1;
1986 instance_size &= ~(min_align - 1);
1989 break;
1990 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: {
1991 guint8 *ref_bitmap;
1993 real_size = 0;
1994 for (i = 0; i < top; i++) {
1995 gint32 align;
1996 guint32 size;
1997 MonoType *ftype;
1999 field = &klass->fields [i];
2002 * There must be info about all the fields in a type if it
2003 * uses explicit layout.
2005 if (mono_field_is_deleted (field))
2006 continue;
2007 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2008 continue;
2010 size = mono_type_size (field->type, &align);
2011 align = packing_size ? MIN (packing_size, align): align;
2012 min_align = MAX (align, min_align);
2014 if (sre) {
2015 /* Already set by typebuilder_setup_fields () */
2016 field_offsets [i] = field->offset + sizeof (MonoObject);
2017 } else {
2018 int idx = first_field_idx + i;
2019 guint32 offset;
2020 mono_metadata_field_info (klass->image, idx, &offset, NULL, NULL);
2021 field_offsets [i] = offset + sizeof (MonoObject);
2023 ftype = mono_type_get_underlying_type (field->type);
2024 ftype = mono_type_get_basic_type_from_generic (ftype);
2025 if (type_has_references (klass, ftype)) {
2026 if (field_offsets [i] % sizeof (gpointer)) {
2027 mono_class_set_type_load_failure (klass, "Reference typed field '%s' has explicit offset that is not pointer-size aligned.", field->name);
2032 * Calc max size.
2034 real_size = MAX (real_size, size + field_offsets [i]);
2037 if (klass->has_references) {
2038 ref_bitmap = g_new0 (guint8, real_size / sizeof (gpointer));
2040 /* Check for overlapping reference and non-reference fields */
2041 for (i = 0; i < top; i++) {
2042 MonoType *ftype;
2044 field = &klass->fields [i];
2046 if (mono_field_is_deleted (field))
2047 continue;
2048 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2049 continue;
2050 ftype = mono_type_get_underlying_type (field->type);
2051 if (MONO_TYPE_IS_REFERENCE (ftype))
2052 ref_bitmap [field_offsets [i] / sizeof (gpointer)] = 1;
2054 for (i = 0; i < top; i++) {
2055 field = &klass->fields [i];
2057 if (mono_field_is_deleted (field))
2058 continue;
2059 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2060 continue;
2062 // FIXME: Too much code does this
2063 #if 0
2064 if (!MONO_TYPE_IS_REFERENCE (field->type) && ref_bitmap [field_offsets [i] / sizeof (gpointer)]) {
2065 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]);
2067 #endif
2069 g_free (ref_bitmap);
2072 instance_size = MAX (real_size, instance_size);
2073 if (instance_size & (min_align - 1)) {
2074 instance_size += min_align - 1;
2075 instance_size &= ~(min_align - 1);
2077 break;
2081 if (layout != TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
2083 * This leads to all kinds of problems with nested structs, so only
2084 * enable it when a MONO_DEBUG property is set.
2086 * For small structs, set min_align to at least the struct size to improve
2087 * performance, and since the JIT memset/memcpy code assumes this and generates
2088 * unaligned accesses otherwise. See #78990 for a testcase.
2090 if (mono_align_small_structs && top) {
2091 if (instance_size <= sizeof (MonoObject) + sizeof (gpointer))
2092 min_align = MAX (min_align, instance_size - sizeof (MonoObject));
2096 if (klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
2097 instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
2098 else if (klass->byval_arg.type == MONO_TYPE_PTR)
2099 instance_size = sizeof (MonoObject) + sizeof (gpointer);
2101 /* Publish the data */
2102 mono_loader_lock ();
2103 if (klass->instance_size && !klass->image->dynamic) {
2104 /* Might be already set using cached info */
2105 if (klass->instance_size != instance_size) {
2106 /* Emit info to help debugging */
2107 g_print ("%s\n", mono_class_full_name (klass));
2108 g_print ("%d %d %d %d\n", klass->instance_size, instance_size, klass->blittable, blittable);
2109 g_print ("%d %d %d %d\n", klass->has_references, has_references, klass->packing_size, packing_size);
2110 g_print ("%d %d\n", klass->min_align, min_align);
2111 for (i = 0; i < top; ++i) {
2112 field = &klass->fields [i];
2113 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2114 printf (" %s %d %d %d\n", klass->fields [i].name, klass->fields [i].offset, field_offsets [i], fields_has_references [i]);
2117 g_assert (klass->instance_size == instance_size);
2118 } else {
2119 klass->instance_size = instance_size;
2121 klass->blittable = blittable;
2122 klass->has_references = has_references;
2123 klass->packing_size = packing_size;
2124 klass->min_align = min_align;
2125 for (i = 0; i < top; ++i) {
2126 field = &klass->fields [i];
2127 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2128 klass->fields [i].offset = field_offsets [i];
2131 mono_memory_barrier ();
2132 klass->size_inited = 1;
2133 mono_loader_unlock ();
2136 * Compute static field layout and size
2137 * Static fields can reference the class itself, so this has to be
2138 * done after instance_size etc. are initialized.
2140 class_size = 0;
2141 for (i = 0; i < top; i++) {
2142 gint32 align;
2143 guint32 size;
2145 field = &klass->fields [i];
2147 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC) || field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
2148 continue;
2149 if (mono_field_is_deleted (field))
2150 continue;
2152 if (mono_type_has_exceptions (field->type)) {
2153 mono_class_set_type_load_failure (klass, "Field '%s' has an invalid type.", field->name);
2154 break;
2157 has_static_fields = TRUE;
2159 size = mono_type_size (field->type, &align);
2160 field_offsets [i] = class_size;
2161 /*align is always non-zero here*/
2162 field_offsets [i] += align - 1;
2163 field_offsets [i] &= ~(align - 1);
2164 class_size = field_offsets [i] + size;
2167 if (has_static_fields && class_size == 0)
2168 /* Simplify code which depends on class_size != 0 if the class has static fields */
2169 class_size = 8;
2171 /* Compute klass->has_static_refs */
2172 has_static_refs = FALSE;
2173 for (i = 0; i < top; i++) {
2174 MonoType *ftype;
2176 field = &klass->fields [i];
2178 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2179 ftype = mono_type_get_underlying_type (field->type);
2180 ftype = mono_type_get_basic_type_from_generic (ftype);
2181 if (type_has_references (klass, ftype))
2182 has_static_refs = TRUE;
2186 /*valuetypes can't be neither bigger than 1Mb or empty. */
2187 if (klass->valuetype && (klass->instance_size <= 0 || klass->instance_size > (0x100000 + sizeof (MonoObject))))
2188 mono_class_set_type_load_failure (klass, "Value type instance size (%d) cannot be zero, negative, or bigger than 1Mb", klass->instance_size);
2190 /* Publish the data */
2191 mono_loader_lock ();
2192 if (!klass->rank)
2193 klass->sizes.class_size = class_size;
2194 klass->has_static_refs = has_static_refs;
2195 for (i = 0; i < top; ++i) {
2196 field = &klass->fields [i];
2198 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2199 field->offset = field_offsets [i];
2202 mono_memory_barrier ();
2203 klass->fields_inited = 1;
2204 mono_loader_unlock ();
2206 g_free (field_offsets);
2207 g_free (fields_has_references);
2210 static MonoMethod*
2211 create_array_method (MonoClass *klass, const char *name, MonoMethodSignature *sig)
2213 MonoMethod *method;
2215 method = (MonoMethod *) mono_image_alloc0 (klass->image, sizeof (MonoMethodPInvoke));
2216 method->klass = klass;
2217 method->flags = METHOD_ATTRIBUTE_PUBLIC;
2218 method->iflags = METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL;
2219 method->signature = sig;
2220 method->name = name;
2221 method->slot = -1;
2222 /* .ctor */
2223 if (name [0] == '.') {
2224 method->flags |= METHOD_ATTRIBUTE_RT_SPECIAL_NAME | METHOD_ATTRIBUTE_SPECIAL_NAME;
2225 } else {
2226 method->iflags |= METHOD_IMPL_ATTRIBUTE_RUNTIME;
2228 return method;
2232 * mono_class_setup_methods:
2233 * @class: a class
2235 * Initializes the 'methods' array in CLASS.
2236 * Calling this method should be avoided if possible since it allocates a lot
2237 * of long-living MonoMethod structures.
2238 * Methods belonging to an interface are assigned a sequential slot starting
2239 * from 0.
2241 * On failure this function sets klass->has_failure and stores a MonoErrorBoxed with details
2243 void
2244 mono_class_setup_methods (MonoClass *klass)
2246 int i, count;
2247 MonoMethod **methods;
2249 if (klass->methods)
2250 return;
2252 if (mono_class_is_ginst (klass)) {
2253 MonoError error;
2254 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2256 mono_class_init (gklass);
2257 if (!mono_class_has_failure (gklass))
2258 mono_class_setup_methods (gklass);
2259 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2260 return;
2262 /* The + 1 makes this always non-NULL to pass the check in mono_class_setup_methods () */
2263 count = mono_class_get_method_count (gklass);
2264 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * (count + 1));
2266 for (i = 0; i < count; i++) {
2267 methods [i] = mono_class_inflate_generic_method_full_checked (
2268 gklass->methods [i], klass, mono_class_get_context (klass), &error);
2269 if (!mono_error_ok (&error)) {
2270 char *method = mono_method_full_name (gklass->methods [i], TRUE);
2271 mono_class_set_type_load_failure (klass, "Could not inflate method %s due to %s", method, mono_error_get_message (&error));
2273 g_free (method);
2274 mono_error_cleanup (&error);
2275 return;
2278 } else if (klass->rank) {
2279 MonoError error;
2280 MonoMethod *amethod;
2281 MonoMethodSignature *sig;
2282 int count_generic = 0, first_generic = 0;
2283 int method_num = 0;
2284 gboolean jagged_ctor = FALSE;
2286 count = 3 + (klass->rank > 1? 2: 1);
2288 mono_class_setup_interfaces (klass, &error);
2289 g_assert (mono_error_ok (&error)); /*FIXME can this fail for array types?*/
2291 if (klass->rank == 1 && klass->element_class->rank) {
2292 jagged_ctor = TRUE;
2293 count ++;
2296 if (klass->interface_count) {
2297 count_generic = generic_array_methods (klass);
2298 first_generic = count;
2299 count += klass->interface_count * count_generic;
2302 methods = (MonoMethod **)mono_class_alloc0 (klass, sizeof (MonoMethod*) * count);
2304 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2305 sig->ret = &mono_defaults.void_class->byval_arg;
2306 sig->pinvoke = TRUE;
2307 sig->hasthis = TRUE;
2308 for (i = 0; i < klass->rank; ++i)
2309 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2311 amethod = create_array_method (klass, ".ctor", sig);
2312 methods [method_num++] = amethod;
2313 if (klass->rank > 1) {
2314 sig = mono_metadata_signature_alloc (klass->image, klass->rank * 2);
2315 sig->ret = &mono_defaults.void_class->byval_arg;
2316 sig->pinvoke = TRUE;
2317 sig->hasthis = TRUE;
2318 for (i = 0; i < klass->rank * 2; ++i)
2319 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2321 amethod = create_array_method (klass, ".ctor", sig);
2322 methods [method_num++] = amethod;
2325 if (jagged_ctor) {
2326 /* Jagged arrays have an extra ctor in .net which creates an array of arrays */
2327 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2328 sig->ret = &mono_defaults.void_class->byval_arg;
2329 sig->pinvoke = TRUE;
2330 sig->hasthis = TRUE;
2331 for (i = 0; i < klass->rank + 1; ++i)
2332 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2333 amethod = create_array_method (klass, ".ctor", sig);
2334 methods [method_num++] = amethod;
2337 /* element Get (idx11, [idx2, ...]) */
2338 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2339 sig->ret = &klass->element_class->byval_arg;
2340 sig->pinvoke = TRUE;
2341 sig->hasthis = TRUE;
2342 for (i = 0; i < klass->rank; ++i)
2343 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2344 amethod = create_array_method (klass, "Get", sig);
2345 methods [method_num++] = amethod;
2346 /* element& Address (idx11, [idx2, ...]) */
2347 sig = mono_metadata_signature_alloc (klass->image, klass->rank);
2348 sig->ret = &klass->element_class->this_arg;
2349 sig->pinvoke = TRUE;
2350 sig->hasthis = TRUE;
2351 for (i = 0; i < klass->rank; ++i)
2352 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2353 amethod = create_array_method (klass, "Address", sig);
2354 methods [method_num++] = amethod;
2355 /* void Set (idx11, [idx2, ...], element) */
2356 sig = mono_metadata_signature_alloc (klass->image, klass->rank + 1);
2357 sig->ret = &mono_defaults.void_class->byval_arg;
2358 sig->pinvoke = TRUE;
2359 sig->hasthis = TRUE;
2360 for (i = 0; i < klass->rank; ++i)
2361 sig->params [i] = &mono_defaults.int32_class->byval_arg;
2362 sig->params [i] = &klass->element_class->byval_arg;
2363 amethod = create_array_method (klass, "Set", sig);
2364 methods [method_num++] = amethod;
2366 for (i = 0; i < klass->interface_count; i++)
2367 setup_generic_array_ifaces (klass, klass->interfaces [i], methods, first_generic + i * count_generic);
2368 } else if (mono_class_has_static_metadata (klass)) {
2369 MonoError error;
2370 int first_idx = mono_class_get_first_method_idx (klass);
2372 count = mono_class_get_method_count (klass);
2373 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * count);
2374 for (i = 0; i < count; ++i) {
2375 int idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_METHOD, first_idx + i + 1);
2376 methods [i] = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | idx, klass, NULL, &error);
2377 if (!methods [i]) {
2378 mono_class_set_type_load_failure (klass, "Could not load method %d due to %s", i, mono_error_get_message (&error));
2379 mono_error_cleanup (&error);
2382 } else {
2383 methods = (MonoMethod **)mono_class_alloc (klass, sizeof (MonoMethod*) * 1);
2384 count = 0;
2387 if (MONO_CLASS_IS_INTERFACE (klass)) {
2388 int slot = 0;
2389 /*Only assign slots to virtual methods as interfaces are allowed to have static methods.*/
2390 for (i = 0; i < count; ++i) {
2391 if (methods [i]->flags & METHOD_ATTRIBUTE_VIRTUAL)
2392 methods [i]->slot = slot++;
2396 mono_image_lock (klass->image);
2398 if (!klass->methods) {
2399 mono_class_set_method_count (klass, count);
2401 /* Needed because of the double-checking locking pattern */
2402 mono_memory_barrier ();
2404 klass->methods = methods;
2407 mono_image_unlock (klass->image);
2411 * mono_class_get_method_by_index:
2413 * Returns klass->methods [index], initializing klass->methods if neccesary.
2415 * LOCKING: Acquires the loader lock.
2417 MonoMethod*
2418 mono_class_get_method_by_index (MonoClass *klass, int index)
2420 MonoError error;
2422 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
2423 /* Avoid calling setup_methods () if possible */
2424 if (gklass && !klass->methods) {
2425 MonoMethod *m;
2427 m = mono_class_inflate_generic_method_full_checked (
2428 gklass->container_class->methods [index], klass, mono_class_get_context (klass), &error);
2429 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2431 * If setup_methods () is called later for this class, no duplicates are created,
2432 * since inflate_generic_method guarantees that only one instance of a method
2433 * is created for each context.
2436 mono_class_setup_methods (klass);
2437 g_assert (m == klass->methods [index]);
2439 return m;
2440 } else {
2441 mono_class_setup_methods (klass);
2442 if (mono_class_has_failure (klass)) /*FIXME do proper error handling*/
2443 return NULL;
2444 g_assert (index >= 0 && index < mono_class_get_method_count (klass));
2445 return klass->methods [index];
2450 * mono_class_get_inflated_method:
2452 * Given an inflated class CLASS and a method METHOD which should be a method of
2453 * CLASS's generic definition, return the inflated method corresponding to METHOD.
2455 MonoMethod*
2456 mono_class_get_inflated_method (MonoClass *klass, MonoMethod *method)
2458 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2459 int i, mcount;
2461 g_assert (method->klass == gklass);
2463 mono_class_setup_methods (gklass);
2464 g_assert (!mono_class_has_failure (gklass)); /*FIXME do proper error handling*/
2466 mcount = mono_class_get_method_count (gklass);
2467 for (i = 0; i < mcount; ++i) {
2468 if (gklass->methods [i] == method) {
2469 if (klass->methods) {
2470 return klass->methods [i];
2471 } else {
2472 MonoError error;
2473 MonoMethod *result = mono_class_inflate_generic_method_full_checked (gklass->methods [i], klass, mono_class_get_context (klass), &error);
2474 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2475 return result;
2480 return NULL;
2484 * mono_class_get_vtable_entry:
2486 * Returns klass->vtable [offset], computing it if neccesary. Returns NULL on failure.
2487 * LOCKING: Acquires the loader lock.
2489 MonoMethod*
2490 mono_class_get_vtable_entry (MonoClass *klass, int offset)
2492 MonoMethod *m;
2494 if (klass->rank == 1) {
2496 * szarrays do not overwrite any methods of Array, so we can avoid
2497 * initializing their vtables in some cases.
2499 mono_class_setup_vtable (klass->parent);
2500 if (offset < klass->parent->vtable_size)
2501 return klass->parent->vtable [offset];
2504 if (mono_class_is_ginst (klass)) {
2505 MonoError error;
2506 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2507 mono_class_setup_vtable (gklass);
2508 m = gklass->vtable [offset];
2510 m = mono_class_inflate_generic_method_full_checked (m, klass, mono_class_get_context (klass), &error);
2511 g_assert (mono_error_ok (&error)); /* FIXME don't swallow this error */
2512 } else {
2513 mono_class_setup_vtable (klass);
2514 if (mono_class_has_failure (klass))
2515 return NULL;
2516 m = klass->vtable [offset];
2519 return m;
2523 * mono_class_get_vtable_size:
2525 * Return the vtable size for KLASS.
2528 mono_class_get_vtable_size (MonoClass *klass)
2530 mono_class_setup_vtable (klass);
2532 return klass->vtable_size;
2536 * mono_class_setup_properties:
2538 * Initialize klass->ext.property and klass->ext.properties.
2540 * This method can fail the class.
2542 static void
2543 mono_class_setup_properties (MonoClass *klass)
2545 guint startm, endm, i, j;
2546 guint32 cols [MONO_PROPERTY_SIZE];
2547 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2548 MonoProperty *properties;
2549 guint32 last;
2550 int first, count;
2551 MonoClassPropertyInfo *info;
2553 info = mono_class_get_property_info (klass);
2554 if (info)
2555 return;
2557 if (mono_class_is_ginst (klass)) {
2558 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2560 mono_class_init (gklass);
2561 mono_class_setup_properties (gklass);
2562 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2563 return;
2565 MonoClassPropertyInfo *ginfo = mono_class_get_property_info (gklass);
2566 properties = mono_class_new0 (klass, MonoProperty, ginfo->count + 1);
2568 for (i = 0; i < ginfo->count; i++) {
2569 MonoError error;
2570 MonoProperty *prop = &properties [i];
2572 *prop = ginfo->properties [i];
2574 if (prop->get)
2575 prop->get = mono_class_inflate_generic_method_full_checked (
2576 prop->get, klass, mono_class_get_context (klass), &error);
2577 if (prop->set)
2578 prop->set = mono_class_inflate_generic_method_full_checked (
2579 prop->set, klass, mono_class_get_context (klass), &error);
2581 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2582 prop->parent = klass;
2585 first = ginfo->first;
2586 count = ginfo->count;
2587 } else {
2588 first = mono_metadata_properties_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2589 count = last - first;
2591 if (count) {
2592 mono_class_setup_methods (klass);
2593 if (mono_class_has_failure (klass))
2594 return;
2597 properties = (MonoProperty *)mono_class_alloc0 (klass, sizeof (MonoProperty) * count);
2598 for (i = first; i < last; ++i) {
2599 mono_metadata_decode_table_row (klass->image, MONO_TABLE_PROPERTY, i, cols, MONO_PROPERTY_SIZE);
2600 properties [i - first].parent = klass;
2601 properties [i - first].attrs = cols [MONO_PROPERTY_FLAGS];
2602 properties [i - first].name = mono_metadata_string_heap (klass->image, cols [MONO_PROPERTY_NAME]);
2604 startm = mono_metadata_methods_from_property (klass->image, i, &endm);
2605 int first_idx = mono_class_get_first_method_idx (klass);
2606 for (j = startm; j < endm; ++j) {
2607 MonoMethod *method;
2609 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2611 if (klass->image->uncompressed_metadata) {
2612 MonoError error;
2613 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2614 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2615 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2616 } else {
2617 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
2620 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2621 case METHOD_SEMANTIC_SETTER:
2622 properties [i - first].set = method;
2623 break;
2624 case METHOD_SEMANTIC_GETTER:
2625 properties [i - first].get = method;
2626 break;
2627 default:
2628 break;
2634 info = mono_class_alloc0 (klass, sizeof (MonoClassPropertyInfo));
2635 info->first = first;
2636 info->count = count;
2637 info->properties = properties;
2638 mono_memory_barrier ();
2640 /* This might leak 'info' which was allocated from the image mempool */
2641 mono_class_set_property_info (klass, info);
2644 static MonoMethod**
2645 inflate_method_listz (MonoMethod **methods, MonoClass *klass, MonoGenericContext *context)
2647 MonoMethod **om, **retval;
2648 int count;
2650 for (om = methods, count = 0; *om; ++om, ++count)
2653 retval = g_new0 (MonoMethod*, count + 1);
2654 count = 0;
2655 for (om = methods, count = 0; *om; ++om, ++count) {
2656 MonoError error;
2657 retval [count] = mono_class_inflate_generic_method_full_checked (*om, klass, context, &error);
2658 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2661 return retval;
2664 /*This method can fail the class.*/
2665 static void
2666 mono_class_setup_events (MonoClass *klass)
2668 int first, count;
2669 guint startm, endm, i, j;
2670 guint32 cols [MONO_EVENT_SIZE];
2671 MonoTableInfo *msemt = &klass->image->tables [MONO_TABLE_METHODSEMANTICS];
2672 guint32 last;
2673 MonoEvent *events;
2675 MonoClassEventInfo *info = mono_class_get_event_info (klass);
2676 if (info)
2677 return;
2679 if (mono_class_is_ginst (klass)) {
2680 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
2681 MonoGenericContext *context = NULL;
2683 mono_class_setup_events (gklass);
2684 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to load"))
2685 return;
2687 MonoClassEventInfo *ginfo = mono_class_get_event_info (gklass);
2688 first = ginfo->first;
2689 count = ginfo->count;
2691 events = mono_class_new0 (klass, MonoEvent, count);
2693 if (count)
2694 context = mono_class_get_context (klass);
2696 for (i = 0; i < count; i++) {
2697 MonoError error;
2698 MonoEvent *event = &events [i];
2699 MonoEvent *gevent = &ginfo->events [i];
2701 mono_error_init (&error); //since we do conditional calls, we must ensure the default value is ok
2703 event->parent = klass;
2704 event->name = gevent->name;
2705 event->add = gevent->add ? mono_class_inflate_generic_method_full_checked (gevent->add, klass, context, &error) : NULL;
2706 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2707 event->remove = gevent->remove ? mono_class_inflate_generic_method_full_checked (gevent->remove, klass, context, &error) : NULL;
2708 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2709 event->raise = gevent->raise ? mono_class_inflate_generic_method_full_checked (gevent->raise, klass, context, &error) : NULL;
2710 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
2712 #ifndef MONO_SMALL_CONFIG
2713 event->other = gevent->other ? inflate_method_listz (gevent->other, klass, context) : NULL;
2714 #endif
2715 event->attrs = gevent->attrs;
2717 } else {
2718 first = mono_metadata_events_from_typedef (klass->image, mono_metadata_token_index (klass->type_token) - 1, &last);
2719 count = last - first;
2721 if (count) {
2722 mono_class_setup_methods (klass);
2723 if (mono_class_has_failure (klass)) {
2724 return;
2728 events = (MonoEvent *)mono_class_alloc0 (klass, sizeof (MonoEvent) * count);
2729 for (i = first; i < last; ++i) {
2730 MonoEvent *event = &events [i - first];
2732 mono_metadata_decode_table_row (klass->image, MONO_TABLE_EVENT, i, cols, MONO_EVENT_SIZE);
2733 event->parent = klass;
2734 event->attrs = cols [MONO_EVENT_FLAGS];
2735 event->name = mono_metadata_string_heap (klass->image, cols [MONO_EVENT_NAME]);
2737 startm = mono_metadata_methods_from_event (klass->image, i, &endm);
2738 int first_idx = mono_class_get_first_method_idx (klass);
2739 for (j = startm; j < endm; ++j) {
2740 MonoMethod *method;
2742 mono_metadata_decode_row (msemt, j, cols, MONO_METHOD_SEMA_SIZE);
2744 if (klass->image->uncompressed_metadata) {
2745 MonoError error;
2746 /* It seems like the MONO_METHOD_SEMA_METHOD column needs no remapping */
2747 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | cols [MONO_METHOD_SEMA_METHOD], klass, NULL, &error);
2748 mono_error_cleanup (&error); /* FIXME don't swallow this error */
2749 } else {
2750 method = klass->methods [cols [MONO_METHOD_SEMA_METHOD] - 1 - first_idx];
2753 switch (cols [MONO_METHOD_SEMA_SEMANTICS]) {
2754 case METHOD_SEMANTIC_ADD_ON:
2755 event->add = method;
2756 break;
2757 case METHOD_SEMANTIC_REMOVE_ON:
2758 event->remove = method;
2759 break;
2760 case METHOD_SEMANTIC_FIRE:
2761 event->raise = method;
2762 break;
2763 case METHOD_SEMANTIC_OTHER: {
2764 #ifndef MONO_SMALL_CONFIG
2765 int n = 0;
2767 if (event->other == NULL) {
2768 event->other = g_new0 (MonoMethod*, 2);
2769 } else {
2770 while (event->other [n])
2771 n++;
2772 event->other = (MonoMethod **)g_realloc (event->other, (n + 2) * sizeof (MonoMethod*));
2774 event->other [n] = method;
2775 /* NULL terminated */
2776 event->other [n + 1] = NULL;
2777 #endif
2778 break;
2780 default:
2781 break;
2787 info = mono_class_alloc0 (klass, sizeof (MonoClassEventInfo));
2788 info->events = events;
2789 info->first = first;
2790 info->count = count;
2792 mono_memory_barrier ();
2794 mono_class_set_event_info (klass, info);
2798 * Global pool of interface IDs, represented as a bitset.
2799 * LOCKING: Protected by the classes lock.
2801 static MonoBitSet *global_interface_bitset = NULL;
2804 * mono_unload_interface_ids:
2805 * @bitset: bit set of interface IDs
2807 * When an image is unloaded, the interface IDs associated with
2808 * the image are put back in the global pool of IDs so the numbers
2809 * can be reused.
2811 void
2812 mono_unload_interface_ids (MonoBitSet *bitset)
2814 classes_lock ();
2815 mono_bitset_sub (global_interface_bitset, bitset);
2816 classes_unlock ();
2819 void
2820 mono_unload_interface_id (MonoClass *klass)
2822 if (global_interface_bitset && klass->interface_id) {
2823 classes_lock ();
2824 mono_bitset_clear (global_interface_bitset, klass->interface_id);
2825 classes_unlock ();
2830 * mono_get_unique_iid:
2831 * @class: interface
2833 * Assign a unique integer ID to the interface represented by @class.
2834 * The ID will positive and as small as possible.
2835 * LOCKING: Acquires the classes lock.
2836 * Returns: The new ID.
2838 static guint32
2839 mono_get_unique_iid (MonoClass *klass)
2841 int iid;
2843 g_assert (MONO_CLASS_IS_INTERFACE (klass));
2845 classes_lock ();
2847 if (!global_interface_bitset) {
2848 global_interface_bitset = mono_bitset_new (128, 0);
2851 iid = mono_bitset_find_first_unset (global_interface_bitset, -1);
2852 if (iid < 0) {
2853 int old_size = mono_bitset_size (global_interface_bitset);
2854 MonoBitSet *new_set = mono_bitset_clone (global_interface_bitset, old_size * 2);
2855 mono_bitset_free (global_interface_bitset);
2856 global_interface_bitset = new_set;
2857 iid = old_size;
2859 mono_bitset_set (global_interface_bitset, iid);
2860 /* set the bit also in the per-image set */
2861 if (!mono_class_is_ginst (klass)) {
2862 if (klass->image->interface_bitset) {
2863 if (iid >= mono_bitset_size (klass->image->interface_bitset)) {
2864 MonoBitSet *new_set = mono_bitset_clone (klass->image->interface_bitset, iid + 1);
2865 mono_bitset_free (klass->image->interface_bitset);
2866 klass->image->interface_bitset = new_set;
2868 } else {
2869 klass->image->interface_bitset = mono_bitset_new (iid + 1, 0);
2871 mono_bitset_set (klass->image->interface_bitset, iid);
2874 classes_unlock ();
2876 #ifndef MONO_SMALL_CONFIG
2877 if (mono_print_vtable) {
2878 int generic_id;
2879 char *type_name = mono_type_full_name (&klass->byval_arg);
2880 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
2881 if (gklass && !gklass->context.class_inst->is_open) {
2882 generic_id = gklass->context.class_inst->id;
2883 g_assert (generic_id != 0);
2884 } else {
2885 generic_id = 0;
2887 printf ("Interface: assigned id %d to %s|%s|%d\n", iid, klass->image->name, type_name, generic_id);
2888 g_free (type_name);
2890 #endif
2892 /* I've confirmed iids safe past 16 bits, however bitset code uses a signed int while testing.
2893 * Once this changes, it should be safe for us to allow 2^32-1 interfaces, until then 2^31-2 is the max. */
2894 g_assert (iid < INT_MAX);
2895 return iid;
2898 static void
2899 collect_implemented_interfaces_aux (MonoClass *klass, GPtrArray **res, GHashTable **ifaces, MonoError *error)
2901 int i;
2902 MonoClass *ic;
2904 mono_class_setup_interfaces (klass, error);
2905 return_if_nok (error);
2907 for (i = 0; i < klass->interface_count; i++) {
2908 ic = klass->interfaces [i];
2910 if (*res == NULL)
2911 *res = g_ptr_array_new ();
2912 if (*ifaces == NULL)
2913 *ifaces = g_hash_table_new (NULL, NULL);
2914 if (g_hash_table_lookup (*ifaces, ic))
2915 continue;
2916 g_ptr_array_add (*res, ic);
2917 g_hash_table_insert (*ifaces, ic, ic);
2918 mono_class_init (ic);
2919 if (mono_class_has_failure (ic)) {
2920 mono_error_set_type_load_class (error, ic, "Error Loading class");
2921 return;
2924 collect_implemented_interfaces_aux (ic, res, ifaces, error);
2925 return_if_nok (error);
2929 GPtrArray*
2930 mono_class_get_implemented_interfaces (MonoClass *klass, MonoError *error)
2932 GPtrArray *res = NULL;
2933 GHashTable *ifaces = NULL;
2935 collect_implemented_interfaces_aux (klass, &res, &ifaces, error);
2936 if (ifaces)
2937 g_hash_table_destroy (ifaces);
2938 if (!mono_error_ok (error)) {
2939 if (res)
2940 g_ptr_array_free (res, TRUE);
2941 return NULL;
2943 return res;
2946 static int
2947 compare_interface_ids (const void *p_key, const void *p_element)
2949 const MonoClass *key = (const MonoClass *)p_key;
2950 const MonoClass *element = *(const MonoClass **)p_element;
2952 return (key->interface_id - element->interface_id);
2955 /*FIXME verify all callers if they should switch to mono_class_interface_offset_with_variance*/
2957 mono_class_interface_offset (MonoClass *klass, MonoClass *itf)
2959 MonoClass **result = (MonoClass **)mono_binary_search (
2960 itf,
2961 klass->interfaces_packed,
2962 klass->interface_offsets_count,
2963 sizeof (MonoClass *),
2964 compare_interface_ids);
2965 if (result) {
2966 return klass->interface_offsets_packed [result - (klass->interfaces_packed)];
2967 } else {
2968 return -1;
2973 * mono_class_interface_offset_with_variance:
2975 * Return the interface offset of @itf in @klass. Sets @non_exact_match to TRUE if the match required variance check
2976 * If @itf is an interface with generic variant arguments, try to find the compatible one.
2978 * Note that this function is responsible for resolving ambiguities. Right now we use whatever ordering interfaces_packed gives us.
2980 * FIXME figure out MS disambiguation rules and fix this function.
2983 mono_class_interface_offset_with_variance (MonoClass *klass, MonoClass *itf, gboolean *non_exact_match)
2985 int i = mono_class_interface_offset (klass, itf);
2986 *non_exact_match = FALSE;
2987 if (i >= 0)
2988 return i;
2990 if (itf->is_array_special_interface && klass->rank < 2) {
2991 MonoClass *gtd = mono_class_get_generic_type_definition (itf);
2993 for (i = 0; i < klass->interface_offsets_count; i++) {
2994 // printf ("\t%s\n", mono_type_get_full_name (klass->interfaces_packed [i]));
2995 if (mono_class_get_generic_type_definition (klass->interfaces_packed [i]) == gtd) {
2996 *non_exact_match = TRUE;
2997 return klass->interface_offsets_packed [i];
3002 if (!mono_class_has_variant_generic_params (itf))
3003 return -1;
3005 for (i = 0; i < klass->interface_offsets_count; i++) {
3006 if (mono_class_is_variant_compatible (itf, klass->interfaces_packed [i], FALSE)) {
3007 *non_exact_match = TRUE;
3008 return klass->interface_offsets_packed [i];
3012 return -1;
3015 static void
3016 print_implemented_interfaces (MonoClass *klass)
3018 char *name;
3019 MonoError error;
3020 GPtrArray *ifaces = NULL;
3021 int i;
3022 int ancestor_level = 0;
3024 name = mono_type_get_full_name (klass);
3025 printf ("Packed interface table for class %s has size %d\n", name, klass->interface_offsets_count);
3026 g_free (name);
3028 for (i = 0; i < klass->interface_offsets_count; i++)
3029 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
3030 klass->interfaces_packed [i]->interface_id,
3031 klass->interface_offsets_packed [i],
3032 mono_class_get_method_count (klass->interfaces_packed [i]),
3033 klass->interfaces_packed [i]->name_space,
3034 klass->interfaces_packed [i]->name );
3035 printf ("Interface flags: ");
3036 for (i = 0; i <= klass->max_interface_id; i++)
3037 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
3038 printf ("(%d,T)", i);
3039 else
3040 printf ("(%d,F)", i);
3041 printf ("\n");
3042 printf ("Dump interface flags:");
3043 #ifdef COMPRESSED_INTERFACE_BITMAP
3045 const uint8_t* p = klass->interface_bitmap;
3046 i = klass->max_interface_id;
3047 while (i > 0) {
3048 printf (" %d x 00 %02X", p [0], p [1]);
3049 i -= p [0] * 8;
3050 i -= 8;
3053 #else
3054 for (i = 0; i < ((((klass->max_interface_id + 1) >> 3)) + (((klass->max_interface_id + 1) & 7)? 1 :0)); i++)
3055 printf (" %02X", klass->interface_bitmap [i]);
3056 #endif
3057 printf ("\n");
3058 while (klass != NULL) {
3059 printf ("[LEVEL %d] Implemented interfaces by class %s:\n", ancestor_level, klass->name);
3060 ifaces = mono_class_get_implemented_interfaces (klass, &error);
3061 if (!mono_error_ok (&error)) {
3062 printf (" Type failed due to %s\n", mono_error_get_message (&error));
3063 mono_error_cleanup (&error);
3064 } else if (ifaces) {
3065 for (i = 0; i < ifaces->len; i++) {
3066 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3067 printf (" [UIID %d] interface %s\n", ic->interface_id, ic->name);
3068 printf (" [%03d][UUID %03d][SLOT %03d][SIZE %03d] interface %s.%s\n", i,
3069 ic->interface_id,
3070 mono_class_interface_offset (klass, ic),
3071 mono_class_get_method_count (ic),
3072 ic->name_space,
3073 ic->name );
3075 g_ptr_array_free (ifaces, TRUE);
3077 ancestor_level ++;
3078 klass = klass->parent;
3083 * Return the number of virtual methods.
3084 * Even for interfaces we can't simply return the number of methods as all CLR types are allowed to have static methods.
3085 * Return -1 on failure.
3086 * FIXME It would be nice if this information could be cached somewhere.
3088 static int
3089 count_virtual_methods (MonoClass *klass)
3091 int i, mcount, vcount = 0;
3092 guint32 flags;
3093 klass = mono_class_get_generic_type_definition (klass); /*We can find this information by looking at the GTD*/
3095 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
3096 mono_class_setup_methods (klass);
3097 if (mono_class_has_failure (klass))
3098 return -1;
3100 mcount = mono_class_get_method_count (klass);
3101 for (i = 0; i < mcount; ++i) {
3102 flags = klass->methods [i]->flags;
3103 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3104 ++vcount;
3106 } else {
3107 int first_idx = mono_class_get_first_method_idx (klass);
3108 mcount = mono_class_get_method_count (klass);
3109 for (i = 0; i < mcount; ++i) {
3110 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
3112 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
3113 ++vcount;
3116 return vcount;
3119 static int
3120 find_interface (int num_ifaces, MonoClass **interfaces_full, MonoClass *ic)
3122 int m, l = 0;
3123 if (!num_ifaces)
3124 return -1;
3125 while (1) {
3126 if (l > num_ifaces)
3127 return -1;
3128 m = (l + num_ifaces) / 2;
3129 if (interfaces_full [m] == ic)
3130 return m;
3131 if (l == num_ifaces)
3132 return -1;
3133 if (!interfaces_full [m] || interfaces_full [m]->interface_id > ic->interface_id) {
3134 num_ifaces = m - 1;
3135 } else {
3136 l = m + 1;
3141 static mono_bool
3142 set_interface_and_offset (int num_ifaces, MonoClass **interfaces_full, int *interface_offsets_full, MonoClass *ic, int offset, mono_bool force_set)
3144 int i = find_interface (num_ifaces, interfaces_full, ic);
3145 if (i >= 0) {
3146 if (!force_set)
3147 return TRUE;
3148 interface_offsets_full [i] = offset;
3149 return FALSE;
3151 for (i = 0; i < num_ifaces; ++i) {
3152 if (interfaces_full [i]) {
3153 int end;
3154 if (interfaces_full [i]->interface_id < ic->interface_id)
3155 continue;
3156 end = i + 1;
3157 while (end < num_ifaces && interfaces_full [end]) end++;
3158 memmove (interfaces_full + i + 1, interfaces_full + i, sizeof (MonoClass*) * (end - i));
3159 memmove (interface_offsets_full + i + 1, interface_offsets_full + i, sizeof (int) * (end - i));
3161 interfaces_full [i] = ic;
3162 interface_offsets_full [i] = offset;
3163 break;
3165 return FALSE;
3168 #ifdef COMPRESSED_INTERFACE_BITMAP
3171 * Compressed interface bitmap design.
3173 * Interface bitmaps take a large amount of memory, because their size is
3174 * linear with the maximum interface id assigned in the process (each interface
3175 * is assigned a unique id as it is loaded). The number of interface classes
3176 * is high because of the many implicit interfaces implemented by arrays (we'll
3177 * need to lazy-load them in the future).
3178 * Most classes implement a very small number of interfaces, so the bitmap is
3179 * sparse. This bitmap needs to be checked by interface casts, so access to the
3180 * needed bit must be fast and doable with few jit instructions.
3182 * The current compression format is as follows:
3183 * *) it is a sequence of one or more two-byte elements
3184 * *) the first byte in the element is the count of empty bitmap bytes
3185 * at the current bitmap position
3186 * *) the second byte in the element is an actual bitmap byte at the current
3187 * bitmap position
3189 * As an example, the following compressed bitmap bytes:
3190 * 0x07 0x01 0x00 0x7
3191 * correspond to the following bitmap:
3192 * 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x07
3194 * Each two-byte element can represent up to 2048 bitmap bits, but as few as a single
3195 * bitmap byte for non-sparse sequences. In practice the interface bitmaps created
3196 * during a gmcs bootstrap are reduced to less tha 5% of the original size.
3200 * mono_compress_bitmap:
3201 * @dest: destination buffer
3202 * @bitmap: bitmap buffer
3203 * @size: size of @bitmap in bytes
3205 * This is a mono internal function.
3206 * The @bitmap data is compressed into a format that is small but
3207 * still searchable in few instructions by the JIT and runtime.
3208 * The compressed data is stored in the buffer pointed to by the
3209 * @dest array. Passing a #NULL value for @dest allows to just compute
3210 * the size of the buffer.
3211 * This compression algorithm assumes the bits set in the bitmap are
3212 * few and far between, like in interface bitmaps.
3213 * Returns: The size of the compressed bitmap in bytes.
3216 mono_compress_bitmap (uint8_t *dest, const uint8_t *bitmap, int size)
3218 int numz = 0;
3219 int res = 0;
3220 const uint8_t *end = bitmap + size;
3221 while (bitmap < end) {
3222 if (*bitmap || numz == 255) {
3223 if (dest) {
3224 *dest++ = numz;
3225 *dest++ = *bitmap;
3227 res += 2;
3228 numz = 0;
3229 bitmap++;
3230 continue;
3232 bitmap++;
3233 numz++;
3235 if (numz) {
3236 res += 2;
3237 if (dest) {
3238 *dest++ = numz;
3239 *dest++ = 0;
3242 return res;
3246 * mono_class_interface_match:
3247 * @bitmap: a compressed bitmap buffer
3248 * @id: the index to check in the bitmap
3250 * This is a mono internal function.
3251 * Checks if a bit is set in a compressed interface bitmap. @id must
3252 * be already checked for being smaller than the maximum id encoded in the
3253 * bitmap.
3255 * Returns: A non-zero value if bit @id is set in the bitmap @bitmap,
3256 * #FALSE otherwise.
3259 mono_class_interface_match (const uint8_t *bitmap, int id)
3261 while (TRUE) {
3262 id -= bitmap [0] * 8;
3263 if (id < 8) {
3264 if (id < 0)
3265 return 0;
3266 return bitmap [1] & (1 << id);
3268 bitmap += 2;
3269 id -= 8;
3272 #endif
3275 * Return -1 on failure and set klass->has_failure and store a MonoErrorBoxed with the details.
3276 * LOCKING: Acquires the loader lock.
3278 static int
3279 setup_interface_offsets (MonoClass *klass, int cur_slot, gboolean overwrite)
3281 MonoError error;
3282 MonoClass *k, *ic;
3283 int i, j, num_ifaces;
3284 guint32 max_iid;
3285 MonoClass **interfaces_full = NULL;
3286 int *interface_offsets_full = NULL;
3287 GPtrArray *ifaces;
3288 GPtrArray **ifaces_array = NULL;
3289 int interface_offsets_count;
3291 mono_loader_lock ();
3293 mono_class_setup_supertypes (klass);
3295 /* compute maximum number of slots and maximum interface id */
3296 max_iid = 0;
3297 num_ifaces = 0; /* this can include duplicated ones */
3298 ifaces_array = g_new0 (GPtrArray *, klass->idepth);
3299 for (j = 0; j < klass->idepth; j++) {
3300 k = klass->supertypes [j];
3301 g_assert (k);
3302 num_ifaces += k->interface_count;
3303 for (i = 0; i < k->interface_count; i++) {
3304 ic = k->interfaces [i];
3306 mono_class_init (ic);
3308 if (max_iid < ic->interface_id)
3309 max_iid = ic->interface_id;
3311 ifaces = mono_class_get_implemented_interfaces (k, &error);
3312 if (!mono_error_ok (&error)) {
3313 char *name = mono_type_get_full_name (k);
3314 mono_class_set_type_load_failure (klass, "Error getting the interfaces of %s due to %s", name, mono_error_get_message (&error));
3315 g_free (name);
3316 mono_error_cleanup (&error);
3317 cur_slot = -1;
3318 goto end;
3320 if (ifaces) {
3321 num_ifaces += ifaces->len;
3322 for (i = 0; i < ifaces->len; ++i) {
3323 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3324 if (max_iid < ic->interface_id)
3325 max_iid = ic->interface_id;
3327 ifaces_array [j] = ifaces;
3331 if (MONO_CLASS_IS_INTERFACE (klass)) {
3332 num_ifaces++;
3333 if (max_iid < klass->interface_id)
3334 max_iid = klass->interface_id;
3337 /* compute vtable offset for interfaces */
3338 interfaces_full = (MonoClass **)g_malloc0 (sizeof (MonoClass*) * num_ifaces);
3339 interface_offsets_full = (int *)g_malloc (sizeof (int) * num_ifaces);
3341 for (i = 0; i < num_ifaces; i++)
3342 interface_offsets_full [i] = -1;
3344 /* skip the current class */
3345 for (j = 0; j < klass->idepth - 1; j++) {
3346 k = klass->supertypes [j];
3347 ifaces = ifaces_array [j];
3349 if (ifaces) {
3350 for (i = 0; i < ifaces->len; ++i) {
3351 int io;
3352 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3354 /*Force the sharing of interface offsets between parent and subtypes.*/
3355 io = mono_class_interface_offset (k, ic);
3356 g_assert (io >= 0);
3357 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, io, TRUE);
3362 g_assert (klass == klass->supertypes [klass->idepth - 1]);
3363 ifaces = ifaces_array [klass->idepth - 1];
3364 if (ifaces) {
3365 for (i = 0; i < ifaces->len; ++i) {
3366 int count;
3367 ic = (MonoClass *)g_ptr_array_index (ifaces, i);
3368 if (set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, ic, cur_slot, FALSE))
3369 continue;
3370 count = count_virtual_methods (ic);
3371 if (count == -1) {
3372 char *name = mono_type_get_full_name (ic);
3373 mono_class_set_type_load_failure (klass, "Error calculating interface offset of %s", name);
3374 g_free (name);
3375 cur_slot = -1;
3376 goto end;
3378 cur_slot += count;
3382 if (MONO_CLASS_IS_INTERFACE (klass))
3383 set_interface_and_offset (num_ifaces, interfaces_full, interface_offsets_full, klass, cur_slot, TRUE);
3385 for (interface_offsets_count = 0, i = 0; i < num_ifaces; i++) {
3386 if (interface_offsets_full [i] != -1)
3387 interface_offsets_count ++;
3390 /* Publish the data */
3391 klass->max_interface_id = max_iid;
3393 * We might get called multiple times:
3394 * - mono_class_init ()
3395 * - mono_class_setup_vtable ().
3396 * - mono_class_setup_interface_offsets ().
3397 * mono_class_setup_interface_offsets () passes 0 as CUR_SLOT, so the computed interface offsets will be invalid. This
3398 * means we have to overwrite those when called from other places (#4440).
3400 if (klass->interfaces_packed) {
3401 if (!overwrite)
3402 g_assert (klass->interface_offsets_count == interface_offsets_count);
3403 } else {
3404 uint8_t *bitmap;
3405 int bsize;
3406 klass->interface_offsets_count = interface_offsets_count;
3407 klass->interfaces_packed = (MonoClass **)mono_class_alloc (klass, sizeof (MonoClass*) * interface_offsets_count);
3408 klass->interface_offsets_packed = (guint16 *)mono_class_alloc (klass, sizeof (guint16) * interface_offsets_count);
3409 bsize = (sizeof (guint8) * ((max_iid + 1) >> 3)) + (((max_iid + 1) & 7)? 1 :0);
3410 #ifdef COMPRESSED_INTERFACE_BITMAP
3411 bitmap = g_malloc0 (bsize);
3412 #else
3413 bitmap = (uint8_t *)mono_class_alloc0 (klass, bsize);
3414 #endif
3415 for (i = 0; i < interface_offsets_count; i++) {
3416 guint32 id = interfaces_full [i]->interface_id;
3417 bitmap [id >> 3] |= (1 << (id & 7));
3418 klass->interfaces_packed [i] = interfaces_full [i];
3419 klass->interface_offsets_packed [i] = interface_offsets_full [i];
3421 #ifdef COMPRESSED_INTERFACE_BITMAP
3422 i = mono_compress_bitmap (NULL, bitmap, bsize);
3423 klass->interface_bitmap = mono_class_alloc0 (klass, i);
3424 mono_compress_bitmap (klass->interface_bitmap, bitmap, bsize);
3425 g_free (bitmap);
3426 #else
3427 klass->interface_bitmap = bitmap;
3428 #endif
3430 end:
3431 mono_loader_unlock ();
3433 g_free (interfaces_full);
3434 g_free (interface_offsets_full);
3435 for (i = 0; i < klass->idepth; i++) {
3436 ifaces = ifaces_array [i];
3437 if (ifaces)
3438 g_ptr_array_free (ifaces, TRUE);
3440 g_free (ifaces_array);
3442 //printf ("JUST DONE: ");
3443 //print_implemented_interfaces (klass);
3445 return cur_slot;
3449 * Setup interface offsets for interfaces.
3450 * Initializes:
3451 * - klass->max_interface_id
3452 * - klass->interface_offsets_count
3453 * - klass->interfaces_packed
3454 * - klass->interface_offsets_packed
3455 * - klass->interface_bitmap
3457 * This function can fail @class.
3459 void
3460 mono_class_setup_interface_offsets (MonoClass *klass)
3462 setup_interface_offsets (klass, 0, FALSE);
3465 /*Checks if @klass has @parent as one of it's parents type gtd
3467 * For example:
3468 * Foo<T>
3469 * Bar<T> : Foo<Bar<Bar<T>>>
3472 static gboolean
3473 mono_class_has_gtd_parent (MonoClass *klass, MonoClass *parent)
3475 klass = mono_class_get_generic_type_definition (klass);
3476 parent = mono_class_get_generic_type_definition (parent);
3477 mono_class_setup_supertypes (klass);
3478 mono_class_setup_supertypes (parent);
3480 return klass->idepth >= parent->idepth &&
3481 mono_class_get_generic_type_definition (klass->supertypes [parent->idepth - 1]) == parent;
3484 gboolean
3485 mono_class_check_vtable_constraints (MonoClass *klass, GList *in_setup)
3487 MonoGenericInst *ginst;
3488 int i;
3490 if (!mono_class_is_ginst (klass)) {
3491 mono_class_setup_vtable_full (klass, in_setup);
3492 return !mono_class_has_failure (klass);
3495 mono_class_setup_vtable_full (mono_class_get_generic_type_definition (klass), in_setup);
3496 if (mono_class_set_type_load_failure_causedby_class (klass, mono_class_get_generic_class (klass)->container_class, "Failed to load generic definition vtable"))
3497 return FALSE;
3499 ginst = mono_class_get_generic_class (klass)->context.class_inst;
3500 for (i = 0; i < ginst->type_argc; ++i) {
3501 MonoClass *arg;
3502 if (ginst->type_argv [i]->type != MONO_TYPE_GENERICINST)
3503 continue;
3504 arg = mono_class_from_mono_type (ginst->type_argv [i]);
3505 /*Those 2 will be checked by mono_class_setup_vtable itself*/
3506 if (mono_class_has_gtd_parent (klass, arg) || mono_class_has_gtd_parent (arg, klass))
3507 continue;
3508 if (!mono_class_check_vtable_constraints (arg, in_setup)) {
3509 mono_class_set_type_load_failure (klass, "Failed to load generic parameter %d", i);
3510 return FALSE;
3513 return TRUE;
3517 * mono_class_setup_vtable:
3519 * Creates the generic vtable of CLASS.
3520 * Initializes the following fields in MonoClass:
3521 * - vtable
3522 * - vtable_size
3523 * Plus all the fields initialized by setup_interface_offsets ().
3524 * If there is an error during vtable construction, klass->has_failure
3525 * is set and details are stored in a MonoErrorBoxed.
3527 * LOCKING: Acquires the loader lock.
3529 void
3530 mono_class_setup_vtable (MonoClass *klass)
3532 mono_class_setup_vtable_full (klass, NULL);
3535 static void
3536 mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
3538 MonoError error;
3539 MonoMethod **overrides;
3540 MonoGenericContext *context;
3541 guint32 type_token;
3542 int onum = 0;
3543 gboolean ok = TRUE;
3545 if (klass->vtable)
3546 return;
3548 if (MONO_CLASS_IS_INTERFACE (klass)) {
3549 /* This sets method->slot for all methods if this is an interface */
3550 mono_class_setup_methods (klass);
3551 return;
3554 if (mono_class_has_failure (klass))
3555 return;
3557 if (g_list_find (in_setup, klass))
3558 return;
3560 mono_loader_lock ();
3562 if (klass->vtable) {
3563 mono_loader_unlock ();
3564 return;
3567 mono_stats.generic_vtable_count ++;
3568 in_setup = g_list_prepend (in_setup, klass);
3570 if (mono_class_is_ginst (klass)) {
3571 if (!mono_class_check_vtable_constraints (klass, in_setup)) {
3572 mono_loader_unlock ();
3573 g_list_remove (in_setup, klass);
3574 return;
3577 context = mono_class_get_context (klass);
3578 type_token = mono_class_get_generic_class (klass)->container_class->type_token;
3579 } else {
3580 context = (MonoGenericContext *) mono_class_try_get_generic_container (klass); //FIXME is this a case of a try?
3581 type_token = klass->type_token;
3584 if (image_is_dynamic (klass->image)) {
3585 /* Generic instances can have zero method overrides without causing any harm.
3586 * This is true since we don't do layout all over again for them, we simply inflate
3587 * the layout of the parent.
3589 mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
3590 if (!is_ok (&error)) {
3591 mono_loader_unlock ();
3592 g_list_remove (in_setup, klass);
3593 mono_class_set_type_load_failure (klass, "Could not load list of method overrides due to %s", mono_error_get_message (&error));
3594 mono_error_cleanup (&error);
3595 return;
3597 } else {
3598 /* The following call fails if there are missing methods in the type */
3599 /* FIXME it's probably a good idea to avoid this for generic instances. */
3600 ok = mono_class_get_overrides_full (klass->image, type_token, &overrides, &onum, context);
3603 if (ok)
3604 mono_class_setup_vtable_general (klass, overrides, onum, in_setup);
3605 else
3606 mono_class_set_type_load_failure (klass, "Could not load list of method overrides");
3608 g_free (overrides);
3610 mono_loader_unlock ();
3611 g_list_remove (in_setup, klass);
3613 return;
3616 #define DEBUG_INTERFACE_VTABLE_CODE 0
3617 #define TRACE_INTERFACE_VTABLE_CODE 0
3618 #define VERIFY_INTERFACE_VTABLE_CODE 0
3619 #define VTABLE_SELECTOR (1)
3621 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3622 #define DEBUG_INTERFACE_VTABLE(stmt) do {\
3623 if (!(VTABLE_SELECTOR)) break; \
3624 stmt;\
3625 } while (0)
3626 #else
3627 #define DEBUG_INTERFACE_VTABLE(stmt)
3628 #endif
3630 #if TRACE_INTERFACE_VTABLE_CODE
3631 #define TRACE_INTERFACE_VTABLE(stmt) do {\
3632 if (!(VTABLE_SELECTOR)) break; \
3633 stmt;\
3634 } while (0)
3635 #else
3636 #define TRACE_INTERFACE_VTABLE(stmt)
3637 #endif
3639 #if VERIFY_INTERFACE_VTABLE_CODE
3640 #define VERIFY_INTERFACE_VTABLE(stmt) do {\
3641 if (!(VTABLE_SELECTOR)) break; \
3642 stmt;\
3643 } while (0)
3644 #else
3645 #define VERIFY_INTERFACE_VTABLE(stmt)
3646 #endif
3649 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3650 static char*
3651 mono_signature_get_full_desc (MonoMethodSignature *sig, gboolean include_namespace)
3653 int i;
3654 char *result;
3655 GString *res = g_string_new ("");
3657 g_string_append_c (res, '(');
3658 for (i = 0; i < sig->param_count; ++i) {
3659 if (i > 0)
3660 g_string_append_c (res, ',');
3661 mono_type_get_desc (res, sig->params [i], include_namespace);
3663 g_string_append (res, ")=>");
3664 if (sig->ret != NULL) {
3665 mono_type_get_desc (res, sig->ret, include_namespace);
3666 } else {
3667 g_string_append (res, "NULL");
3669 result = res->str;
3670 g_string_free (res, FALSE);
3671 return result;
3673 static void
3674 print_method_signatures (MonoMethod *im, MonoMethod *cm) {
3675 char *im_sig = mono_signature_get_full_desc (mono_method_signature (im), TRUE);
3676 char *cm_sig = mono_signature_get_full_desc (mono_method_signature (cm), TRUE);
3677 printf ("(IM \"%s\", CM \"%s\")", im_sig, cm_sig);
3678 g_free (im_sig);
3679 g_free (cm_sig);
3683 #endif
3684 static gboolean
3685 is_wcf_hack_disabled (void)
3687 static gboolean disabled;
3688 static gboolean inited = FALSE;
3689 if (!inited) {
3690 disabled = g_getenv ("MONO_DISABLE_WCF_HACK") != NULL;
3691 inited = TRUE;
3693 return disabled;
3696 static gboolean
3697 check_interface_method_override (MonoClass *klass, MonoMethod *im, MonoMethod *cm, gboolean require_newslot, gboolean interface_is_explicitly_implemented_by_class, gboolean slot_is_empty)
3699 MonoMethodSignature *cmsig, *imsig;
3700 if (strcmp (im->name, cm->name) == 0) {
3701 if (! (cm->flags & METHOD_ATTRIBUTE_PUBLIC)) {
3702 TRACE_INTERFACE_VTABLE (printf ("[PUBLIC CHECK FAILED]"));
3703 return FALSE;
3705 if (! slot_is_empty) {
3706 if (require_newslot) {
3707 if (! interface_is_explicitly_implemented_by_class) {
3708 TRACE_INTERFACE_VTABLE (printf ("[NOT EXPLICIT IMPLEMENTATION IN FULL SLOT REFUSED]"));
3709 return FALSE;
3711 if (! (cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
3712 TRACE_INTERFACE_VTABLE (printf ("[NEWSLOT CHECK FAILED]"));
3713 return FALSE;
3715 } else {
3716 TRACE_INTERFACE_VTABLE (printf ("[FULL SLOT REFUSED]"));
3719 cmsig = mono_method_signature (cm);
3720 imsig = mono_method_signature (im);
3721 if (!cmsig || !imsig) {
3722 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
3723 return FALSE;
3726 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3727 TRACE_INTERFACE_VTABLE (printf ("[SIGNATURE CHECK FAILED "));
3728 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3729 TRACE_INTERFACE_VTABLE (printf ("]"));
3730 return FALSE;
3732 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS]"));
3733 if (mono_security_core_clr_enabled ())
3734 mono_security_core_clr_check_override (klass, cm, im);
3736 TRACE_INTERFACE_VTABLE (printf ("[NAME CHECK OK]"));
3737 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3738 char *body_name = mono_method_full_name (cm, TRUE);
3739 char *decl_name = mono_method_full_name (im, TRUE);
3740 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3741 g_free (body_name);
3742 g_free (decl_name);
3743 return FALSE;
3746 return TRUE;
3747 } else {
3748 MonoClass *ic = im->klass;
3749 const char *ic_name_space = ic->name_space;
3750 const char *ic_name = ic->name;
3751 char *subname;
3753 if (! require_newslot) {
3754 TRACE_INTERFACE_VTABLE (printf ("[INJECTED METHOD REFUSED]"));
3755 return FALSE;
3757 if (cm->klass->rank == 0) {
3758 TRACE_INTERFACE_VTABLE (printf ("[RANK CHECK FAILED]"));
3759 return FALSE;
3761 cmsig = mono_method_signature (cm);
3762 imsig = mono_method_signature (im);
3763 if (!cmsig || !imsig) {
3764 mono_class_set_type_load_failure (klass, "Could not resolve the signature of a virtual method");
3765 return FALSE;
3768 if (! mono_metadata_signature_equal (cmsig, imsig)) {
3769 TRACE_INTERFACE_VTABLE (printf ("[(INJECTED) SIGNATURE CHECK FAILED "));
3770 TRACE_INTERFACE_VTABLE (print_method_signatures (im, cm));
3771 TRACE_INTERFACE_VTABLE (printf ("]"));
3772 return FALSE;
3774 if (mono_class_get_image (ic) != mono_defaults.corlib) {
3775 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE CORLIB CHECK FAILED]"));
3776 return FALSE;
3778 if ((ic_name_space == NULL) || (strcmp (ic_name_space, "System.Collections.Generic") != 0)) {
3779 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAMESPACE CHECK FAILED]"));
3780 return FALSE;
3782 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))) {
3783 TRACE_INTERFACE_VTABLE (printf ("[INTERFACE NAME CHECK FAILED]"));
3784 return FALSE;
3787 subname = strstr (cm->name, ic_name_space);
3788 if (subname != cm->name) {
3789 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL NAMESPACE CHECK FAILED]"));
3790 return FALSE;
3792 subname += strlen (ic_name_space);
3793 if (subname [0] != '.') {
3794 TRACE_INTERFACE_VTABLE (printf ("[FIRST DOT CHECK FAILED]"));
3795 return FALSE;
3797 subname ++;
3798 if (strstr (subname, ic_name) != subname) {
3799 TRACE_INTERFACE_VTABLE (printf ("[ACTUAL CLASS NAME CHECK FAILED]"));
3800 return FALSE;
3802 subname += strlen (ic_name);
3803 if (subname [0] != '.') {
3804 TRACE_INTERFACE_VTABLE (printf ("[SECOND DOT CHECK FAILED]"));
3805 return FALSE;
3807 subname ++;
3808 if (strcmp (subname, im->name) != 0) {
3809 TRACE_INTERFACE_VTABLE (printf ("[METHOD NAME CHECK FAILED]"));
3810 return FALSE;
3813 TRACE_INTERFACE_VTABLE (printf ("[SECURITY CHECKS (INJECTED CASE)]"));
3814 if (mono_security_core_clr_enabled ())
3815 mono_security_core_clr_check_override (klass, cm, im);
3817 TRACE_INTERFACE_VTABLE (printf ("[INJECTED INTERFACE CHECK OK]"));
3818 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, im, NULL)) {
3819 char *body_name = mono_method_full_name (cm, TRUE);
3820 char *decl_name = mono_method_full_name (im, TRUE);
3821 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
3822 g_free (body_name);
3823 g_free (decl_name);
3824 return FALSE;
3827 return TRUE;
3831 #if (TRACE_INTERFACE_VTABLE_CODE|DEBUG_INTERFACE_VTABLE_CODE)
3832 static void
3833 foreach_override (gpointer key, gpointer value, gpointer user_data) {
3834 MonoMethod *method = key;
3835 MonoMethod *override = value;
3836 MonoClass *method_class = mono_method_get_class (method);
3837 MonoClass *override_class = mono_method_get_class (override);
3839 printf (" Method '%s.%s:%s' has override '%s.%s:%s'\n",
3840 mono_class_get_namespace (method_class), mono_class_get_name (method_class), mono_method_get_name (method),
3841 mono_class_get_namespace (override_class), mono_class_get_name (override_class), mono_method_get_name (override));
3843 static void
3844 print_overrides (GHashTable *override_map, const char *message) {
3845 if (override_map) {
3846 printf ("Override map \"%s\" START:\n", message);
3847 g_hash_table_foreach (override_map, foreach_override, NULL);
3848 printf ("Override map \"%s\" END.\n", message);
3849 } else {
3850 printf ("Override map \"%s\" EMPTY.\n", message);
3853 static void
3854 print_vtable_full (MonoClass *klass, MonoMethod** vtable, int size, int first_non_interface_slot, const char *message, gboolean print_interfaces) {
3855 char *full_name = mono_type_full_name (&klass->byval_arg);
3856 int i;
3857 int parent_size;
3859 printf ("*** Vtable for class '%s' at \"%s\" (size %d)\n", full_name, message, size);
3861 if (print_interfaces) {
3862 print_implemented_interfaces (klass);
3863 printf ("* Interfaces for class '%s' done.\nStarting vtable (size %d):\n", full_name, size);
3866 if (klass->parent) {
3867 parent_size = klass->parent->vtable_size;
3868 } else {
3869 parent_size = 0;
3871 for (i = 0; i < size; ++i) {
3872 MonoMethod *cm = vtable [i];
3873 char *cm_name = cm ? mono_method_full_name (cm, TRUE) : g_strdup ("nil");
3874 char newness = (i < parent_size) ? 'O' : ((i < first_non_interface_slot) ? 'I' : 'N');
3876 printf (" [%c][%03d][INDEX %03d] %s [%p]\n", newness, i, cm ? cm->slot : - 1, cm_name, cm);
3877 g_free (cm_name);
3880 g_free (full_name);
3882 #endif
3884 #if VERIFY_INTERFACE_VTABLE_CODE
3885 static int
3886 mono_method_try_get_vtable_index (MonoMethod *method)
3888 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
3889 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
3890 if (imethod->declaring->is_generic)
3891 return imethod->declaring->slot;
3893 return method->slot;
3896 static void
3897 mono_class_verify_vtable (MonoClass *klass)
3899 int i, count;
3900 char *full_name = mono_type_full_name (&klass->byval_arg);
3902 printf ("*** Verifying VTable of class '%s' \n", full_name);
3903 g_free (full_name);
3904 full_name = NULL;
3906 if (!klass->methods)
3907 return;
3909 count = mono_class_method_count (klass);
3910 for (i = 0; i < count; ++i) {
3911 MonoMethod *cm = klass->methods [i];
3912 int slot;
3914 if (!(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
3915 continue;
3917 g_free (full_name);
3918 full_name = mono_method_full_name (cm, TRUE);
3920 slot = mono_method_try_get_vtable_index (cm);
3921 if (slot >= 0) {
3922 if (slot >= klass->vtable_size) {
3923 printf ("\tInvalid method %s at index %d with vtable of length %d\n", full_name, slot, klass->vtable_size);
3924 continue;
3927 if (slot >= 0 && klass->vtable [slot] != cm && (klass->vtable [slot])) {
3928 char *other_name = klass->vtable [slot] ? mono_method_full_name (klass->vtable [slot], TRUE) : g_strdup ("[null value]");
3929 printf ("\tMethod %s has slot %d but vtable has %s on it\n", full_name, slot, other_name);
3930 g_free (other_name);
3932 } else
3933 printf ("\tVirtual method %s does n't have an assigned slot\n", full_name);
3935 g_free (full_name);
3937 #endif
3939 static void
3940 print_unimplemented_interface_method_info (MonoClass *klass, MonoClass *ic, MonoMethod *im, int im_slot, MonoMethod **overrides, int onum)
3942 int index, mcount;
3943 char *method_signature;
3944 char *type_name;
3946 for (index = 0; index < onum; ++index) {
3947 mono_trace_warning (MONO_TRACE_TYPE, " at slot %d: %s (%d) overrides %s (%d)", im_slot, overrides [index*2+1]->name,
3948 overrides [index*2+1]->slot, overrides [index*2]->name, overrides [index*2]->slot);
3950 method_signature = mono_signature_get_desc (mono_method_signature (im), FALSE);
3951 type_name = mono_type_full_name (&klass->byval_arg);
3952 mono_trace_warning (MONO_TRACE_TYPE, "no implementation for interface method %s::%s(%s) in class %s",
3953 mono_type_get_name (&ic->byval_arg), im->name, method_signature, type_name);
3954 g_free (method_signature);
3955 g_free (type_name);
3956 mono_class_setup_methods (klass);
3957 if (mono_class_has_failure (klass)) {
3958 char *name = mono_type_get_full_name (klass);
3959 mono_trace_warning (MONO_TRACE_TYPE, "CLASS %s failed to resolve methods", name);
3960 g_free (name);
3961 return;
3963 mcount = mono_class_get_method_count (klass);
3964 for (index = 0; index < mcount; ++index) {
3965 MonoMethod *cm = klass->methods [index];
3966 method_signature = mono_signature_get_desc (mono_method_signature (cm), TRUE);
3968 mono_trace_warning (MONO_TRACE_TYPE, "METHOD %s(%s)", cm->name, method_signature);
3969 g_free (method_signature);
3973 static MonoMethod*
3974 mono_method_get_method_definition (MonoMethod *method)
3976 while (method->is_inflated)
3977 method = ((MonoMethodInflated*)method)->declaring;
3978 return method;
3981 static gboolean
3982 verify_class_overrides (MonoClass *klass, MonoMethod **overrides, int onum)
3984 int i;
3986 for (i = 0; i < onum; ++i) {
3987 MonoMethod *decl = overrides [i * 2];
3988 MonoMethod *body = overrides [i * 2 + 1];
3990 if (mono_class_get_generic_type_definition (body->klass) != mono_class_get_generic_type_definition (klass)) {
3991 mono_class_set_type_load_failure (klass, "Method belongs to a different class than the declared one");
3992 return FALSE;
3995 if (!(body->flags & METHOD_ATTRIBUTE_VIRTUAL) || (body->flags & METHOD_ATTRIBUTE_STATIC)) {
3996 if (body->flags & METHOD_ATTRIBUTE_STATIC)
3997 mono_class_set_type_load_failure (klass, "Method must not be static to override a base type");
3998 else
3999 mono_class_set_type_load_failure (klass, "Method must be virtual to override a base type");
4000 return FALSE;
4003 if (!(decl->flags & METHOD_ATTRIBUTE_VIRTUAL) || (decl->flags & METHOD_ATTRIBUTE_STATIC)) {
4004 if (body->flags & METHOD_ATTRIBUTE_STATIC)
4005 mono_class_set_type_load_failure (klass, "Cannot override a static method in a base type");
4006 else
4007 mono_class_set_type_load_failure (klass, "Cannot override a non virtual method in a base type");
4008 return FALSE;
4011 if (!mono_class_is_assignable_from_slow (decl->klass, klass)) {
4012 mono_class_set_type_load_failure (klass, "Method overrides a class or interface that is not extended or implemented by this type");
4013 return FALSE;
4016 body = mono_method_get_method_definition (body);
4017 decl = mono_method_get_method_definition (decl);
4019 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (body, decl, NULL)) {
4020 char *body_name = mono_method_full_name (body, TRUE);
4021 char *decl_name = mono_method_full_name (decl, TRUE);
4022 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4023 g_free (body_name);
4024 g_free (decl_name);
4025 return FALSE;
4028 return TRUE;
4031 static gboolean
4032 mono_class_need_stelemref_method (MonoClass *klass)
4034 return klass->rank == 1 && MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg);
4038 * LOCKING: this is supposed to be called with the loader lock held.
4040 void
4041 mono_class_setup_vtable_general (MonoClass *klass, MonoMethod **overrides, int onum, GList *in_setup)
4043 MonoError error;
4044 MonoClass *k, *ic;
4045 MonoMethod **vtable = NULL;
4046 int i, max_vtsize = 0, cur_slot = 0;
4047 guint32 max_iid;
4048 GPtrArray *ifaces = NULL;
4049 GHashTable *override_map = NULL;
4050 MonoMethod *cm;
4051 #if (DEBUG_INTERFACE_VTABLE_CODE|TRACE_INTERFACE_VTABLE_CODE)
4052 int first_non_interface_slot;
4053 #endif
4054 GSList *virt_methods = NULL, *l;
4055 int stelemref_slot = 0;
4057 if (klass->vtable)
4058 return;
4060 if (overrides && !verify_class_overrides (klass, overrides, onum))
4061 return;
4063 ifaces = mono_class_get_implemented_interfaces (klass, &error);
4064 if (!mono_error_ok (&error)) {
4065 char *name = mono_type_get_full_name (klass);
4066 mono_class_set_type_load_failure (klass, "Could not resolve %s interfaces due to %s", name, mono_error_get_message (&error));
4067 g_free (name);
4068 mono_error_cleanup (&error);
4069 return;
4070 } else if (ifaces) {
4071 for (i = 0; i < ifaces->len; i++) {
4072 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
4073 max_vtsize += mono_class_get_method_count (ic);
4075 g_ptr_array_free (ifaces, TRUE);
4076 ifaces = NULL;
4079 if (klass->parent) {
4080 mono_class_init (klass->parent);
4081 mono_class_setup_vtable_full (klass->parent, in_setup);
4083 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class failed to load"))
4084 return;
4086 max_vtsize += klass->parent->vtable_size;
4087 cur_slot = klass->parent->vtable_size;
4090 max_vtsize += mono_class_get_method_count (klass);
4092 /*Array have a slot for stelemref*/
4093 if (mono_class_need_stelemref_method (klass)) {
4094 stelemref_slot = cur_slot;
4095 ++max_vtsize;
4096 ++cur_slot;
4099 /* printf ("METAINIT %s.%s\n", klass->name_space, klass->name); */
4101 cur_slot = setup_interface_offsets (klass, cur_slot, TRUE);
4102 if (cur_slot == -1) /*setup_interface_offsets fails the type.*/
4103 return;
4105 max_iid = klass->max_interface_id;
4106 DEBUG_INTERFACE_VTABLE (first_non_interface_slot = cur_slot);
4108 /* Optimized version for generic instances */
4109 if (mono_class_is_ginst (klass)) {
4110 MonoError error;
4111 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4112 MonoMethod **tmp;
4114 mono_class_setup_vtable_full (gklass, in_setup);
4115 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Could not load generic definition"))
4116 return;
4118 tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * gklass->vtable_size);
4119 klass->vtable_size = gklass->vtable_size;
4120 for (i = 0; i < gklass->vtable_size; ++i)
4121 if (gklass->vtable [i]) {
4122 MonoMethod *inflated = mono_class_inflate_generic_method_full_checked (gklass->vtable [i], klass, mono_class_get_context (klass), &error);
4123 if (!mono_error_ok (&error)) {
4124 mono_class_set_type_load_failure (klass, "Could not inflate method due to %s", mono_error_get_message (&error));
4125 mono_error_cleanup (&error);
4126 return;
4128 tmp [i] = inflated;
4129 tmp [i]->slot = gklass->vtable [i]->slot;
4131 mono_memory_barrier ();
4132 klass->vtable = tmp;
4134 /* Have to set method->slot for abstract virtual methods */
4135 if (klass->methods && gklass->methods) {
4136 int mcount = mono_class_get_method_count (klass);
4137 for (i = 0; i < mcount; ++i)
4138 if (klass->methods [i]->slot == -1)
4139 klass->methods [i]->slot = gklass->methods [i]->slot;
4142 return;
4145 vtable = (MonoMethod **)g_malloc0 (sizeof (gpointer) * max_vtsize);
4147 if (klass->parent && klass->parent->vtable_size) {
4148 MonoClass *parent = klass->parent;
4149 int i;
4151 memcpy (vtable, parent->vtable, sizeof (gpointer) * parent->vtable_size);
4153 // Also inherit parent interface vtables, just as a starting point.
4154 // This is needed otherwise bug-77127.exe fails when the property methods
4155 // have different names in the iterface and the class, because for child
4156 // classes the ".override" information is not used anymore.
4157 for (i = 0; i < parent->interface_offsets_count; i++) {
4158 MonoClass *parent_interface = parent->interfaces_packed [i];
4159 int interface_offset = mono_class_interface_offset (klass, parent_interface);
4160 /*FIXME this is now dead code as this condition will never hold true.
4161 Since interface offsets are inherited then the offset of an interface implemented
4162 by a parent will never be the out of it's vtable boundary.
4164 if (interface_offset >= parent->vtable_size) {
4165 int parent_interface_offset = mono_class_interface_offset (parent, parent_interface);
4166 int j;
4168 mono_class_setup_methods (parent_interface); /*FIXME Just kill this whole chunk of dead code*/
4169 TRACE_INTERFACE_VTABLE (printf (" +++ Inheriting interface %s.%s\n", parent_interface->name_space, parent_interface->name));
4170 int mcount = mono_class_get_method_count (parent_interface);
4171 for (j = 0; j < mcount && !mono_class_has_failure (klass); j++) {
4172 vtable [interface_offset + j] = parent->vtable [parent_interface_offset + j];
4173 TRACE_INTERFACE_VTABLE (printf (" --- Inheriting: [%03d][(%03d)+(%03d)] => [%03d][(%03d)+(%03d)]\n",
4174 parent_interface_offset + j, parent_interface_offset, j,
4175 interface_offset + j, interface_offset, j));
4182 /*Array have a slot for stelemref*/
4183 if (mono_class_need_stelemref_method (klass)) {
4184 MonoMethod *method = mono_marshal_get_virtual_stelemref (klass);
4185 if (!method->slot)
4186 method->slot = stelemref_slot;
4187 else
4188 g_assert (method->slot == stelemref_slot);
4190 vtable [stelemref_slot] = method;
4193 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER INHERITING PARENT VTABLE", TRUE));
4194 /* override interface methods */
4195 for (i = 0; i < onum; i++) {
4196 MonoMethod *decl = overrides [i*2];
4197 if (MONO_CLASS_IS_INTERFACE (decl->klass)) {
4198 int dslot;
4199 dslot = mono_method_get_vtable_slot (decl);
4200 if (dslot == -1) {
4201 mono_class_set_type_load_failure (klass, "");
4202 goto fail;
4205 dslot += mono_class_interface_offset (klass, decl->klass);
4206 vtable [dslot] = overrides [i*2 + 1];
4207 vtable [dslot]->slot = dslot;
4208 if (!override_map)
4209 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4211 g_hash_table_insert (override_map, overrides [i * 2], overrides [i * 2 + 1]);
4213 if (mono_security_core_clr_enabled ())
4214 mono_security_core_clr_check_override (klass, vtable [dslot], decl);
4217 TRACE_INTERFACE_VTABLE (print_overrides (override_map, "AFTER OVERRIDING INTERFACE METHODS"));
4218 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER OVERRIDING INTERFACE METHODS", FALSE));
4221 * Create a list of virtual methods to avoid calling
4222 * mono_class_get_virtual_methods () which is slow because of the metadata
4223 * optimization.
4226 gpointer iter = NULL;
4227 MonoMethod *cm;
4229 virt_methods = NULL;
4230 while ((cm = mono_class_get_virtual_methods (klass, &iter))) {
4231 virt_methods = g_slist_prepend (virt_methods, cm);
4233 if (mono_class_has_failure (klass))
4234 goto fail;
4237 // Loop on all implemented interfaces...
4238 for (i = 0; i < klass->interface_offsets_count; i++) {
4239 MonoClass *parent = klass->parent;
4240 int ic_offset;
4241 gboolean interface_is_explicitly_implemented_by_class;
4242 int im_index;
4244 ic = klass->interfaces_packed [i];
4245 ic_offset = mono_class_interface_offset (klass, ic);
4247 mono_class_setup_methods (ic);
4248 if (mono_class_has_failure (ic))
4249 goto fail;
4251 // Check if this interface is explicitly implemented (instead of just inherited)
4252 if (parent != NULL) {
4253 int implemented_interfaces_index;
4254 interface_is_explicitly_implemented_by_class = FALSE;
4255 for (implemented_interfaces_index = 0; implemented_interfaces_index < klass->interface_count; implemented_interfaces_index++) {
4256 if (ic == klass->interfaces [implemented_interfaces_index]) {
4257 interface_is_explicitly_implemented_by_class = TRUE;
4258 break;
4261 } else {
4262 interface_is_explicitly_implemented_by_class = TRUE;
4265 // Loop on all interface methods...
4266 int mcount = mono_class_get_method_count (ic);
4267 for (im_index = 0; im_index < mcount; im_index++) {
4268 MonoMethod *im = ic->methods [im_index];
4269 int im_slot = ic_offset + im->slot;
4270 MonoMethod *override_im = (override_map != NULL) ? (MonoMethod *)g_hash_table_lookup (override_map, im) : NULL;
4272 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4273 continue;
4275 TRACE_INTERFACE_VTABLE (printf ("\tchecking iface method %s\n", mono_method_full_name (im,1)));
4277 // If there is an explicit implementation, just use it right away,
4278 // otherwise look for a matching method
4279 if (override_im == NULL) {
4280 int cm_index;
4281 MonoMethod *cm;
4283 // First look for a suitable method among the class methods
4284 for (l = virt_methods; l; l = l->next) {
4285 cm = (MonoMethod *)l->data;
4286 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)));
4287 if (check_interface_method_override (klass, im, cm, TRUE, interface_is_explicitly_implemented_by_class, (vtable [im_slot] == NULL))) {
4288 TRACE_INTERFACE_VTABLE (printf ("[check ok]: ASSIGNING"));
4289 vtable [im_slot] = cm;
4290 /* Why do we need this? */
4291 if (cm->slot < 0) {
4292 cm->slot = im_slot;
4295 TRACE_INTERFACE_VTABLE (printf ("\n"));
4296 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4297 goto fail;
4300 // If the slot is still empty, look in all the inherited virtual methods...
4301 if ((vtable [im_slot] == NULL) && klass->parent != NULL) {
4302 MonoClass *parent = klass->parent;
4303 // Reverse order, so that last added methods are preferred
4304 for (cm_index = parent->vtable_size - 1; cm_index >= 0; cm_index--) {
4305 MonoMethod *cm = parent->vtable [cm_index];
4307 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));
4308 if ((cm != NULL) && check_interface_method_override (klass, im, cm, FALSE, FALSE, TRUE)) {
4309 TRACE_INTERFACE_VTABLE (printf ("[everything ok]: ASSIGNING"));
4310 vtable [im_slot] = cm;
4311 /* Why do we need this? */
4312 if (cm->slot < 0) {
4313 cm->slot = im_slot;
4315 break;
4317 if (mono_class_has_failure (klass)) /*Might be set by check_interface_method_override*/
4318 goto fail;
4319 TRACE_INTERFACE_VTABLE ((cm != NULL) && printf ("\n"));
4322 } else {
4323 g_assert (vtable [im_slot] == override_im);
4328 // If the class is not abstract, check that all its interface slots are full.
4329 // The check is done here and not directly at the end of the loop above because
4330 // it can happen (for injected generic array interfaces) that the same slot is
4331 // processed multiple times (those interfaces have overlapping slots), and it
4332 // will not always be the first pass the one that fills the slot.
4333 if (!mono_class_is_abstract (klass)) {
4334 for (i = 0; i < klass->interface_offsets_count; i++) {
4335 int ic_offset;
4336 int im_index;
4338 ic = klass->interfaces_packed [i];
4339 ic_offset = mono_class_interface_offset (klass, ic);
4341 int mcount = mono_class_get_method_count (ic);
4342 for (im_index = 0; im_index < mcount; im_index++) {
4343 MonoMethod *im = ic->methods [im_index];
4344 int im_slot = ic_offset + im->slot;
4346 if (im->flags & METHOD_ATTRIBUTE_STATIC)
4347 continue;
4349 TRACE_INTERFACE_VTABLE (printf (" [class is not abstract, checking slot %d for interface '%s'.'%s', method %s, slot check is %d]\n",
4350 im_slot, ic->name_space, ic->name, im->name, (vtable [im_slot] == NULL)));
4351 if (vtable [im_slot] == NULL) {
4352 print_unimplemented_interface_method_info (klass, ic, im, im_slot, overrides, onum);
4353 goto fail;
4359 TRACE_INTERFACE_VTABLE (print_vtable_full (klass, vtable, cur_slot, first_non_interface_slot, "AFTER SETTING UP INTERFACE METHODS", FALSE));
4360 for (l = virt_methods; l; l = l->next) {
4361 cm = (MonoMethod *)l->data;
4363 * If the method is REUSE_SLOT, we must check in the
4364 * base class for a method to override.
4366 if (!(cm->flags & METHOD_ATTRIBUTE_NEW_SLOT)) {
4367 int slot = -1;
4368 for (k = klass->parent; k ; k = k->parent) {
4369 gpointer k_iter;
4370 MonoMethod *m1;
4372 k_iter = NULL;
4373 while ((m1 = mono_class_get_virtual_methods (k, &k_iter))) {
4374 MonoMethodSignature *cmsig, *m1sig;
4376 cmsig = mono_method_signature (cm);
4377 m1sig = mono_method_signature (m1);
4379 if (!cmsig || !m1sig) {
4380 /* FIXME proper error message */
4381 mono_class_set_type_load_failure (klass, "");
4382 return;
4385 if (!strcmp(cm->name, m1->name) &&
4386 mono_metadata_signature_equal (cmsig, m1sig)) {
4388 if (mono_security_core_clr_enabled ())
4389 mono_security_core_clr_check_override (klass, cm, m1);
4391 slot = mono_method_get_vtable_slot (m1);
4392 if (slot == -1)
4393 goto fail;
4395 if (is_wcf_hack_disabled () && !mono_method_can_access_method_full (cm, m1, NULL)) {
4396 char *body_name = mono_method_full_name (cm, TRUE);
4397 char *decl_name = mono_method_full_name (m1, TRUE);
4398 mono_class_set_type_load_failure (klass, "Method %s overrides method '%s' which is not accessible", body_name, decl_name);
4399 g_free (body_name);
4400 g_free (decl_name);
4401 goto fail;
4404 g_assert (cm->slot < max_vtsize);
4405 if (!override_map)
4406 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4407 TRACE_INTERFACE_VTABLE (printf ("adding iface override from %s [%p] to %s [%p]\n",
4408 mono_method_full_name (m1, 1), m1,
4409 mono_method_full_name (cm, 1), cm));
4410 g_hash_table_insert (override_map, m1, cm);
4411 break;
4414 if (mono_class_has_failure (k))
4415 goto fail;
4417 if (slot >= 0)
4418 break;
4420 if (slot >= 0)
4421 cm->slot = slot;
4424 /*Non final newslot methods must be given a non-interface vtable slot*/
4425 if ((cm->flags & METHOD_ATTRIBUTE_NEW_SLOT) && !(cm->flags & METHOD_ATTRIBUTE_FINAL) && cm->slot >= 0)
4426 cm->slot = -1;
4428 if (cm->slot < 0)
4429 cm->slot = cur_slot++;
4431 if (!(cm->flags & METHOD_ATTRIBUTE_ABSTRACT))
4432 vtable [cm->slot] = cm;
4435 /* override non interface methods */
4436 for (i = 0; i < onum; i++) {
4437 MonoMethod *decl = overrides [i*2];
4438 if (!MONO_CLASS_IS_INTERFACE (decl->klass)) {
4439 g_assert (decl->slot != -1);
4440 vtable [decl->slot] = overrides [i*2 + 1];
4441 overrides [i * 2 + 1]->slot = decl->slot;
4442 if (!override_map)
4443 override_map = g_hash_table_new (mono_aligned_addr_hash, NULL);
4444 TRACE_INTERFACE_VTABLE (printf ("adding explicit override from %s [%p] to %s [%p]\n",
4445 mono_method_full_name (decl, 1), decl,
4446 mono_method_full_name (overrides [i * 2 + 1], 1), overrides [i * 2 + 1]));
4447 g_hash_table_insert (override_map, decl, overrides [i * 2 + 1]);
4449 if (mono_security_core_clr_enabled ())
4450 mono_security_core_clr_check_override (klass, vtable [decl->slot], decl);
4455 * If a method occupies more than one place in the vtable, and it is
4456 * overriden, then change the other occurances too.
4458 if (override_map) {
4459 MonoMethod *cm;
4461 for (i = 0; i < max_vtsize; ++i)
4462 if (vtable [i]) {
4463 TRACE_INTERFACE_VTABLE (printf ("checking slot %d method %s[%p] for overrides\n", i, mono_method_full_name (vtable [i], 1), vtable [i]));
4465 cm = (MonoMethod *)g_hash_table_lookup (override_map, vtable [i]);
4466 if (cm)
4467 vtable [i] = cm;
4470 g_hash_table_destroy (override_map);
4471 override_map = NULL;
4474 g_slist_free (virt_methods);
4475 virt_methods = NULL;
4477 g_assert (cur_slot <= max_vtsize);
4479 /* Ensure that all vtable slots are filled with concrete instance methods */
4480 if (!mono_class_is_abstract (klass)) {
4481 for (i = 0; i < cur_slot; ++i) {
4482 if (vtable [i] == NULL || (vtable [i]->flags & (METHOD_ATTRIBUTE_ABSTRACT | METHOD_ATTRIBUTE_STATIC))) {
4483 char *type_name = mono_type_get_full_name (klass);
4484 char *method_name = vtable [i] ? mono_method_full_name (vtable [i], TRUE) : g_strdup ("none");
4485 mono_class_set_type_load_failure (klass, "Type %s has invalid vtable method slot %d with method %s", type_name, i, method_name);
4486 g_free (type_name);
4487 g_free (method_name);
4488 g_free (vtable);
4489 return;
4494 if (mono_class_is_ginst (klass)) {
4495 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4497 mono_class_init (gklass);
4499 klass->vtable_size = MAX (gklass->vtable_size, cur_slot);
4500 } else {
4501 /* Check that the vtable_size value computed in mono_class_init () is correct */
4502 if (klass->vtable_size)
4503 g_assert (cur_slot == klass->vtable_size);
4504 klass->vtable_size = cur_slot;
4507 /* Try to share the vtable with our parent. */
4508 if (klass->parent && (klass->parent->vtable_size == klass->vtable_size) && (memcmp (klass->parent->vtable, vtable, sizeof (gpointer) * klass->vtable_size) == 0)) {
4509 mono_memory_barrier ();
4510 klass->vtable = klass->parent->vtable;
4511 } else {
4512 MonoMethod **tmp = (MonoMethod **)mono_class_alloc0 (klass, sizeof (gpointer) * klass->vtable_size);
4513 memcpy (tmp, vtable, sizeof (gpointer) * klass->vtable_size);
4514 mono_memory_barrier ();
4515 klass->vtable = tmp;
4518 DEBUG_INTERFACE_VTABLE (print_vtable_full (klass, klass->vtable, klass->vtable_size, first_non_interface_slot, "FINALLY", FALSE));
4519 if (mono_print_vtable) {
4520 int icount = 0;
4522 print_implemented_interfaces (klass);
4524 for (i = 0; i <= max_iid; i++)
4525 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, i))
4526 icount++;
4528 printf ("VTable %s (vtable entries = %d, interfaces = %d)\n", mono_type_full_name (&klass->byval_arg),
4529 klass->vtable_size, icount);
4531 for (i = 0; i < cur_slot; ++i) {
4532 MonoMethod *cm;
4534 cm = vtable [i];
4535 if (cm) {
4536 printf (" slot assigned: %03d, slot index: %03d %s\n", i, cm->slot,
4537 mono_method_full_name (cm, TRUE));
4542 if (icount) {
4543 printf ("Interfaces %s.%s (max_iid = %d)\n", klass->name_space,
4544 klass->name, max_iid);
4546 for (i = 0; i < klass->interface_count; i++) {
4547 ic = klass->interfaces [i];
4548 printf (" slot offset: %03d, method count: %03d, iid: %03d %s\n",
4549 mono_class_interface_offset (klass, ic),
4550 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4553 for (k = klass->parent; k ; k = k->parent) {
4554 for (i = 0; i < k->interface_count; i++) {
4555 ic = k->interfaces [i];
4556 printf (" parent slot offset: %03d, method count: %03d, iid: %03d %s\n",
4557 mono_class_interface_offset (klass, ic),
4558 count_virtual_methods (ic), ic->interface_id, mono_type_full_name (&ic->byval_arg));
4564 g_free (vtable);
4566 VERIFY_INTERFACE_VTABLE (mono_class_verify_vtable (klass));
4567 return;
4569 fail:
4571 char *name = mono_type_get_full_name (klass);
4572 mono_class_set_type_load_failure (klass, "VTable setup of type %s failed", name);
4573 g_free (name);
4574 g_free (vtable);
4575 if (override_map)
4576 g_hash_table_destroy (override_map);
4577 if (virt_methods)
4578 g_slist_free (virt_methods);
4583 * mono_method_get_vtable_slot:
4585 * Returns method->slot, computing it if neccesary. Return -1 on failure.
4586 * LOCKING: Acquires the loader lock.
4588 * FIXME Use proper MonoError machinery here.
4591 mono_method_get_vtable_slot (MonoMethod *method)
4593 if (method->slot == -1) {
4594 mono_class_setup_vtable (method->klass);
4595 if (mono_class_has_failure (method->klass))
4596 return -1;
4597 if (method->slot == -1) {
4598 MonoClass *gklass;
4599 int i, mcount;
4601 if (!mono_class_is_ginst (method->klass)) {
4602 g_assert (method->is_inflated);
4603 return mono_method_get_vtable_slot (((MonoMethodInflated*)method)->declaring);
4606 /* This can happen for abstract methods of generic instances due to the shortcut code in mono_class_setup_vtable_general (). */
4607 g_assert (mono_class_is_ginst (method->klass));
4608 gklass = mono_class_get_generic_class (method->klass)->container_class;
4609 mono_class_setup_methods (method->klass);
4610 g_assert (method->klass->methods);
4611 mcount = mono_class_get_method_count (method->klass);
4612 for (i = 0; i < mcount; ++i) {
4613 if (method->klass->methods [i] == method)
4614 break;
4616 g_assert (i < mcount);
4617 g_assert (gklass->methods);
4618 method->slot = gklass->methods [i]->slot;
4620 g_assert (method->slot != -1);
4622 return method->slot;
4626 * mono_method_get_vtable_index:
4627 * @method: a method
4629 * Returns the index into the runtime vtable to access the method or,
4630 * in the case of a virtual generic method, the virtual generic method
4631 * thunk. Returns -1 on failure.
4633 * FIXME Use proper MonoError machinery here.
4636 mono_method_get_vtable_index (MonoMethod *method)
4638 if (method->is_inflated && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
4639 MonoMethodInflated *imethod = (MonoMethodInflated*)method;
4640 if (imethod->declaring->is_generic)
4641 return mono_method_get_vtable_slot (imethod->declaring);
4643 return mono_method_get_vtable_slot (method);
4646 static MonoMethod *default_ghc = NULL;
4647 static MonoMethod *default_finalize = NULL;
4648 static int finalize_slot = -1;
4649 static int ghc_slot = -1;
4651 static void
4652 initialize_object_slots (MonoClass *klass)
4654 int i;
4655 if (default_ghc)
4656 return;
4657 if (klass == mono_defaults.object_class) {
4658 mono_class_setup_vtable (klass);
4659 for (i = 0; i < klass->vtable_size; ++i) {
4660 MonoMethod *cm = klass->vtable [i];
4662 if (!strcmp (cm->name, "GetHashCode"))
4663 ghc_slot = i;
4664 else if (!strcmp (cm->name, "Finalize"))
4665 finalize_slot = i;
4668 g_assert (ghc_slot > 0);
4669 default_ghc = klass->vtable [ghc_slot];
4671 g_assert (finalize_slot > 0);
4672 default_finalize = klass->vtable [finalize_slot];
4676 typedef struct {
4677 MonoMethod *array_method;
4678 char *name;
4679 } GenericArrayMethodInfo;
4681 static int generic_array_method_num = 0;
4682 static GenericArrayMethodInfo *generic_array_method_info = NULL;
4684 static int
4685 generic_array_methods (MonoClass *klass)
4687 int i, count_generic = 0, mcount;
4688 GList *list = NULL, *tmp;
4689 if (generic_array_method_num)
4690 return generic_array_method_num;
4691 mono_class_setup_methods (klass->parent); /*This is setting up System.Array*/
4692 g_assert (!mono_class_has_failure (klass->parent)); /*So hitting this assert is a huge problem*/
4693 mcount = mono_class_get_method_count (klass->parent);
4694 for (i = 0; i < mcount; i++) {
4695 MonoMethod *m = klass->parent->methods [i];
4696 if (!strncmp (m->name, "InternalArray__", 15)) {
4697 count_generic++;
4698 list = g_list_prepend (list, m);
4701 list = g_list_reverse (list);
4702 generic_array_method_info = (GenericArrayMethodInfo *)mono_image_alloc (mono_defaults.corlib, sizeof (GenericArrayMethodInfo) * count_generic);
4703 i = 0;
4704 for (tmp = list; tmp; tmp = tmp->next) {
4705 const char *mname, *iname;
4706 gchar *name;
4707 MonoMethod *m = (MonoMethod *)tmp->data;
4708 const char *ireadonlylist_prefix = "InternalArray__IReadOnlyList_";
4709 const char *ireadonlycollection_prefix = "InternalArray__IReadOnlyCollection_";
4711 generic_array_method_info [i].array_method = m;
4712 if (!strncmp (m->name, "InternalArray__ICollection_", 27)) {
4713 iname = "System.Collections.Generic.ICollection`1.";
4714 mname = m->name + 27;
4715 } else if (!strncmp (m->name, "InternalArray__IEnumerable_", 27)) {
4716 iname = "System.Collections.Generic.IEnumerable`1.";
4717 mname = m->name + 27;
4718 } else if (!strncmp (m->name, ireadonlylist_prefix, strlen (ireadonlylist_prefix))) {
4719 iname = "System.Collections.Generic.IReadOnlyList`1.";
4720 mname = m->name + strlen (ireadonlylist_prefix);
4721 } else if (!strncmp (m->name, ireadonlycollection_prefix, strlen (ireadonlycollection_prefix))) {
4722 iname = "System.Collections.Generic.IReadOnlyCollection`1.";
4723 mname = m->name + strlen (ireadonlycollection_prefix);
4724 } else if (!strncmp (m->name, "InternalArray__", 15)) {
4725 iname = "System.Collections.Generic.IList`1.";
4726 mname = m->name + 15;
4727 } else {
4728 g_assert_not_reached ();
4731 name = (gchar *)mono_image_alloc (mono_defaults.corlib, strlen (iname) + strlen (mname) + 1);
4732 strcpy (name, iname);
4733 strcpy (name + strlen (iname), mname);
4734 generic_array_method_info [i].name = name;
4735 i++;
4737 /*g_print ("array generic methods: %d\n", count_generic);*/
4739 generic_array_method_num = count_generic;
4740 g_list_free (list);
4741 return generic_array_method_num;
4744 static void
4745 setup_generic_array_ifaces (MonoClass *klass, MonoClass *iface, MonoMethod **methods, int pos)
4747 MonoGenericContext tmp_context;
4748 int i;
4750 tmp_context.class_inst = NULL;
4751 tmp_context.method_inst = mono_class_get_generic_class (iface)->context.class_inst;
4752 //g_print ("setting up array interface: %s\n", mono_type_get_name_full (&iface->byval_arg, 0));
4754 for (i = 0; i < generic_array_method_num; i++) {
4755 MonoError error;
4756 MonoMethod *m = generic_array_method_info [i].array_method;
4757 MonoMethod *inflated;
4759 inflated = mono_class_inflate_generic_method_checked (m, &tmp_context, &error);
4760 g_assert (mono_error_ok (&error)); /*FIXME proper error handling*/
4761 methods [pos++] = mono_marshal_get_generic_array_helper (klass, iface, generic_array_method_info [i].name, inflated);
4765 static char*
4766 concat_two_strings_with_zero (MonoImage *image, const char *s1, const char *s2)
4768 int null_length = strlen ("(null)");
4769 int len = (s1 ? strlen (s1) : null_length) + (s2 ? strlen (s2) : null_length) + 2;
4770 char *s = (char *)mono_image_alloc (image, len);
4771 int result;
4773 result = g_snprintf (s, len, "%s%c%s", s1 ? s1 : "(null)", '\0', s2 ? s2 : "(null)");
4774 g_assert (result == len - 1);
4776 return s;
4780 * mono_class_init:
4781 * @klass: the class to initialize
4783 * Compute the instance_size, class_size and other infos that cannot be
4784 * computed at mono_class_get() time. Also compute vtable_size if possible.
4785 * Returns TRUE on success or FALSE if there was a problem in loading
4786 * the type (incorrect assemblies, missing assemblies, methods, etc).
4787 * Initializes the following fields in @klass:
4788 * - all the fields initialized by mono_class_init_sizes ()
4789 * - has_cctor
4790 * - ghcimpl
4791 * - inited
4793 * LOCKING: Acquires the loader lock.
4795 gboolean
4796 mono_class_init (MonoClass *klass)
4798 int i, vtable_size = 0, array_method_count = 0;
4799 MonoCachedClassInfo cached_info;
4800 gboolean has_cached_info;
4801 gboolean locked = FALSE;
4802 gboolean ghcimpl = FALSE;
4803 gboolean has_cctor = FALSE;
4804 int first_iface_slot = 0;
4806 g_assert (klass);
4808 /* Double-checking locking pattern */
4809 if (klass->inited || mono_class_has_failure (klass))
4810 return !mono_class_has_failure (klass);
4812 /*g_print ("Init class %s\n", mono_type_get_full_name (klass));*/
4815 * This function can recursively call itself.
4817 GSList *init_list = (GSList *)mono_native_tls_get_value (init_pending_tls_id);
4818 if (g_slist_find (init_list, klass)) {
4819 mono_class_set_type_load_failure (klass, "Recursive type definition detected");
4820 goto leave;
4822 init_list = g_slist_prepend (init_list, klass);
4823 mono_native_tls_set_value (init_pending_tls_id, init_list);
4826 * We want to avoid doing complicated work inside locks, so we compute all the required
4827 * information and write it to @klass inside a lock.
4830 if (mono_verifier_is_enabled_for_class (klass) && !mono_verifier_verify_class (klass)) {
4831 mono_class_set_type_load_failure (klass, "%s", concat_two_strings_with_zero (klass->image, klass->name, klass->image->assembly_name));
4832 goto leave;
4835 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
4836 MonoClass *element_class = klass->element_class;
4837 if (!element_class->inited)
4838 mono_class_init (element_class);
4839 if (mono_class_set_type_load_failure_causedby_class (klass, element_class, "Could not load array element class"))
4840 goto leave;
4843 mono_stats.initialized_class_count++;
4845 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic) {
4846 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4848 mono_class_init (gklass);
4849 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic Type Definition failed to init"))
4850 goto leave;
4852 mono_class_setup_interface_id (klass);
4855 if (klass->parent && !klass->parent->inited)
4856 mono_class_init (klass->parent);
4858 has_cached_info = mono_class_get_cached_class_info (klass, &cached_info);
4860 /* Compute instance size etc. */
4861 init_sizes_with_info (klass, has_cached_info ? &cached_info : NULL);
4862 if (mono_class_has_failure (klass))
4863 goto leave;
4865 mono_class_setup_supertypes (klass);
4867 if (!default_ghc)
4868 initialize_object_slots (klass);
4871 * Initialize the rest of the data without creating a generic vtable if possible.
4872 * If possible, also compute vtable_size, so mono_class_create_runtime_vtable () can
4873 * also avoid computing a generic vtable.
4875 if (has_cached_info) {
4876 /* AOT case */
4877 vtable_size = cached_info.vtable_size;
4878 ghcimpl = cached_info.ghcimpl;
4879 has_cctor = cached_info.has_cctor;
4880 } else if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
4881 /* SZARRAY can have 2 vtable layouts, with and without the stelemref method.
4882 * The first slot if for array with.
4884 static int szarray_vtable_size[2] = { 0 };
4886 int slot = MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg) ? 0 : 1;
4888 /* SZARRAY case */
4889 if (!szarray_vtable_size [slot]) {
4890 mono_class_setup_vtable (klass);
4891 szarray_vtable_size [slot] = klass->vtable_size;
4892 vtable_size = klass->vtable_size;
4893 } else {
4894 vtable_size = szarray_vtable_size[slot];
4896 } else if (mono_class_is_ginst (klass) && !MONO_CLASS_IS_INTERFACE (klass)) {
4897 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4899 /* Generic instance case */
4900 ghcimpl = gklass->ghcimpl;
4901 has_cctor = gklass->has_cctor;
4903 mono_class_setup_vtable (gklass);
4904 if (mono_class_set_type_load_failure_causedby_class (klass, gklass, "Generic type definition failed to init"))
4905 goto leave;
4907 vtable_size = gklass->vtable_size;
4908 } else {
4909 /* General case */
4911 /* ghcimpl is not currently used
4912 klass->ghcimpl = 1;
4913 if (klass->parent) {
4914 MonoMethod *cmethod = klass->vtable [ghc_slot];
4915 if (cmethod->is_inflated)
4916 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
4917 if (cmethod == default_ghc) {
4918 klass->ghcimpl = 0;
4923 /* C# doesn't allow interfaces to have cctors */
4924 if (!MONO_CLASS_IS_INTERFACE (klass) || klass->image != mono_defaults.corlib) {
4925 MonoMethod *cmethod = NULL;
4927 if (mono_class_is_ginst (klass)) {
4928 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
4930 /* Generic instance case */
4931 ghcimpl = gklass->ghcimpl;
4932 has_cctor = gklass->has_cctor;
4933 } else if (klass->type_token && !image_is_dynamic(klass->image)) {
4934 cmethod = find_method_in_metadata (klass, ".cctor", 0, METHOD_ATTRIBUTE_SPECIAL_NAME);
4935 /* The find_method function ignores the 'flags' argument */
4936 if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_SPECIAL_NAME))
4937 has_cctor = 1;
4938 } else {
4939 mono_class_setup_methods (klass);
4940 if (mono_class_has_failure (klass))
4941 goto leave;
4943 int mcount = mono_class_get_method_count (klass);
4944 for (i = 0; i < mcount; ++i) {
4945 MonoMethod *method = klass->methods [i];
4946 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) &&
4947 (strcmp (".cctor", method->name) == 0)) {
4948 has_cctor = 1;
4949 break;
4956 if (klass->rank) {
4957 array_method_count = 3 + (klass->rank > 1? 2: 1);
4959 if (klass->interface_count) {
4960 int count_generic = generic_array_methods (klass);
4961 array_method_count += klass->interface_count * count_generic;
4965 if (klass->parent) {
4966 if (!klass->parent->vtable_size)
4967 mono_class_setup_vtable (klass->parent);
4968 if (mono_class_set_type_load_failure_causedby_class (klass, klass->parent, "Parent class vtable failed to initialize"))
4969 goto leave;
4970 g_assert (klass->parent->vtable_size);
4971 first_iface_slot = klass->parent->vtable_size;
4972 if (mono_class_need_stelemref_method (klass))
4973 ++first_iface_slot;
4977 * Do the actual changes to @klass inside the loader lock
4979 mono_loader_lock ();
4980 locked = TRUE;
4982 if (klass->inited || mono_class_has_failure (klass)) {
4983 mono_loader_unlock ();
4984 /* Somebody might have gotten in before us */
4985 return !mono_class_has_failure (klass);
4988 mono_stats.initialized_class_count++;
4990 if (mono_class_is_ginst (klass) && !mono_class_get_generic_class (klass)->is_dynamic)
4991 mono_stats.generic_class_count++;
4993 if (mono_class_is_ginst (klass) || image_is_dynamic (klass->image) || !klass->type_token || (has_cached_info && !cached_info.has_nested_classes))
4994 klass->nested_classes_inited = TRUE;
4995 klass->ghcimpl = ghcimpl;
4996 klass->has_cctor = has_cctor;
4997 if (vtable_size)
4998 klass->vtable_size = vtable_size;
4999 if (has_cached_info) {
5000 klass->has_finalize = cached_info.has_finalize;
5001 klass->has_finalize_inited = TRUE;
5003 if (klass->rank)
5004 mono_class_set_method_count (klass, array_method_count);
5006 mono_loader_unlock ();
5007 locked = FALSE;
5009 setup_interface_offsets (klass, first_iface_slot, TRUE);
5011 if (mono_security_core_clr_enabled ())
5012 mono_security_core_clr_check_inheritance (klass);
5014 if (mono_class_is_ginst (klass) && !mono_verifier_class_is_valid_generic_instantiation (klass))
5015 mono_class_set_type_load_failure (klass, "Invalid generic instantiation");
5017 goto leave;
5019 leave:
5020 init_list = g_slist_remove (init_list, klass);
5021 mono_native_tls_set_value (init_pending_tls_id, init_list);
5023 if (locked)
5024 mono_loader_unlock ();
5026 /* Leave this for last */
5027 mono_loader_lock ();
5028 klass->inited = 1;
5029 mono_loader_unlock ();
5031 return !mono_class_has_failure (klass);
5035 * mono_class_has_finalizer:
5037 * Return whenever KLASS has a finalizer, initializing klass->has_finalizer in the
5038 * process.
5040 gboolean
5041 mono_class_has_finalizer (MonoClass *klass)
5043 gboolean has_finalize = FALSE;
5045 if (klass->has_finalize_inited)
5046 return klass->has_finalize;
5048 /* Interfaces and valuetypes are not supposed to have finalizers */
5049 if (!(MONO_CLASS_IS_INTERFACE (klass) || klass->valuetype)) {
5050 MonoMethod *cmethod = NULL;
5052 if (klass->rank == 1 && klass->byval_arg.type == MONO_TYPE_SZARRAY) {
5053 } else if (mono_class_is_ginst (klass)) {
5054 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
5056 has_finalize = mono_class_has_finalizer (gklass);
5057 } else if (klass->parent && klass->parent->has_finalize) {
5058 has_finalize = TRUE;
5059 } else {
5060 if (klass->parent) {
5062 * Can't search in metadata for a method named Finalize, because that
5063 * ignores overrides.
5065 mono_class_setup_vtable (klass);
5066 if (mono_class_has_failure (klass))
5067 cmethod = NULL;
5068 else
5069 cmethod = klass->vtable [finalize_slot];
5072 if (cmethod) {
5073 g_assert (klass->vtable_size > finalize_slot);
5075 if (klass->parent) {
5076 if (cmethod->is_inflated)
5077 cmethod = ((MonoMethodInflated*)cmethod)->declaring;
5078 if (cmethod != default_finalize)
5079 has_finalize = TRUE;
5085 mono_loader_lock ();
5086 if (!klass->has_finalize_inited) {
5087 klass->has_finalize = has_finalize ? 1 : 0;
5089 mono_memory_barrier ();
5090 klass->has_finalize_inited = TRUE;
5092 mono_loader_unlock ();
5094 return klass->has_finalize;
5097 gboolean
5098 mono_is_corlib_image (MonoImage *image)
5100 return image == mono_defaults.corlib;
5104 * LOCKING: this assumes the loader lock is held
5106 void
5107 mono_class_setup_mono_type (MonoClass *klass)
5109 const char *name = klass->name;
5110 const char *nspace = klass->name_space;
5111 gboolean is_corlib = mono_is_corlib_image (klass->image);
5113 klass->this_arg.byref = 1;
5114 klass->this_arg.data.klass = klass;
5115 klass->this_arg.type = MONO_TYPE_CLASS;
5116 klass->byval_arg.data.klass = klass;
5117 klass->byval_arg.type = MONO_TYPE_CLASS;
5119 if (is_corlib && !strcmp (nspace, "System")) {
5120 if (!strcmp (name, "ValueType")) {
5122 * do not set the valuetype bit for System.ValueType.
5123 * klass->valuetype = 1;
5125 klass->blittable = TRUE;
5126 } else if (!strcmp (name, "Enum")) {
5128 * do not set the valuetype bit for System.Enum.
5129 * klass->valuetype = 1;
5131 klass->valuetype = 0;
5132 klass->enumtype = 0;
5133 } else if (!strcmp (name, "Object")) {
5134 klass->byval_arg.type = MONO_TYPE_OBJECT;
5135 klass->this_arg.type = MONO_TYPE_OBJECT;
5136 } else if (!strcmp (name, "String")) {
5137 klass->byval_arg.type = MONO_TYPE_STRING;
5138 klass->this_arg.type = MONO_TYPE_STRING;
5139 } else if (!strcmp (name, "TypedReference")) {
5140 klass->byval_arg.type = MONO_TYPE_TYPEDBYREF;
5141 klass->this_arg.type = MONO_TYPE_TYPEDBYREF;
5145 if (klass->valuetype) {
5146 int t = MONO_TYPE_VALUETYPE;
5148 if (is_corlib && !strcmp (nspace, "System")) {
5149 switch (*name) {
5150 case 'B':
5151 if (!strcmp (name, "Boolean")) {
5152 t = MONO_TYPE_BOOLEAN;
5153 } else if (!strcmp(name, "Byte")) {
5154 t = MONO_TYPE_U1;
5155 klass->blittable = TRUE;
5157 break;
5158 case 'C':
5159 if (!strcmp (name, "Char")) {
5160 t = MONO_TYPE_CHAR;
5162 break;
5163 case 'D':
5164 if (!strcmp (name, "Double")) {
5165 t = MONO_TYPE_R8;
5166 klass->blittable = TRUE;
5168 break;
5169 case 'I':
5170 if (!strcmp (name, "Int32")) {
5171 t = MONO_TYPE_I4;
5172 klass->blittable = TRUE;
5173 } else if (!strcmp(name, "Int16")) {
5174 t = MONO_TYPE_I2;
5175 klass->blittable = TRUE;
5176 } else if (!strcmp(name, "Int64")) {
5177 t = MONO_TYPE_I8;
5178 klass->blittable = TRUE;
5179 } else if (!strcmp(name, "IntPtr")) {
5180 t = MONO_TYPE_I;
5181 klass->blittable = TRUE;
5183 break;
5184 case 'S':
5185 if (!strcmp (name, "Single")) {
5186 t = MONO_TYPE_R4;
5187 klass->blittable = TRUE;
5188 } else if (!strcmp(name, "SByte")) {
5189 t = MONO_TYPE_I1;
5190 klass->blittable = TRUE;
5192 break;
5193 case 'U':
5194 if (!strcmp (name, "UInt32")) {
5195 t = MONO_TYPE_U4;
5196 klass->blittable = TRUE;
5197 } else if (!strcmp(name, "UInt16")) {
5198 t = MONO_TYPE_U2;
5199 klass->blittable = TRUE;
5200 } else if (!strcmp(name, "UInt64")) {
5201 t = MONO_TYPE_U8;
5202 klass->blittable = TRUE;
5203 } else if (!strcmp(name, "UIntPtr")) {
5204 t = MONO_TYPE_U;
5205 klass->blittable = TRUE;
5207 break;
5208 case 'T':
5209 if (!strcmp (name, "TypedReference")) {
5210 t = MONO_TYPE_TYPEDBYREF;
5211 klass->blittable = TRUE;
5213 break;
5214 case 'V':
5215 if (!strcmp (name, "Void")) {
5216 t = MONO_TYPE_VOID;
5218 break;
5219 default:
5220 break;
5223 klass->byval_arg.type = (MonoTypeEnum)t;
5224 klass->this_arg.type = (MonoTypeEnum)t;
5227 if (MONO_CLASS_IS_INTERFACE (klass)) {
5228 klass->interface_id = mono_get_unique_iid (klass);
5230 if (is_corlib && !strcmp (nspace, "System.Collections.Generic")) {
5231 //FIXME IEnumerator needs to be special because GetEnumerator uses magic under the hood
5232 /* FIXME: System.Array/InternalEnumerator don't need all this interface fabrication machinery.
5233 * MS returns diferrent types based on which instance is called. For example:
5234 * object obj = new byte[10][];
5235 * Type a = ((IEnumerable<byte[]>)obj).GetEnumerator ().GetType ();
5236 * Type b = ((IEnumerable<IList<byte>>)obj).GetEnumerator ().GetType ();
5237 * a != b ==> true
5239 if (!strcmp (name, "IList`1") || !strcmp (name, "ICollection`1") || !strcmp (name, "IEnumerable`1") || !strcmp (name, "IEnumerator`1"))
5240 klass->is_array_special_interface = 1;
5245 #ifndef DISABLE_COM
5247 * COM initialization is delayed until needed.
5248 * However when a [ComImport] attribute is present on a type it will trigger
5249 * the initialization. This is not a problem unless the BCL being executed
5250 * lacks the types that COM depends on (e.g. Variant on Silverlight).
5252 static void
5253 init_com_from_comimport (MonoClass *klass)
5255 /* we don't always allow COM initialization under the CoreCLR (e.g. Moonlight does not require it) */
5256 if (mono_security_core_clr_enabled ()) {
5257 /* but some other CoreCLR user could requires it for their platform (i.e. trusted) code */
5258 if (!mono_security_core_clr_determine_platform_image (klass->image)) {
5259 /* but it can not be made available for application (i.e. user code) since all COM calls
5260 * are considered native calls. In this case we fail with a TypeLoadException (just like
5261 * Silverlight 2 does */
5262 mono_class_set_type_load_failure (klass, "");
5263 return;
5267 /* FIXME : we should add an extra checks to ensure COM can be initialized properly before continuing */
5269 #endif /*DISABLE_COM*/
5272 * LOCKING: this assumes the loader lock is held
5274 void
5275 mono_class_setup_parent (MonoClass *klass, MonoClass *parent)
5277 gboolean system_namespace;
5278 gboolean is_corlib = mono_is_corlib_image (klass->image);
5280 system_namespace = !strcmp (klass->name_space, "System") && is_corlib;
5282 /* if root of the hierarchy */
5283 if (system_namespace && !strcmp (klass->name, "Object")) {
5284 klass->parent = NULL;
5285 klass->instance_size = sizeof (MonoObject);
5286 return;
5288 if (!strcmp (klass->name, "<Module>")) {
5289 klass->parent = NULL;
5290 klass->instance_size = 0;
5291 return;
5294 if (!MONO_CLASS_IS_INTERFACE (klass)) {
5295 /* Imported COM Objects always derive from __ComObject. */
5296 #ifndef DISABLE_COM
5297 if (MONO_CLASS_IS_IMPORT (klass)) {
5298 init_com_from_comimport (klass);
5299 if (parent == mono_defaults.object_class)
5300 parent = mono_class_get_com_object_class ();
5302 #endif
5303 if (!parent) {
5304 /* set the parent to something useful and safe, but mark the type as broken */
5305 parent = mono_defaults.object_class;
5306 mono_class_set_type_load_failure (klass, "");
5307 g_assert (parent);
5310 klass->parent = parent;
5312 if (mono_class_is_ginst (parent) && !parent->name) {
5314 * If the parent is a generic instance, we may get
5315 * called before it is fully initialized, especially
5316 * before it has its name.
5318 return;
5321 #ifndef DISABLE_REMOTING
5322 klass->marshalbyref = parent->marshalbyref;
5323 klass->contextbound = parent->contextbound;
5324 #endif
5326 klass->delegate = parent->delegate;
5328 if (MONO_CLASS_IS_IMPORT (klass) || mono_class_is_com_object (parent))
5329 mono_class_set_is_com_object (klass);
5331 if (system_namespace) {
5332 #ifndef DISABLE_REMOTING
5333 if (klass->name [0] == 'M' && !strcmp (klass->name, "MarshalByRefObject"))
5334 klass->marshalbyref = 1;
5336 if (klass->name [0] == 'C' && !strcmp (klass->name, "ContextBoundObject"))
5337 klass->contextbound = 1;
5338 #endif
5339 if (klass->name [0] == 'D' && !strcmp (klass->name, "Delegate"))
5340 klass->delegate = 1;
5343 if (klass->parent->enumtype || (mono_is_corlib_image (klass->parent->image) && (strcmp (klass->parent->name, "ValueType") == 0) &&
5344 (strcmp (klass->parent->name_space, "System") == 0)))
5345 klass->valuetype = 1;
5346 if (mono_is_corlib_image (klass->parent->image) && ((strcmp (klass->parent->name, "Enum") == 0) && (strcmp (klass->parent->name_space, "System") == 0))) {
5347 klass->valuetype = klass->enumtype = 1;
5349 /*klass->enumtype = klass->parent->enumtype; */
5350 } else {
5351 /* initialize com types if COM interfaces are present */
5352 #ifndef DISABLE_COM
5353 if (MONO_CLASS_IS_IMPORT (klass))
5354 init_com_from_comimport (klass);
5355 #endif
5356 klass->parent = NULL;
5362 * mono_class_setup_supertypes:
5363 * @class: a class
5365 * Build the data structure needed to make fast type checks work.
5366 * This currently sets two fields in @class:
5367 * - idepth: distance between @class and System.Object in the type
5368 * hierarchy + 1
5369 * - supertypes: array of classes: each element has a class in the hierarchy
5370 * starting from @class up to System.Object
5372 * LOCKING: Acquires the loader lock.
5374 void
5375 mono_class_setup_supertypes (MonoClass *klass)
5377 int ms, idepth;
5378 MonoClass **supertypes;
5380 mono_atomic_load_acquire (supertypes, MonoClass **, &klass->supertypes);
5381 if (supertypes)
5382 return;
5384 if (klass->parent && !klass->parent->supertypes)
5385 mono_class_setup_supertypes (klass->parent);
5386 if (klass->parent)
5387 idepth = klass->parent->idepth + 1;
5388 else
5389 idepth = 1;
5391 ms = MAX (MONO_DEFAULT_SUPERTABLE_SIZE, idepth);
5392 supertypes = (MonoClass **)mono_class_alloc0 (klass, sizeof (MonoClass *) * ms);
5394 if (klass->parent) {
5395 CHECKED_METADATA_WRITE_PTR ( supertypes [idepth - 1] , klass );
5397 int supertype_idx;
5398 for (supertype_idx = 0; supertype_idx < klass->parent->idepth; supertype_idx++)
5399 CHECKED_METADATA_WRITE_PTR ( supertypes [supertype_idx] , klass->parent->supertypes [supertype_idx] );
5400 } else {
5401 CHECKED_METADATA_WRITE_PTR ( supertypes [0] , klass );
5404 mono_memory_barrier ();
5406 mono_loader_lock ();
5407 klass->idepth = idepth;
5408 /* Needed so idepth is visible before supertypes is set */
5409 mono_memory_barrier ();
5410 klass->supertypes = supertypes;
5411 mono_loader_unlock ();
5414 static gboolean
5415 discard_gclass_due_to_failure (MonoClass *gclass, void *user_data)
5417 return mono_class_get_generic_class (gclass)->container_class == user_data;
5420 static gboolean
5421 fix_gclass_incomplete_instantiation (MonoClass *gclass, void *user_data)
5423 MonoClass *gtd = (MonoClass*)user_data;
5424 /* Only try to fix generic instances of @gtd */
5425 if (mono_class_get_generic_class (gclass)->container_class != gtd)
5426 return FALSE;
5428 /* Check if the generic instance has no parent. */
5429 if (gtd->parent && !gclass->parent)
5430 mono_generic_class_setup_parent (gclass, gtd);
5432 return TRUE;
5435 static void
5436 mono_class_set_failure_and_error (MonoClass *klass, MonoError *error, const char *msg)
5438 mono_class_set_type_load_failure (klass, "%s", msg);
5439 mono_error_set_type_load_class (error, klass, "%s", msg);
5443 * mono_class_create_from_typedef:
5444 * @image: image where the token is valid
5445 * @type_token: typedef token
5446 * @error: used to return any error found while creating the type
5448 * Create the MonoClass* representing the specified type token.
5449 * @type_token must be a TypeDef token.
5451 * FIXME: don't return NULL on failure, just the the caller figure it out.
5453 static MonoClass *
5454 mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError *error)
5456 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
5457 MonoClass *klass, *parent = NULL;
5458 guint32 cols [MONO_TYPEDEF_SIZE];
5459 guint32 cols_next [MONO_TYPEDEF_SIZE];
5460 guint tidx = mono_metadata_token_index (type_token);
5461 MonoGenericContext *context = NULL;
5462 const char *name, *nspace;
5463 guint icount = 0;
5464 MonoClass **interfaces;
5465 guint32 field_last, method_last;
5466 guint32 nesting_tokeen;
5468 mono_error_init (error);
5470 if (mono_metadata_token_table (type_token) != MONO_TABLE_TYPEDEF || tidx > tt->rows) {
5471 mono_error_set_bad_image (error, image, "Invalid typedef token %x", type_token);
5472 return NULL;
5475 mono_loader_lock ();
5477 if ((klass = (MonoClass *)mono_internal_hash_table_lookup (&image->class_cache, GUINT_TO_POINTER (type_token)))) {
5478 mono_loader_unlock ();
5479 return klass;
5482 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
5484 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
5485 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
5487 if (mono_metadata_has_generic_params (image, type_token)) {
5488 klass = mono_image_alloc0 (image, sizeof (MonoClassGtd));
5489 klass->class_kind = MONO_CLASS_GTD;
5490 classes_size += sizeof (MonoClassGtd);
5491 ++class_gtd_count;
5492 } else {
5493 klass = mono_image_alloc0 (image, sizeof (MonoClassDef));
5494 klass->class_kind = MONO_CLASS_DEF;
5495 classes_size += sizeof (MonoClassDef);
5496 ++class_def_count;
5499 klass->name = name;
5500 klass->name_space = nspace;
5502 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5504 klass->image = image;
5505 klass->type_token = type_token;
5506 mono_class_set_flags (klass, cols [MONO_TYPEDEF_FLAGS]);
5508 mono_internal_hash_table_insert (&image->class_cache, GUINT_TO_POINTER (type_token), klass);
5511 * Check whether we're a generic type definition.
5513 if (mono_class_is_gtd (klass)) {
5514 MonoGenericContainer *generic_container = mono_metadata_load_generic_params (image, klass->type_token, NULL);
5515 generic_container->owner.klass = klass;
5516 generic_container->is_anonymous = FALSE; // Owner class is now known, container is no longer anonymous
5517 context = &generic_container->context;
5518 mono_class_set_generic_container (klass, generic_container);
5519 enable_gclass_recording ();
5522 if (cols [MONO_TYPEDEF_EXTENDS]) {
5523 MonoClass *tmp;
5524 guint32 parent_token = mono_metadata_token_from_dor (cols [MONO_TYPEDEF_EXTENDS]);
5526 if (mono_metadata_token_table (parent_token) == MONO_TABLE_TYPESPEC) {
5527 /*WARNING: this must satisfy mono_metadata_type_hash*/
5528 klass->this_arg.byref = 1;
5529 klass->this_arg.data.klass = klass;
5530 klass->this_arg.type = MONO_TYPE_CLASS;
5531 klass->byval_arg.data.klass = klass;
5532 klass->byval_arg.type = MONO_TYPE_CLASS;
5534 parent = mono_class_get_checked (image, parent_token, error);
5535 if (parent && context) /* Always inflate */
5536 parent = mono_class_inflate_generic_class_checked (parent, context, error);
5538 if (parent == NULL) {
5539 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5540 goto parent_failure;
5543 for (tmp = parent; tmp; tmp = tmp->parent) {
5544 if (tmp == klass) {
5545 mono_class_set_failure_and_error (klass, error, "Cycle found while resolving parent");
5546 goto parent_failure;
5548 if (mono_class_is_gtd (klass) && mono_class_is_ginst (tmp) && mono_class_get_generic_class (tmp)->container_class == klass) {
5549 mono_class_set_failure_and_error (klass, error, "Parent extends generic instance of this type");
5550 goto parent_failure;
5555 mono_class_setup_parent (klass, parent);
5557 /* uses ->valuetype, which is initialized by mono_class_setup_parent above */
5558 mono_class_setup_mono_type (klass);
5560 if (mono_class_is_gtd (klass))
5561 disable_gclass_recording (fix_gclass_incomplete_instantiation, klass);
5564 * This might access klass->byval_arg for recursion generated by generic constraints,
5565 * so it has to come after setup_mono_type ().
5567 if ((nesting_tokeen = mono_metadata_nested_in_typedef (image, type_token))) {
5568 klass->nested_in = mono_class_create_from_typedef (image, nesting_tokeen, error);
5569 if (!mono_error_ok (error)) {
5570 /*FIXME implement a mono_class_set_failure_from_mono_error */
5571 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5572 mono_loader_unlock ();
5573 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5574 return NULL;
5578 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_UNICODE_CLASS)
5579 klass->unicode = 1;
5581 #ifdef HOST_WIN32
5582 if ((mono_class_get_flags (klass) & TYPE_ATTRIBUTE_STRING_FORMAT_MASK) == TYPE_ATTRIBUTE_AUTO_CLASS)
5583 klass->unicode = 1;
5584 #endif
5586 klass->cast_class = klass->element_class = klass;
5587 if (mono_is_corlib_image (klass->image)) {
5588 switch (klass->byval_arg.type) {
5589 case MONO_TYPE_I1:
5590 if (mono_defaults.byte_class)
5591 klass->cast_class = mono_defaults.byte_class;
5592 break;
5593 case MONO_TYPE_U1:
5594 if (mono_defaults.sbyte_class)
5595 mono_defaults.sbyte_class = klass;
5596 break;
5597 case MONO_TYPE_I2:
5598 if (mono_defaults.uint16_class)
5599 mono_defaults.uint16_class = klass;
5600 break;
5601 case MONO_TYPE_U2:
5602 if (mono_defaults.int16_class)
5603 klass->cast_class = mono_defaults.int16_class;
5604 break;
5605 case MONO_TYPE_I4:
5606 if (mono_defaults.uint32_class)
5607 mono_defaults.uint32_class = klass;
5608 break;
5609 case MONO_TYPE_U4:
5610 if (mono_defaults.int32_class)
5611 klass->cast_class = mono_defaults.int32_class;
5612 break;
5613 case MONO_TYPE_I8:
5614 if (mono_defaults.uint64_class)
5615 mono_defaults.uint64_class = klass;
5616 break;
5617 case MONO_TYPE_U8:
5618 if (mono_defaults.int64_class)
5619 klass->cast_class = mono_defaults.int64_class;
5620 break;
5624 if (!klass->enumtype) {
5625 if (!mono_metadata_interfaces_from_typedef_full (
5626 image, type_token, &interfaces, &icount, FALSE, context, error)){
5628 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5629 mono_loader_unlock ();
5630 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5631 return NULL;
5634 /* This is required now that it is possible for more than 2^16 interfaces to exist. */
5635 g_assert(icount <= 65535);
5637 klass->interfaces = interfaces;
5638 klass->interface_count = icount;
5639 klass->interfaces_inited = 1;
5642 /*g_print ("Load class %s\n", name);*/
5645 * Compute the field and method lists
5647 int first_field_idx = cols [MONO_TYPEDEF_FIELD_LIST] - 1;
5648 mono_class_set_first_field_idx (klass, first_field_idx);
5649 int first_method_idx = cols [MONO_TYPEDEF_METHOD_LIST] - 1;
5650 mono_class_set_first_method_idx (klass, first_method_idx);
5652 if (tt->rows > tidx){
5653 mono_metadata_decode_row (tt, tidx, cols_next, MONO_TYPEDEF_SIZE);
5654 field_last = cols_next [MONO_TYPEDEF_FIELD_LIST] - 1;
5655 method_last = cols_next [MONO_TYPEDEF_METHOD_LIST] - 1;
5656 } else {
5657 field_last = image->tables [MONO_TABLE_FIELD].rows;
5658 method_last = image->tables [MONO_TABLE_METHOD].rows;
5661 if (cols [MONO_TYPEDEF_FIELD_LIST] &&
5662 cols [MONO_TYPEDEF_FIELD_LIST] <= image->tables [MONO_TABLE_FIELD].rows)
5663 mono_class_set_field_count (klass, field_last - first_field_idx);
5664 if (cols [MONO_TYPEDEF_METHOD_LIST] <= image->tables [MONO_TABLE_METHOD].rows)
5665 mono_class_set_method_count (klass, method_last - first_method_idx);
5667 /* reserve space to store vector pointer in arrays */
5668 if (mono_is_corlib_image (image) && !strcmp (nspace, "System") && !strcmp (name, "Array")) {
5669 klass->instance_size += 2 * sizeof (gpointer);
5670 g_assert (mono_class_get_field_count (klass) == 0);
5673 if (klass->enumtype) {
5674 MonoType *enum_basetype = mono_class_find_enum_basetype (klass, error);
5675 if (!enum_basetype) {
5676 /*set it to a default value as the whole runtime can't handle this to be null*/
5677 klass->cast_class = klass->element_class = mono_defaults.int32_class;
5678 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
5679 mono_loader_unlock ();
5680 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5681 return NULL;
5683 klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype);
5687 * If we're a generic type definition, load the constraints.
5688 * We must do this after the class has been constructed to make certain recursive scenarios
5689 * work.
5691 if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) {
5692 mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error));
5693 mono_loader_unlock ();
5694 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5695 return NULL;
5698 if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "Mono.Simd") && !strcmp (nspace, "Mono.Simd")) {
5699 if (!strncmp (name, "Vector", 6))
5700 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");
5701 } else if (klass->image->assembly_name && !strcmp (klass->image->assembly_name, "System.Numerics") && !strcmp (nspace, "System.Numerics")) {
5702 if (!strcmp (name, "Vector2") || !strcmp (name, "Vector3") || !strcmp (name, "Vector4"))
5703 klass->simd_type = 1;
5706 mono_loader_unlock ();
5708 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
5710 return klass;
5712 parent_failure:
5713 if (mono_class_is_gtd (klass))
5714 disable_gclass_recording (discard_gclass_due_to_failure, klass);
5716 mono_class_setup_mono_type (klass);
5717 mono_loader_unlock ();
5718 mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED);
5719 return NULL;
5722 /** Is klass a Nullable<T> ginst? */
5723 gboolean
5724 mono_class_is_nullable (MonoClass *klass)
5726 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
5727 return gklass && gklass->container_class == mono_defaults.generic_nullable_class;
5731 /** if klass is T? return T */
5732 MonoClass*
5733 mono_class_get_nullable_param (MonoClass *klass)
5735 g_assert (mono_class_is_nullable (klass));
5736 return mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
5739 static void
5740 mono_generic_class_setup_parent (MonoClass *klass, MonoClass *gtd)
5742 if (gtd->parent) {
5743 MonoError error;
5744 MonoGenericClass *gclass = mono_class_get_generic_class (klass);
5746 klass->parent = mono_class_inflate_generic_class_checked (gtd->parent, mono_generic_class_get_context (gclass), &error);
5747 if (!mono_error_ok (&error)) {
5748 /*Set parent to something safe as the runtime doesn't handle well this kind of failure.*/
5749 klass->parent = mono_defaults.object_class;
5750 mono_class_set_type_load_failure (klass, "Parent is a generic type instantiation that failed due to: %s", mono_error_get_message (&error));
5751 mono_error_cleanup (&error);
5754 mono_loader_lock ();
5755 if (klass->parent)
5756 mono_class_setup_parent (klass, klass->parent);
5758 if (klass->enumtype) {
5759 klass->cast_class = gtd->cast_class;
5760 klass->element_class = gtd->element_class;
5762 mono_loader_unlock ();
5765 gboolean
5766 mono_type_is_primitive (MonoType *type)
5768 return (type->type >= MONO_TYPE_BOOLEAN && type->type <= MONO_TYPE_R8) ||
5769 type-> type == MONO_TYPE_I || type->type == MONO_TYPE_U;
5773 * Create the `MonoClass' for an instantiation of a generic type.
5774 * We only do this if we actually need it.
5776 MonoClass*
5777 mono_generic_class_get_class (MonoGenericClass *gclass)
5779 MonoClass *klass, *gklass;
5781 if (gclass->cached_class)
5782 return gclass->cached_class;
5784 klass = (MonoClass *)mono_image_set_alloc0 (gclass->owner, sizeof (MonoClassGenericInst));
5786 gklass = gclass->container_class;
5788 if (gklass->nested_in) {
5789 /* The nested_in type should not be inflated since it's possible to produce a nested type with less generic arguments*/
5790 klass->nested_in = gklass->nested_in;
5793 klass->name = gklass->name;
5794 klass->name_space = gklass->name_space;
5796 klass->image = gklass->image;
5797 klass->type_token = gklass->type_token;
5799 klass->class_kind = MONO_CLASS_GINST;
5800 //FIXME add setter
5801 ((MonoClassGenericInst*)klass)->generic_class = gclass;
5803 klass->byval_arg.type = MONO_TYPE_GENERICINST;
5804 klass->this_arg.type = klass->byval_arg.type;
5805 klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
5806 klass->this_arg.byref = TRUE;
5807 klass->enumtype = gklass->enumtype;
5808 klass->valuetype = gklass->valuetype;
5811 if (gklass->image->assembly_name && !strcmp (gklass->image->assembly_name, "System.Numerics.Vectors") && !strcmp (gklass->name_space, "System.Numerics") && !strcmp (gklass->name, "Vector`1")) {
5812 g_assert (gclass->context.class_inst);
5813 g_assert (gclass->context.class_inst->type_argc > 0);
5814 if (mono_type_is_primitive (gclass->context.class_inst->type_argv [0]))
5815 klass->simd_type = 1;
5817 klass->is_array_special_interface = gklass->is_array_special_interface;
5819 klass->cast_class = klass->element_class = klass;
5821 if (gclass->is_dynamic) {
5823 * 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.
5824 * This is to avoid work that would probably give wrong results as fields change as we build the TypeBuilder.
5825 * See remove_instantiations_of_and_ensure_contents in reflection.c and its usage in reflection.c to understand the fixup stage of SRE banking.
5827 if (!gklass->wastypebuilder)
5828 klass->inited = 1;
5830 if (klass->enumtype) {
5832 * For enums, gklass->fields might not been set, but instance_size etc. is
5833 * already set in mono_reflection_create_internal_class (). For non-enums,
5834 * these will be computed normally in mono_class_layout_fields ().
5836 klass->instance_size = gklass->instance_size;
5837 klass->sizes.class_size = gklass->sizes.class_size;
5838 klass->size_inited = 1;
5842 mono_loader_lock ();
5844 if (gclass->cached_class) {
5845 mono_loader_unlock ();
5846 return gclass->cached_class;
5849 if (record_gclass_instantiation > 0)
5850 gclass_recorded_list = g_slist_append (gclass_recorded_list, klass);
5852 if (mono_class_is_nullable (klass))
5853 klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass);
5855 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5857 mono_generic_class_setup_parent (klass, gklass);
5859 if (gclass->is_dynamic)
5860 mono_class_setup_supertypes (klass);
5862 mono_memory_barrier ();
5863 gclass->cached_class = klass;
5865 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
5867 ++class_ginst_count;
5868 inflated_classes_size += sizeof (MonoClassGenericInst);
5870 mono_loader_unlock ();
5872 return klass;
5875 static MonoImage *
5876 get_image_for_container (MonoGenericContainer *container)
5878 MonoImage *result;
5879 if (container->is_anonymous) {
5880 result = container->owner.image;
5881 } else {
5882 MonoClass *klass;
5883 if (container->is_method) {
5884 MonoMethod *method = container->owner.method;
5885 g_assert_checked (method);
5886 klass = method->klass;
5887 } else {
5888 klass = container->owner.klass;
5890 g_assert_checked (klass);
5891 result = klass->image;
5893 g_assert (result);
5894 return result;
5897 MonoImage *
5898 get_image_for_generic_param (MonoGenericParam *param)
5900 MonoGenericContainer *container = mono_generic_param_owner (param);
5901 g_assert_checked (container);
5902 return get_image_for_container (container);
5905 // Make a string in the designated image consisting of a single integer.
5906 #define INT_STRING_SIZE 16
5907 char *
5908 make_generic_name_string (MonoImage *image, int num)
5910 char *name = (char *)mono_image_alloc0 (image, INT_STRING_SIZE);
5911 g_snprintf (name, INT_STRING_SIZE, "%d", num);
5912 return name;
5915 // This is called by mono_class_from_generic_parameter_internal when a new class must be created.
5916 // pinfo is derived from param by the caller for us.
5917 static MonoClass*
5918 make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo)
5920 MonoClass *klass, **ptr;
5921 int count, pos, i;
5922 MonoGenericContainer *container = mono_generic_param_owner (param);
5923 g_assert_checked (container);
5925 MonoImage *image = get_image_for_container (container);
5926 gboolean is_mvar = container->is_method;
5927 gboolean is_anonymous = container->is_anonymous;
5929 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassGenericParam));
5930 klass->class_kind = MONO_CLASS_GPARAM;
5931 classes_size += sizeof (MonoClassGenericParam);
5932 ++class_gparam_count;
5934 if (pinfo) {
5935 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name , pinfo->name );
5936 } else {
5937 int n = mono_generic_param_num (param);
5938 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->name , make_generic_name_string (image, n) );
5941 if (is_anonymous) {
5942 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , "" );
5943 } else if (is_mvar) {
5944 MonoMethod *omethod = container->owner.method;
5945 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , (omethod && omethod->klass) ? omethod->klass->name_space : "" );
5946 } else {
5947 MonoClass *oklass = container->owner.klass;
5948 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" );
5951 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
5953 // Count non-NULL items in pinfo->constraints
5954 count = 0;
5955 if (pinfo)
5956 for (ptr = pinfo->constraints; ptr && *ptr; ptr++, count++)
5959 pos = 0;
5960 if ((count > 0) && !MONO_CLASS_IS_INTERFACE (pinfo->constraints [0])) {
5961 CHECKED_METADATA_WRITE_PTR ( klass->parent , pinfo->constraints [0] );
5962 pos++;
5963 } else if (pinfo && pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) {
5964 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_class_load_from_name (mono_defaults.corlib, "System", "ValueType") );
5965 } else {
5966 CHECKED_METADATA_WRITE_PTR ( klass->parent , mono_defaults.object_class );
5969 if (count - pos > 0) {
5970 klass->interface_count = count - pos;
5971 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->interfaces , (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass *) * (count - pos)) );
5972 klass->interfaces_inited = TRUE;
5973 for (i = pos; i < count; i++)
5974 CHECKED_METADATA_WRITE_PTR ( klass->interfaces [i - pos] , pinfo->constraints [i] );
5977 CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->image , image );
5979 klass->inited = TRUE;
5980 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->cast_class , klass );
5981 CHECKED_METADATA_WRITE_PTR_LOCAL ( klass->element_class , klass );
5983 klass->byval_arg.type = is_mvar ? MONO_TYPE_MVAR : MONO_TYPE_VAR;
5984 klass->this_arg.type = klass->byval_arg.type;
5985 CHECKED_METADATA_WRITE_PTR ( klass->this_arg.data.generic_param , param );
5986 CHECKED_METADATA_WRITE_PTR ( klass->byval_arg.data.generic_param , param );
5987 klass->this_arg.byref = TRUE;
5989 /* We don't use type_token for VAR since only classes can use it (not arrays, pointer, VARs, etc) */
5990 klass->sizes.generic_param_token = pinfo ? pinfo->token : 0;
5992 /*Init these fields to sane values*/
5993 klass->min_align = 1;
5995 * This makes sure the the value size of this class is equal to the size of the types the gparam is
5996 * constrained to, the JIT depends on this.
5998 klass->instance_size = sizeof (MonoObject) + mono_type_stack_size_internal (&klass->byval_arg, NULL, TRUE);
5999 mono_memory_barrier ();
6000 klass->size_inited = 1;
6002 mono_class_setup_supertypes (klass);
6004 if (count - pos > 0) {
6005 mono_class_setup_vtable (klass->parent);
6006 if (mono_class_has_failure (klass->parent))
6007 mono_class_set_type_load_failure (klass, "Failed to setup parent interfaces");
6008 else
6009 setup_interface_offsets (klass, klass->parent->vtable_size, TRUE);
6012 return klass;
6015 #define FAST_CACHE_SIZE 16
6018 * get_anon_gparam_class and set_anon_gparam_class are helpers for mono_class_from_generic_parameter_internal.
6019 * The latter will sometimes create MonoClasses for anonymous generic params. To prevent this being wasteful,
6020 * we cache the MonoClasses.
6021 * FIXME: It would be better to instead cache anonymous MonoGenericParams, and allow anonymous params to point directly to classes using the pklass field.
6022 * LOCKING: Takes the image lock depending on @take_lock.
6024 static MonoClass *
6025 get_anon_gparam_class (MonoGenericParam *param, gboolean take_lock)
6027 int n = mono_generic_param_num (param);
6028 MonoImage *image = get_image_for_generic_param (param);
6029 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6030 MonoClass *klass = NULL;
6031 GHashTable *ht;
6033 g_assert (image);
6035 // For params with a small num and no constraints, we use a "fast" cache which does simple num lookup in an array.
6036 // For high numbers or constraints we have to use pointer hashes.
6037 if (param->gshared_constraint) {
6038 ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6039 if (ht) {
6040 if (take_lock)
6041 mono_image_lock (image);
6042 klass = (MonoClass *)g_hash_table_lookup (ht, param);
6043 if (take_lock)
6044 mono_image_unlock (image);
6046 return klass;
6049 if (n < FAST_CACHE_SIZE) {
6050 if (is_mvar)
6051 return image->mvar_cache_fast ? image->mvar_cache_fast [n] : NULL;
6052 else
6053 return image->var_cache_fast ? image->var_cache_fast [n] : NULL;
6054 } else {
6055 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6056 if (ht) {
6057 if (take_lock)
6058 mono_image_lock (image);
6059 klass = (MonoClass *)g_hash_table_lookup (ht, GINT_TO_POINTER (n));
6060 if (take_lock)
6061 mono_image_unlock (image);
6063 return klass;
6068 * LOCKING: Image lock (param->image) must be held
6070 static void
6071 set_anon_gparam_class (MonoGenericParam *param, MonoClass *klass)
6073 int n = mono_generic_param_num (param);
6074 MonoImage *image = get_image_for_generic_param (param);
6075 gboolean is_mvar = mono_generic_param_owner (param)->is_method;
6077 g_assert (image);
6079 if (param->gshared_constraint) {
6080 GHashTable *ht = is_mvar ? image->mvar_cache_constrained : image->var_cache_constrained;
6081 if (!ht) {
6082 ht = g_hash_table_new ((GHashFunc)mono_metadata_generic_param_hash, (GEqualFunc)mono_metadata_generic_param_equal);
6083 mono_memory_barrier ();
6084 if (is_mvar)
6085 image->mvar_cache_constrained = ht;
6086 else
6087 image->var_cache_constrained = ht;
6089 g_hash_table_insert (ht, param, klass);
6090 } else if (n < FAST_CACHE_SIZE) {
6091 if (is_mvar) {
6092 /* Requires locking to avoid droping an already published class */
6093 if (!image->mvar_cache_fast)
6094 image->mvar_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6095 image->mvar_cache_fast [n] = klass;
6096 } else {
6097 if (!image->var_cache_fast)
6098 image->var_cache_fast = (MonoClass **)mono_image_alloc0 (image, sizeof (MonoClass*) * FAST_CACHE_SIZE);
6099 image->var_cache_fast [n] = klass;
6101 } else {
6102 GHashTable *ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6103 if (!ht) {
6104 ht = is_mvar ? image->mvar_cache_slow : image->var_cache_slow;
6105 if (!ht) {
6106 ht = g_hash_table_new (NULL, NULL);
6107 mono_memory_barrier ();
6108 if (is_mvar)
6109 image->mvar_cache_slow = ht;
6110 else
6111 image->var_cache_slow = ht;
6114 g_hash_table_insert (ht, GINT_TO_POINTER (n), klass);
6119 * LOCKING: Acquires the image lock (@image).
6121 MonoClass *
6122 mono_class_from_generic_parameter_internal (MonoGenericParam *param)
6124 MonoImage *image = get_image_for_generic_param (param);
6125 MonoGenericParamInfo *pinfo = mono_generic_param_info (param);
6126 MonoClass *klass, *klass2;
6128 // If a klass already exists for this object and is cached, return it.
6129 if (pinfo) // Non-anonymous
6130 klass = pinfo->pklass;
6131 else // Anonymous
6132 klass = get_anon_gparam_class (param, TRUE);
6134 if (klass)
6135 return klass;
6137 // Create a new klass
6138 klass = make_generic_param_class (param, pinfo);
6140 // Now we need to cache the klass we created.
6141 // But since we wait to grab the lock until after creating the klass, we need to check to make sure
6142 // another thread did not get in and cache a klass ahead of us. In that case, return their klass
6143 // and allow our newly-created klass object to just leak.
6144 mono_memory_barrier ();
6146 mono_image_lock (image);
6148 // Here "klass2" refers to the klass potentially created by the other thread.
6149 if (pinfo) // Repeat check from above
6150 klass2 = pinfo->pklass;
6151 else
6152 klass2 = get_anon_gparam_class (param, FALSE);
6154 if (klass2) {
6155 klass = klass2;
6156 } else {
6157 // Cache here
6158 if (pinfo)
6159 pinfo->pklass = klass;
6160 else
6161 set_anon_gparam_class (param, klass);
6163 mono_image_unlock (image);
6165 /* FIXME: Should this go inside 'make_generic_param_klass'? */
6166 if (klass2)
6167 mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED); // Alert profiler about botched class create
6168 else
6169 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6171 return klass;
6175 * mono_class_from_generic_parameter:
6176 * @param: Parameter to find/construct a class for.
6177 * @arg2: Is ignored.
6178 * @arg3: Is ignored.
6180 MonoClass *
6181 mono_class_from_generic_parameter (MonoGenericParam *param, MonoImage *arg2 G_GNUC_UNUSED, gboolean arg3 G_GNUC_UNUSED)
6183 return mono_class_from_generic_parameter_internal (param);
6186 MonoClass *
6187 mono_ptr_class_get (MonoType *type)
6189 MonoClass *result;
6190 MonoClass *el_class;
6191 MonoImage *image;
6192 char *name;
6194 el_class = mono_class_from_mono_type (type);
6195 image = el_class->image;
6197 mono_image_lock (image);
6198 if (image->ptr_cache) {
6199 if ((result = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6200 mono_image_unlock (image);
6201 return result;
6204 mono_image_unlock (image);
6206 result = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassPointer));
6208 classes_size += sizeof (MonoClassPointer);
6209 ++class_pointer_count;
6211 result->parent = NULL; /* no parent for PTR types */
6212 result->name_space = el_class->name_space;
6213 name = g_strdup_printf ("%s*", el_class->name);
6214 result->name = mono_image_strdup (image, name);
6215 result->class_kind = MONO_CLASS_POINTER;
6216 g_free (name);
6218 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6220 result->image = el_class->image;
6221 result->inited = TRUE;
6222 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6223 result->cast_class = result->element_class = el_class;
6224 result->blittable = TRUE;
6226 result->byval_arg.type = MONO_TYPE_PTR;
6227 result->this_arg.type = result->byval_arg.type;
6228 result->this_arg.data.type = result->byval_arg.data.type = &result->element_class->byval_arg;
6229 result->this_arg.byref = TRUE;
6231 mono_class_setup_supertypes (result);
6233 mono_image_lock (image);
6234 if (image->ptr_cache) {
6235 MonoClass *result2;
6236 if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) {
6237 mono_image_unlock (image);
6238 mono_profiler_class_loaded (result, MONO_PROFILE_FAILED);
6239 return result2;
6241 } else {
6242 image->ptr_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6244 g_hash_table_insert (image->ptr_cache, el_class, result);
6245 mono_image_unlock (image);
6247 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6249 return result;
6252 static MonoClass *
6253 mono_fnptr_class_get (MonoMethodSignature *sig)
6255 MonoClass *result, *cached;
6256 static GHashTable *ptr_hash = NULL;
6258 /* FIXME: These should be allocate from a mempool as well, but which one ? */
6260 mono_loader_lock ();
6261 if (!ptr_hash)
6262 ptr_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
6263 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
6264 mono_loader_unlock ();
6265 if (cached)
6266 return cached;
6268 result = g_new0 (MonoClass, 1);
6270 result->parent = NULL; /* no parent for PTR types */
6271 result->name_space = "System";
6272 result->name = "MonoFNPtrFakeClass";
6273 result->class_kind = MONO_CLASS_POINTER;
6275 result->image = mono_defaults.corlib; /* need to fix... */
6276 result->instance_size = sizeof (MonoObject) + sizeof (gpointer);
6277 result->cast_class = result->element_class = result;
6278 result->byval_arg.type = MONO_TYPE_FNPTR;
6279 result->this_arg.type = result->byval_arg.type;
6280 result->this_arg.data.method = result->byval_arg.data.method = sig;
6281 result->this_arg.byref = TRUE;
6282 result->blittable = TRUE;
6283 result->inited = TRUE;
6285 mono_class_setup_supertypes (result);
6287 mono_loader_lock ();
6289 cached = (MonoClass *)g_hash_table_lookup (ptr_hash, sig);
6290 if (cached) {
6291 g_free (result);
6292 mono_loader_unlock ();
6293 return cached;
6296 mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
6298 classes_size += sizeof (MonoClassPointer);
6299 ++class_pointer_count;
6301 g_hash_table_insert (ptr_hash, sig, result);
6303 mono_loader_unlock ();
6305 mono_profiler_class_loaded (result, MONO_PROFILE_OK);
6307 return result;
6311 * mono_class_from_mono_type:
6312 * @type: describes the type to return
6314 * This returns a MonoClass for the specified MonoType, the value is never NULL.
6316 MonoClass *
6317 mono_class_from_mono_type (MonoType *type)
6319 switch (type->type) {
6320 case MONO_TYPE_OBJECT:
6321 return type->data.klass? type->data.klass: mono_defaults.object_class;
6322 case MONO_TYPE_VOID:
6323 return type->data.klass? type->data.klass: mono_defaults.void_class;
6324 case MONO_TYPE_BOOLEAN:
6325 return type->data.klass? type->data.klass: mono_defaults.boolean_class;
6326 case MONO_TYPE_CHAR:
6327 return type->data.klass? type->data.klass: mono_defaults.char_class;
6328 case MONO_TYPE_I1:
6329 return type->data.klass? type->data.klass: mono_defaults.sbyte_class;
6330 case MONO_TYPE_U1:
6331 return type->data.klass? type->data.klass: mono_defaults.byte_class;
6332 case MONO_TYPE_I2:
6333 return type->data.klass? type->data.klass: mono_defaults.int16_class;
6334 case MONO_TYPE_U2:
6335 return type->data.klass? type->data.klass: mono_defaults.uint16_class;
6336 case MONO_TYPE_I4:
6337 return type->data.klass? type->data.klass: mono_defaults.int32_class;
6338 case MONO_TYPE_U4:
6339 return type->data.klass? type->data.klass: mono_defaults.uint32_class;
6340 case MONO_TYPE_I:
6341 return type->data.klass? type->data.klass: mono_defaults.int_class;
6342 case MONO_TYPE_U:
6343 return type->data.klass? type->data.klass: mono_defaults.uint_class;
6344 case MONO_TYPE_I8:
6345 return type->data.klass? type->data.klass: mono_defaults.int64_class;
6346 case MONO_TYPE_U8:
6347 return type->data.klass? type->data.klass: mono_defaults.uint64_class;
6348 case MONO_TYPE_R4:
6349 return type->data.klass? type->data.klass: mono_defaults.single_class;
6350 case MONO_TYPE_R8:
6351 return type->data.klass? type->data.klass: mono_defaults.double_class;
6352 case MONO_TYPE_STRING:
6353 return type->data.klass? type->data.klass: mono_defaults.string_class;
6354 case MONO_TYPE_TYPEDBYREF:
6355 return type->data.klass? type->data.klass: mono_defaults.typed_reference_class;
6356 case MONO_TYPE_ARRAY:
6357 return mono_bounded_array_class_get (type->data.array->eklass, type->data.array->rank, TRUE);
6358 case MONO_TYPE_PTR:
6359 return mono_ptr_class_get (type->data.type);
6360 case MONO_TYPE_FNPTR:
6361 return mono_fnptr_class_get (type->data.method);
6362 case MONO_TYPE_SZARRAY:
6363 return mono_array_class_get (type->data.klass, 1);
6364 case MONO_TYPE_CLASS:
6365 case MONO_TYPE_VALUETYPE:
6366 return type->data.klass;
6367 case MONO_TYPE_GENERICINST:
6368 return mono_generic_class_get_class (type->data.generic_class);
6369 case MONO_TYPE_MVAR:
6370 case MONO_TYPE_VAR:
6371 return mono_class_from_generic_parameter_internal (type->data.generic_param);
6372 default:
6373 g_warning ("mono_class_from_mono_type: implement me 0x%02x\n", type->type);
6374 g_assert_not_reached ();
6377 // Yes, this returns NULL, even if it is documented as not doing so, but there
6378 // is no way for the code to make it this far, due to the assert above.
6379 return NULL;
6383 * mono_type_retrieve_from_typespec
6384 * @image: context where the image is created
6385 * @type_spec: typespec token
6386 * @context: the generic context used to evaluate generic instantiations in
6388 static MonoType *
6389 mono_type_retrieve_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, gboolean *did_inflate, MonoError *error)
6391 MonoType *t = mono_type_create_from_typespec_checked (image, type_spec, error);
6393 *did_inflate = FALSE;
6395 if (!t)
6396 return NULL;
6398 if (context && (context->class_inst || context->method_inst)) {
6399 MonoType *inflated = inflate_generic_type (NULL, t, context, error);
6401 if (!mono_error_ok (error)) {
6402 return NULL;
6405 if (inflated) {
6406 t = inflated;
6407 *did_inflate = TRUE;
6410 return t;
6414 * mono_class_create_from_typespec
6415 * @image: context where the image is created
6416 * @type_spec: typespec token
6417 * @context: the generic context used to evaluate generic instantiations in
6419 static MonoClass *
6420 mono_class_create_from_typespec (MonoImage *image, guint32 type_spec, MonoGenericContext *context, MonoError *error)
6422 MonoClass *ret;
6423 gboolean inflated = FALSE;
6424 MonoType *t = mono_type_retrieve_from_typespec (image, type_spec, context, &inflated, error);
6425 return_val_if_nok (error, NULL);
6426 ret = mono_class_from_mono_type (t);
6427 if (inflated)
6428 mono_metadata_free_type (t);
6429 return ret;
6433 * mono_bounded_array_class_get:
6434 * @element_class: element class
6435 * @rank: the dimension of the array class
6436 * @bounded: whenever the array has non-zero bounds
6438 * Returns: A class object describing the array with element type @element_type and
6439 * dimension @rank.
6441 MonoClass *
6442 mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded)
6444 MonoImage *image;
6445 MonoClass *klass, *cached, *k;
6446 MonoClass *parent = NULL;
6447 GSList *list, *rootlist = NULL;
6448 int nsize;
6449 char *name;
6451 g_assert (rank <= 255);
6453 if (rank > 1)
6454 /* bounded only matters for one-dimensional arrays */
6455 bounded = FALSE;
6457 image = eclass->image;
6459 /* Check cache */
6460 cached = NULL;
6461 if (rank == 1 && !bounded) {
6463 * This case is very frequent not just during compilation because of calls
6464 * from mono_class_from_mono_type (), mono_array_new (),
6465 * Array:CreateInstance (), etc, so use a separate cache + a separate lock.
6467 mono_os_mutex_lock (&image->szarray_cache_lock);
6468 if (!image->szarray_cache)
6469 image->szarray_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6470 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6471 mono_os_mutex_unlock (&image->szarray_cache_lock);
6472 } else {
6473 mono_loader_lock ();
6474 if (!image->array_cache)
6475 image->array_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
6476 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
6477 for (list = rootlist; list; list = list->next) {
6478 k = (MonoClass *)list->data;
6479 if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6480 cached = k;
6481 break;
6484 mono_loader_unlock ();
6486 if (cached)
6487 return cached;
6489 parent = mono_defaults.array_class;
6490 if (!parent->inited)
6491 mono_class_init (parent);
6493 klass = (MonoClass *)mono_image_alloc0 (image, sizeof (MonoClassArray));
6495 klass->image = image;
6496 klass->name_space = eclass->name_space;
6497 klass->class_kind = MONO_CLASS_ARRAY;
6499 nsize = strlen (eclass->name);
6500 name = (char *)g_malloc (nsize + 2 + rank + 1);
6501 memcpy (name, eclass->name, nsize);
6502 name [nsize] = '[';
6503 if (rank > 1)
6504 memset (name + nsize + 1, ',', rank - 1);
6505 if (bounded)
6506 name [nsize + rank] = '*';
6507 name [nsize + rank + bounded] = ']';
6508 name [nsize + rank + bounded + 1] = 0;
6509 klass->name = mono_image_strdup (image, name);
6510 g_free (name);
6512 klass->type_token = 0;
6513 klass->parent = parent;
6514 klass->instance_size = mono_class_instance_size (klass->parent);
6516 if (eclass->byval_arg.type == MONO_TYPE_TYPEDBYREF || eclass->byval_arg.type == MONO_TYPE_VOID) {
6517 /*Arrays of those two types are invalid.*/
6518 MonoError prepared_error;
6519 mono_error_init (&prepared_error);
6520 mono_error_set_invalid_program (&prepared_error, "Arrays of void or System.TypedReference types are invalid.");
6521 mono_class_set_failure (klass, mono_error_box (&prepared_error, klass->image));
6522 mono_error_cleanup (&prepared_error);
6523 } else if (eclass->enumtype && !mono_class_enum_basetype (eclass)) {
6524 guint32 ref_info_handle = mono_class_get_ref_info_handle (eclass);
6525 if (!ref_info_handle || eclass->wastypebuilder) {
6526 g_warning ("Only incomplete TypeBuilder objects are allowed to be an enum without base_type");
6527 g_assert (ref_info_handle && !eclass->wastypebuilder);
6529 /* element_size -1 is ok as this is not an instantitable type*/
6530 klass->sizes.element_size = -1;
6531 } else
6532 klass->sizes.element_size = mono_class_array_element_size (eclass);
6534 mono_class_setup_supertypes (klass);
6536 if (mono_class_is_ginst (eclass))
6537 mono_class_init (eclass);
6538 if (!eclass->size_inited)
6539 mono_class_setup_fields (eclass);
6540 mono_class_set_type_load_failure_causedby_class (klass, eclass, "Could not load array element type");
6541 /*FIXME we fail the array type, but we have to let other fields be set.*/
6543 klass->has_references = MONO_TYPE_IS_REFERENCE (&eclass->byval_arg) || eclass->has_references? TRUE: FALSE;
6545 klass->rank = rank;
6547 if (eclass->enumtype)
6548 klass->cast_class = eclass->element_class;
6549 else
6550 klass->cast_class = eclass;
6552 switch (klass->cast_class->byval_arg.type) {
6553 case MONO_TYPE_I1:
6554 klass->cast_class = mono_defaults.byte_class;
6555 break;
6556 case MONO_TYPE_U2:
6557 klass->cast_class = mono_defaults.int16_class;
6558 break;
6559 case MONO_TYPE_U4:
6560 #if SIZEOF_VOID_P == 4
6561 case MONO_TYPE_I:
6562 case MONO_TYPE_U:
6563 #endif
6564 klass->cast_class = mono_defaults.int32_class;
6565 break;
6566 case MONO_TYPE_U8:
6567 #if SIZEOF_VOID_P == 8
6568 case MONO_TYPE_I:
6569 case MONO_TYPE_U:
6570 #endif
6571 klass->cast_class = mono_defaults.int64_class;
6572 break;
6573 default:
6574 break;
6577 klass->element_class = eclass;
6579 if ((rank > 1) || bounded) {
6580 MonoArrayType *at = (MonoArrayType *)mono_image_alloc0 (image, sizeof (MonoArrayType));
6581 klass->byval_arg.type = MONO_TYPE_ARRAY;
6582 klass->byval_arg.data.array = at;
6583 at->eklass = eclass;
6584 at->rank = rank;
6585 /* FIXME: complete.... */
6586 } else {
6587 klass->byval_arg.type = MONO_TYPE_SZARRAY;
6588 klass->byval_arg.data.klass = eclass;
6590 klass->this_arg = klass->byval_arg;
6591 klass->this_arg.byref = 1;
6593 mono_loader_lock ();
6595 /* Check cache again */
6596 cached = NULL;
6597 if (rank == 1 && !bounded) {
6598 mono_os_mutex_lock (&image->szarray_cache_lock);
6599 cached = (MonoClass *)g_hash_table_lookup (image->szarray_cache, eclass);
6600 mono_os_mutex_unlock (&image->szarray_cache_lock);
6601 } else {
6602 rootlist = (GSList *)g_hash_table_lookup (image->array_cache, eclass);
6603 for (list = rootlist; list; list = list->next) {
6604 k = (MonoClass *)list->data;
6605 if ((k->rank == rank) && (k->byval_arg.type == (((rank > 1) || bounded) ? MONO_TYPE_ARRAY : MONO_TYPE_SZARRAY))) {
6606 cached = k;
6607 break;
6611 if (cached) {
6612 mono_loader_unlock ();
6613 return cached;
6616 mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
6618 classes_size += sizeof (MonoClassArray);
6619 ++class_array_count;
6621 if (rank == 1 && !bounded) {
6622 mono_os_mutex_lock (&image->szarray_cache_lock);
6623 g_hash_table_insert (image->szarray_cache, eclass, klass);
6624 mono_os_mutex_unlock (&image->szarray_cache_lock);
6625 } else {
6626 list = g_slist_append (rootlist, klass);
6627 g_hash_table_insert (image->array_cache, eclass, list);
6630 mono_loader_unlock ();
6632 mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
6634 return klass;
6638 * mono_array_class_get:
6639 * @element_class: element class
6640 * @rank: the dimension of the array class
6642 * Returns: A class object describing the array with element type @element_type and
6643 * dimension @rank.
6645 MonoClass *
6646 mono_array_class_get (MonoClass *eclass, guint32 rank)
6648 return mono_bounded_array_class_get (eclass, rank, FALSE);
6652 * mono_class_instance_size:
6653 * @klass: a class
6655 * Use to get the size of a class in bytes.
6657 * Returns: The size of an object instance
6659 gint32
6660 mono_class_instance_size (MonoClass *klass)
6662 if (!klass->size_inited)
6663 mono_class_init (klass);
6665 return klass->instance_size;
6669 * mono_class_min_align:
6670 * @klass: a class
6672 * Use to get the computed minimum alignment requirements for the specified class.
6674 * Returns: minimum alignment requirements
6676 gint32
6677 mono_class_min_align (MonoClass *klass)
6679 if (!klass->size_inited)
6680 mono_class_init (klass);
6682 return klass->min_align;
6686 * mono_class_value_size:
6687 * @klass: a class
6689 * This function is used for value types, and return the
6690 * space and the alignment to store that kind of value object.
6692 * Returns: the size of a value of kind @klass
6694 gint32
6695 mono_class_value_size (MonoClass *klass, guint32 *align)
6697 gint32 size;
6699 /* fixme: check disable, because we still have external revereces to
6700 * mscorlib and Dummy Objects
6702 /*g_assert (klass->valuetype);*/
6704 size = mono_class_instance_size (klass) - sizeof (MonoObject);
6706 if (align)
6707 *align = klass->min_align;
6709 return size;
6713 * mono_class_data_size:
6714 * @klass: a class
6716 * Returns: The size of the static class data
6718 gint32
6719 mono_class_data_size (MonoClass *klass)
6721 if (!klass->inited)
6722 mono_class_init (klass);
6723 /* This can happen with dynamically created types */
6724 if (!klass->fields_inited)
6725 mono_class_setup_fields (klass);
6727 /* in arrays, sizes.class_size is unioned with element_size
6728 * and arrays have no static fields
6730 if (klass->rank)
6731 return 0;
6732 return klass->sizes.class_size;
6736 * Auxiliary routine to mono_class_get_field
6738 * Takes a field index instead of a field token.
6740 static MonoClassField *
6741 mono_class_get_field_idx (MonoClass *klass, int idx)
6743 mono_class_setup_fields (klass);
6744 if (mono_class_has_failure (klass))
6745 return NULL;
6747 while (klass) {
6748 int first_field_idx = mono_class_get_first_field_idx (klass);
6749 int fcount = mono_class_get_field_count (klass);
6750 if (klass->image->uncompressed_metadata) {
6752 * first_field_idx points to the FieldPtr table, while idx points into the
6753 * Field table, so we have to do a search.
6755 /*FIXME this is broken for types with multiple fields with the same name.*/
6756 const char *name = mono_metadata_string_heap (klass->image, mono_metadata_decode_row_col (&klass->image->tables [MONO_TABLE_FIELD], idx, MONO_FIELD_NAME));
6757 int i;
6759 for (i = 0; i < fcount; ++i)
6760 if (mono_field_get_name (&klass->fields [i]) == name)
6761 return &klass->fields [i];
6762 g_assert_not_reached ();
6763 } else {
6764 if (fcount) {
6765 if ((idx >= first_field_idx) && (idx < first_field_idx + fcount)){
6766 return &klass->fields [idx - first_field_idx];
6770 klass = klass->parent;
6772 return NULL;
6776 * mono_class_get_field:
6777 * @class: the class to lookup the field.
6778 * @field_token: the field token
6780 * Returns: A MonoClassField representing the type and offset of
6781 * the field, or a NULL value if the field does not belong to this
6782 * class.
6784 MonoClassField *
6785 mono_class_get_field (MonoClass *klass, guint32 field_token)
6787 int idx = mono_metadata_token_index (field_token);
6789 g_assert (mono_metadata_token_code (field_token) == MONO_TOKEN_FIELD_DEF);
6791 return mono_class_get_field_idx (klass, idx - 1);
6795 * mono_class_get_field_from_name:
6796 * @klass: the class to lookup the field.
6797 * @name: the field name
6799 * Search the class @klass and it's parents for a field with the name @name.
6801 * Returns: The MonoClassField pointer of the named field or NULL
6803 MonoClassField *
6804 mono_class_get_field_from_name (MonoClass *klass, const char *name)
6806 return mono_class_get_field_from_name_full (klass, name, NULL);
6810 * mono_class_get_field_from_name_full:
6811 * @klass: the class to lookup the field.
6812 * @name: the field name
6813 * @type: the type of the fields. This optional.
6815 * Search the class @klass and it's parents for a field with the name @name and type @type.
6817 * If @klass is an inflated generic type, the type comparison is done with the equivalent field
6818 * of its generic type definition.
6820 * Returns: The MonoClassField pointer of the named field or NULL
6822 MonoClassField *
6823 mono_class_get_field_from_name_full (MonoClass *klass, const char *name, MonoType *type)
6825 int i;
6827 mono_class_setup_fields (klass);
6828 if (mono_class_has_failure (klass))
6829 return NULL;
6831 while (klass) {
6832 int fcount = mono_class_get_field_count (klass);
6833 for (i = 0; i < fcount; ++i) {
6834 MonoClassField *field = &klass->fields [i];
6836 if (strcmp (name, mono_field_get_name (field)) != 0)
6837 continue;
6839 if (type) {
6840 MonoType *field_type = mono_metadata_get_corresponding_field_from_generic_type_definition (field)->type;
6841 if (!mono_metadata_type_equal_full (type, field_type, TRUE))
6842 continue;
6844 return field;
6846 klass = klass->parent;
6848 return NULL;
6852 * mono_class_get_field_token:
6853 * @field: the field we need the token of
6855 * Get the token of a field. Note that the tokesn is only valid for the image
6856 * the field was loaded from. Don't use this function for fields in dynamic types.
6858 * Returns: The token representing the field in the image it was loaded from.
6860 guint32
6861 mono_class_get_field_token (MonoClassField *field)
6863 MonoClass *klass = field->parent;
6864 int i;
6866 mono_class_setup_fields (klass);
6868 while (klass) {
6869 if (!klass->fields)
6870 return 0;
6871 int first_field_idx = mono_class_get_first_field_idx (klass);
6872 int fcount = mono_class_get_field_count (klass);
6873 for (i = 0; i < fcount; ++i) {
6874 if (&klass->fields [i] == field) {
6875 int idx = first_field_idx + i + 1;
6877 if (klass->image->uncompressed_metadata)
6878 idx = mono_metadata_translate_token_index (klass->image, MONO_TABLE_FIELD, idx);
6879 return mono_metadata_make_token (MONO_TABLE_FIELD, idx);
6882 klass = klass->parent;
6885 g_assert_not_reached ();
6886 return 0;
6889 static int
6890 mono_field_get_index (MonoClassField *field)
6892 int index = field - field->parent->fields;
6893 g_assert (index >= 0 && index < mono_class_get_field_count (field->parent));
6895 return index;
6899 * mono_class_get_field_default_value:
6901 * Return the default value of the field as a pointer into the metadata blob.
6903 const char*
6904 mono_class_get_field_default_value (MonoClassField *field, MonoTypeEnum *def_type)
6906 guint32 cindex;
6907 guint32 constant_cols [MONO_CONSTANT_SIZE];
6908 int field_index;
6909 MonoClass *klass = field->parent;
6910 MonoFieldDefaultValue *def_values;
6912 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
6914 def_values = mono_class_get_field_def_values (klass);
6915 if (!def_values) {
6916 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
6918 mono_class_set_field_def_values (klass, def_values);
6921 field_index = mono_field_get_index (field);
6923 if (!def_values [field_index].data) {
6924 cindex = mono_metadata_get_constant_index (field->parent->image, mono_class_get_field_token (field), 0);
6925 if (!cindex)
6926 return NULL;
6928 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
6930 mono_metadata_decode_row (&field->parent->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
6931 def_values [field_index].def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
6932 mono_memory_barrier ();
6933 def_values [field_index].data = (const char *)mono_metadata_blob_heap (field->parent->image, constant_cols [MONO_CONSTANT_VALUE]);
6936 *def_type = def_values [field_index].def_type;
6937 return def_values [field_index].data;
6940 static int
6941 mono_property_get_index (MonoProperty *prop)
6943 MonoClassPropertyInfo *info = mono_class_get_property_info (prop->parent);
6944 int index = prop - info->properties;
6946 g_assert (index >= 0 && index < info->count);
6948 return index;
6952 * mono_class_get_property_default_value:
6954 * Return the default value of the field as a pointer into the metadata blob.
6956 const char*
6957 mono_class_get_property_default_value (MonoProperty *property, MonoTypeEnum *def_type)
6959 guint32 cindex;
6960 guint32 constant_cols [MONO_CONSTANT_SIZE];
6961 MonoClass *klass = property->parent;
6963 g_assert (property->attrs & PROPERTY_ATTRIBUTE_HAS_DEFAULT);
6965 * We don't cache here because it is not used by C# so it's quite rare, but
6966 * we still do the lookup in klass->ext because that is where the data
6967 * is stored for dynamic assemblies.
6970 if (image_is_dynamic (klass->image)) {
6971 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
6972 int prop_index = mono_property_get_index (property);
6973 if (info->def_values && info->def_values [prop_index].data) {
6974 *def_type = info->def_values [prop_index].def_type;
6975 return info->def_values [prop_index].data;
6977 return NULL;
6979 cindex = mono_metadata_get_constant_index (klass->image, mono_class_get_property_token (property), 0);
6980 if (!cindex)
6981 return NULL;
6983 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
6984 *def_type = (MonoTypeEnum)constant_cols [MONO_CONSTANT_TYPE];
6985 return (const char *)mono_metadata_blob_heap (klass->image, constant_cols [MONO_CONSTANT_VALUE]);
6988 guint32
6989 mono_class_get_event_token (MonoEvent *event)
6991 MonoClass *klass = event->parent;
6992 int i;
6994 while (klass) {
6995 MonoClassEventInfo *info = mono_class_get_event_info (klass);
6996 if (info) {
6997 for (i = 0; i < info->count; ++i) {
6998 if (&info->events [i] == event)
6999 return mono_metadata_make_token (MONO_TABLE_EVENT, info->first + i + 1);
7002 klass = klass->parent;
7005 g_assert_not_reached ();
7006 return 0;
7010 * mono_class_get_property_from_name:
7011 * @klass: a class
7012 * @name: name of the property to lookup in the specified class
7014 * Use this method to lookup a property in a class
7015 * Returns: the MonoProperty with the given name, or NULL if the property
7016 * does not exist on the @klass.
7018 MonoProperty*
7019 mono_class_get_property_from_name (MonoClass *klass, const char *name)
7021 while (klass) {
7022 MonoProperty* p;
7023 gpointer iter = NULL;
7024 while ((p = mono_class_get_properties (klass, &iter))) {
7025 if (! strcmp (name, p->name))
7026 return p;
7028 klass = klass->parent;
7030 return NULL;
7034 * mono_class_get_property_token:
7035 * @prop: MonoProperty to query
7037 * Returns: The ECMA token for the specified property.
7039 guint32
7040 mono_class_get_property_token (MonoProperty *prop)
7042 MonoClass *klass = prop->parent;
7043 while (klass) {
7044 MonoProperty* p;
7045 int i = 0;
7046 gpointer iter = NULL;
7047 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
7048 while ((p = mono_class_get_properties (klass, &iter))) {
7049 if (&info->properties [i] == prop)
7050 return mono_metadata_make_token (MONO_TABLE_PROPERTY, info->first + i + 1);
7052 i ++;
7054 klass = klass->parent;
7057 g_assert_not_reached ();
7058 return 0;
7061 char *
7062 mono_class_name_from_token (MonoImage *image, guint32 type_token)
7064 const char *name, *nspace;
7065 if (image_is_dynamic (image))
7066 return g_strdup_printf ("DynamicType 0x%08x", type_token);
7068 switch (type_token & 0xff000000){
7069 case MONO_TOKEN_TYPE_DEF: {
7070 guint32 cols [MONO_TYPEDEF_SIZE];
7071 MonoTableInfo *tt = &image->tables [MONO_TABLE_TYPEDEF];
7072 guint tidx = mono_metadata_token_index (type_token);
7074 if (tidx > tt->rows)
7075 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7077 mono_metadata_decode_row (tt, tidx - 1, cols, MONO_TYPEDEF_SIZE);
7078 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7079 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7080 if (strlen (nspace) == 0)
7081 return g_strdup_printf ("%s", name);
7082 else
7083 return g_strdup_printf ("%s.%s", nspace, name);
7086 case MONO_TOKEN_TYPE_REF: {
7087 MonoError error;
7088 guint32 cols [MONO_TYPEREF_SIZE];
7089 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7090 guint tidx = mono_metadata_token_index (type_token);
7092 if (tidx > t->rows)
7093 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7095 if (!mono_verifier_verify_typeref_row (image, tidx - 1, &error)) {
7096 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7097 mono_error_cleanup (&error);
7098 return msg;
7101 mono_metadata_decode_row (t, tidx-1, cols, MONO_TYPEREF_SIZE);
7102 name = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAME]);
7103 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEREF_NAMESPACE]);
7104 if (strlen (nspace) == 0)
7105 return g_strdup_printf ("%s", name);
7106 else
7107 return g_strdup_printf ("%s.%s", nspace, name);
7110 case MONO_TOKEN_TYPE_SPEC:
7111 return g_strdup_printf ("Typespec 0x%08x", type_token);
7112 default:
7113 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7117 static char *
7118 mono_assembly_name_from_token (MonoImage *image, guint32 type_token)
7120 if (image_is_dynamic (image))
7121 return g_strdup_printf ("DynamicAssembly %s", image->name);
7123 switch (type_token & 0xff000000){
7124 case MONO_TOKEN_TYPE_DEF:
7125 if (image->assembly)
7126 return mono_stringify_assembly_name (&image->assembly->aname);
7127 else if (image->assembly_name)
7128 return g_strdup (image->assembly_name);
7129 return g_strdup_printf ("%s", image->name ? image->name : "[Could not resolve assembly name");
7130 case MONO_TOKEN_TYPE_REF: {
7131 MonoError error;
7132 MonoAssemblyName aname;
7133 guint32 cols [MONO_TYPEREF_SIZE];
7134 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEREF];
7135 guint32 idx = mono_metadata_token_index (type_token);
7137 if (idx > t->rows)
7138 return g_strdup_printf ("Invalid type token 0x%08x", type_token);
7140 if (!mono_verifier_verify_typeref_row (image, idx - 1, &error)) {
7141 char *msg = g_strdup_printf ("Invalid type token 0x%08x due to '%s'", type_token, mono_error_get_message (&error));
7142 mono_error_cleanup (&error);
7143 return msg;
7145 mono_metadata_decode_row (t, idx-1, cols, MONO_TYPEREF_SIZE);
7147 idx = cols [MONO_TYPEREF_SCOPE] >> MONO_RESOLUTION_SCOPE_BITS;
7148 switch (cols [MONO_TYPEREF_SCOPE] & MONO_RESOLUTION_SCOPE_MASK) {
7149 case MONO_RESOLUTION_SCOPE_MODULE:
7150 /* FIXME: */
7151 return g_strdup ("");
7152 case MONO_RESOLUTION_SCOPE_MODULEREF:
7153 /* FIXME: */
7154 return g_strdup ("");
7155 case MONO_RESOLUTION_SCOPE_TYPEREF:
7156 /* FIXME: */
7157 return g_strdup ("");
7158 case MONO_RESOLUTION_SCOPE_ASSEMBLYREF:
7159 mono_assembly_get_assemblyref (image, idx - 1, &aname);
7160 return mono_stringify_assembly_name (&aname);
7161 default:
7162 g_assert_not_reached ();
7164 break;
7166 case MONO_TOKEN_TYPE_SPEC:
7167 /* FIXME: */
7168 return g_strdup ("");
7169 default:
7170 g_assert_not_reached ();
7173 return NULL;
7177 * mono_class_get_full:
7178 * @image: the image where the class resides
7179 * @type_token: the token for the class
7180 * @context: the generic context used to evaluate generic instantiations in
7181 * @deprecated: Functions that expose MonoGenericContext are going away in mono 4.0
7183 * Returns: The MonoClass that represents @type_token in @image
7185 MonoClass *
7186 mono_class_get_full (MonoImage *image, guint32 type_token, MonoGenericContext *context)
7188 MonoError error;
7189 MonoClass *klass;
7190 klass = mono_class_get_checked (image, type_token, &error);
7192 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7193 klass = mono_class_inflate_generic_class_checked (klass, context, &error);
7195 g_assert (mono_error_ok (&error)); /* FIXME deprecate this function and forbit the runtime from using it. */
7196 return klass;
7200 MonoClass *
7201 mono_class_get_and_inflate_typespec_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7203 MonoClass *klass;
7205 mono_error_init (error);
7206 klass = mono_class_get_checked (image, type_token, error);
7208 if (klass && context && mono_metadata_token_table (type_token) == MONO_TABLE_TYPESPEC)
7209 klass = mono_class_inflate_generic_class_checked (klass, context, error);
7211 return klass;
7214 * mono_class_get_checked:
7215 * @image: the image where the class resides
7216 * @type_token: the token for the class
7217 * @error: error object to return any error
7219 * Returns: The MonoClass that represents @type_token in @image, or NULL on error.
7221 MonoClass *
7222 mono_class_get_checked (MonoImage *image, guint32 type_token, MonoError *error)
7224 MonoClass *klass = NULL;
7226 mono_error_init (error);
7228 if (image_is_dynamic (image)) {
7229 int table = mono_metadata_token_table (type_token);
7231 if (table != MONO_TABLE_TYPEDEF && table != MONO_TABLE_TYPEREF && table != MONO_TABLE_TYPESPEC) {
7232 mono_error_set_bad_image (error, image,"Bad token table for dynamic image: %x", table);
7233 return NULL;
7235 klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, NULL, error);
7236 goto done;
7239 switch (type_token & 0xff000000){
7240 case MONO_TOKEN_TYPE_DEF:
7241 klass = mono_class_create_from_typedef (image, type_token, error);
7242 break;
7243 case MONO_TOKEN_TYPE_REF:
7244 klass = mono_class_from_typeref_checked (image, type_token, error);
7245 break;
7246 case MONO_TOKEN_TYPE_SPEC:
7247 klass = mono_class_create_from_typespec (image, type_token, NULL, error);
7248 break;
7249 default:
7250 mono_error_set_bad_image (error, image, "Unknown type token %x", type_token & 0xff000000);
7253 done:
7254 /* Generic case, should be avoided for when a better error is possible. */
7255 if (!klass && mono_error_ok (error)) {
7256 char *name = mono_class_name_from_token (image, type_token);
7257 char *assembly = mono_assembly_name_from_token (image, type_token);
7258 mono_error_set_type_load_name (error, name, assembly, "Could not resolve type with token %08x (class/assembly %s, %s)", type_token, name, assembly);
7261 return klass;
7266 * mono_type_get_checked:
7267 * @image: the image where the type resides
7268 * @type_token: the token for the type
7269 * @context: the generic context used to evaluate generic instantiations in
7270 * @error: Error handling context
7272 * This functions exists to fullfill the fact that sometimes it's desirable to have access to the
7274 * Returns: The MonoType that represents @type_token in @image
7276 MonoType *
7277 mono_type_get_checked (MonoImage *image, guint32 type_token, MonoGenericContext *context, MonoError *error)
7279 MonoType *type = NULL;
7280 gboolean inflated = FALSE;
7282 mono_error_init (error);
7284 //FIXME: this will not fix the very issue for which mono_type_get_full exists -but how to do it then?
7285 if (image_is_dynamic (image)) {
7286 MonoClass *klass = (MonoClass *)mono_lookup_dynamic_token (image, type_token, context, error);
7287 return_val_if_nok (error, NULL);
7288 return mono_class_get_type (klass);
7291 if ((type_token & 0xff000000) != MONO_TOKEN_TYPE_SPEC) {
7292 MonoClass *klass = mono_class_get_checked (image, type_token, error);
7294 if (!klass) {
7295 return NULL;
7298 g_assert (klass);
7299 return mono_class_get_type (klass);
7302 type = mono_type_retrieve_from_typespec (image, type_token, context, &inflated, error);
7304 if (!type) {
7305 return NULL;
7308 if (inflated) {
7309 MonoType *tmp = type;
7310 type = mono_class_get_type (mono_class_from_mono_type (type));
7311 /* FIXME: This is a workaround fo the fact that a typespec token sometimes reference to the generic type definition.
7312 * A MonoClass::byval_arg of a generic type definion has type CLASS.
7313 * Some parts of mono create a GENERICINST to reference a generic type definition and this generates confict with byval_arg.
7315 * The long term solution is to chaise this places and make then set MonoType::type correctly.
7316 * */
7317 if (type->type != tmp->type)
7318 type = tmp;
7319 else
7320 mono_metadata_free_type (tmp);
7322 return type;
7326 * mono_class_get:
7327 * @image: image where the class token will be looked up.
7328 * @type_token: a type token from the image
7330 * Returns the MonoClass with the given @type_token on the @image
7332 MonoClass *
7333 mono_class_get (MonoImage *image, guint32 type_token)
7335 return mono_class_get_full (image, type_token, NULL);
7339 * mono_image_init_name_cache:
7341 * Initializes the class name cache stored in image->name_cache.
7343 * LOCKING: Acquires the corresponding image lock.
7345 void
7346 mono_image_init_name_cache (MonoImage *image)
7348 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7349 guint32 cols [MONO_TYPEDEF_SIZE];
7350 const char *name;
7351 const char *nspace;
7352 guint32 i, visib, nspace_index;
7353 GHashTable *name_cache2, *nspace_table, *the_name_cache;
7355 if (image->name_cache)
7356 return;
7358 the_name_cache = g_hash_table_new (g_str_hash, g_str_equal);
7360 if (image_is_dynamic (image)) {
7361 mono_image_lock (image);
7362 if (image->name_cache) {
7363 /* Somebody initialized it before us */
7364 g_hash_table_destroy (the_name_cache);
7365 } else {
7366 mono_atomic_store_release (&image->name_cache, the_name_cache);
7368 mono_image_unlock (image);
7369 return;
7372 /* Temporary hash table to avoid lookups in the nspace_table */
7373 name_cache2 = g_hash_table_new (NULL, NULL);
7375 for (i = 1; i <= t->rows; ++i) {
7376 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7377 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7379 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7380 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7382 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7383 continue;
7384 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7385 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7387 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
7388 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7389 if (!nspace_table) {
7390 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7391 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7392 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7393 nspace_table);
7395 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
7398 /* Load type names from EXPORTEDTYPES table */
7400 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7401 guint32 cols [MONO_EXP_TYPE_SIZE];
7402 int i;
7404 for (i = 0; i < t->rows; ++i) {
7405 mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
7407 guint32 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7408 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_EXP_TYPE)
7409 /* Nested type */
7410 continue;
7412 name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
7413 nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
7415 nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
7416 nspace_table = (GHashTable *)g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
7417 if (!nspace_table) {
7418 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7419 g_hash_table_insert (the_name_cache, (char*)nspace, nspace_table);
7420 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
7421 nspace_table);
7423 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
7427 g_hash_table_destroy (name_cache2);
7429 mono_image_lock (image);
7430 if (image->name_cache) {
7431 /* Somebody initialized it before us */
7432 g_hash_table_destroy (the_name_cache);
7433 } else {
7434 mono_atomic_store_release (&image->name_cache, the_name_cache);
7436 mono_image_unlock (image);
7439 /*FIXME Only dynamic assemblies should allow this operation.*/
7440 void
7441 mono_image_add_to_name_cache (MonoImage *image, const char *nspace,
7442 const char *name, guint32 index)
7444 GHashTable *nspace_table;
7445 GHashTable *name_cache;
7446 guint32 old_index;
7448 mono_image_init_name_cache (image);
7449 mono_image_lock (image);
7451 name_cache = image->name_cache;
7452 if (!(nspace_table = (GHashTable *)g_hash_table_lookup (name_cache, nspace))) {
7453 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
7454 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
7457 if ((old_index = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, (char*) name))))
7458 g_error ("overrwritting old token %x on image %s for type %s::%s", old_index, image->name, nspace, name);
7460 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
7462 mono_image_unlock (image);
7465 typedef struct {
7466 gconstpointer key;
7467 gpointer value;
7468 } FindUserData;
7470 static void
7471 find_nocase (gpointer key, gpointer value, gpointer user_data)
7473 char *name = (char*)key;
7474 FindUserData *data = (FindUserData*)user_data;
7476 if (!data->value && (mono_utf8_strcasecmp (name, (char*)data->key) == 0))
7477 data->value = value;
7481 * mono_class_from_name_case:
7482 * @image: The MonoImage where the type is looked up in
7483 * @name_space: the type namespace
7484 * @name: the type short name.
7485 * @deprecated: use the mono_class_from_name_case_checked variant instead.
7487 * Obtains a MonoClass with a given namespace and a given name which
7488 * is located in the given MonoImage. The namespace and name
7489 * lookups are case insensitive.
7491 MonoClass *
7492 mono_class_from_name_case (MonoImage *image, const char* name_space, const char *name)
7494 MonoError error;
7495 MonoClass *res = mono_class_from_name_case_checked (image, name_space, name, &error);
7496 mono_error_cleanup (&error);
7498 return res;
7502 * mono_class_from_name_case:
7503 * @image: The MonoImage where the type is looked up in
7504 * @name_space: the type namespace
7505 * @name: the type short name.
7506 * @error: if
7508 * Obtains a MonoClass with a given namespace and a given name which
7509 * is located in the given MonoImage. The namespace and name
7510 * lookups are case insensitive.
7512 * Returns: The MonoClass if the given namespace and name were found, or NULL if it
7513 * was not found. The @error object will contain information about the problem
7514 * in that case.
7516 MonoClass *
7517 mono_class_from_name_case_checked (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7519 MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
7520 guint32 cols [MONO_TYPEDEF_SIZE];
7521 const char *n;
7522 const char *nspace;
7523 guint32 i, visib;
7525 mono_error_init (error);
7527 if (image_is_dynamic (image)) {
7528 guint32 token = 0;
7529 FindUserData user_data;
7531 mono_image_init_name_cache (image);
7532 mono_image_lock (image);
7534 user_data.key = name_space;
7535 user_data.value = NULL;
7536 g_hash_table_foreach (image->name_cache, find_nocase, &user_data);
7538 if (user_data.value) {
7539 GHashTable *nspace_table = (GHashTable*)user_data.value;
7541 user_data.key = name;
7542 user_data.value = NULL;
7544 g_hash_table_foreach (nspace_table, find_nocase, &user_data);
7546 if (user_data.value)
7547 token = GPOINTER_TO_UINT (user_data.value);
7550 mono_image_unlock (image);
7552 if (token)
7553 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | token, error);
7554 else
7555 return NULL;
7559 /* add a cache if needed */
7560 for (i = 1; i <= t->rows; ++i) {
7561 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
7562 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
7564 * Nested types are accessed from the nesting name. We use the fact that nested types use different visibility flags
7565 * than toplevel types, thus avoiding the need to grovel through the NESTED_TYPE table
7567 if (visib >= TYPE_ATTRIBUTE_NESTED_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM)
7568 continue;
7569 n = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
7570 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
7571 if (mono_utf8_strcasecmp (n, name) == 0 && mono_utf8_strcasecmp (nspace, name_space) == 0)
7572 return mono_class_get_checked (image, MONO_TOKEN_TYPE_DEF | i, error);
7574 return NULL;
7577 static MonoClass*
7578 return_nested_in (MonoClass *klass, char *nested)
7580 MonoClass *found;
7581 char *s = strchr (nested, '/');
7582 gpointer iter = NULL;
7584 if (s) {
7585 *s = 0;
7586 s++;
7589 while ((found = mono_class_get_nested_types (klass, &iter))) {
7590 if (strcmp (found->name, nested) == 0) {
7591 if (s)
7592 return return_nested_in (found, s);
7593 return found;
7596 return NULL;
7599 static MonoClass*
7600 search_modules (MonoImage *image, const char *name_space, const char *name, MonoError *error)
7602 MonoTableInfo *file_table = &image->tables [MONO_TABLE_FILE];
7603 MonoImage *file_image;
7604 MonoClass *klass;
7605 int i;
7607 mono_error_init (error);
7610 * The EXPORTEDTYPES table only contains public types, so have to search the
7611 * modules as well.
7612 * Note: image->modules contains the contents of the MODULEREF table, while
7613 * the real module list is in the FILE table.
7615 for (i = 0; i < file_table->rows; i++) {
7616 guint32 cols [MONO_FILE_SIZE];
7617 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
7618 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
7619 continue;
7621 file_image = mono_image_load_file_for_image_checked (image, i + 1, error);
7622 if (file_image) {
7623 klass = mono_class_from_name_checked (file_image, name_space, name, error);
7624 if (klass || !is_ok (error))
7625 return klass;
7629 return NULL;
7632 static MonoClass *
7633 mono_class_from_name_checked_aux (MonoImage *image, const char* name_space, const char *name, GHashTable* visited_images, MonoError *error)
7635 GHashTable *nspace_table;
7636 MonoImage *loaded_image;
7637 guint32 token = 0;
7638 int i;
7639 MonoClass *klass;
7640 char *nested;
7641 char buf [1024];
7643 mono_error_init (error);
7645 // Checking visited images avoids stack overflows when cyclic references exist.
7646 if (g_hash_table_lookup (visited_images, image))
7647 return NULL;
7649 g_hash_table_insert (visited_images, image, GUINT_TO_POINTER(1));
7651 if ((nested = strchr (name, '/'))) {
7652 int pos = nested - name;
7653 int len = strlen (name);
7654 if (len > 1023)
7655 return NULL;
7656 memcpy (buf, name, len + 1);
7657 buf [pos] = 0;
7658 nested = buf + pos + 1;
7659 name = buf;
7662 /* FIXME: get_class_from_name () can't handle types in the EXPORTEDTYPE table */
7663 if (get_class_from_name && image->tables [MONO_TABLE_EXPORTEDTYPE].rows == 0) {
7664 gboolean res = get_class_from_name (image, name_space, name, &klass);
7665 if (res) {
7666 if (!klass) {
7667 klass = search_modules (image, name_space, name, error);
7668 if (!is_ok (error))
7669 return NULL;
7671 if (nested)
7672 return klass ? return_nested_in (klass, nested) : NULL;
7673 else
7674 return klass;
7678 mono_image_init_name_cache (image);
7679 mono_image_lock (image);
7681 nspace_table = (GHashTable *)g_hash_table_lookup (image->name_cache, name_space);
7683 if (nspace_table)
7684 token = GPOINTER_TO_UINT (g_hash_table_lookup (nspace_table, name));
7686 mono_image_unlock (image);
7688 if (!token && image_is_dynamic (image) && image->modules) {
7689 /* Search modules as well */
7690 for (i = 0; i < image->module_count; ++i) {
7691 MonoImage *module = image->modules [i];
7693 klass = mono_class_from_name_checked (module, name_space, name, error);
7694 if (klass || !is_ok (error))
7695 return klass;
7699 if (!token) {
7700 klass = search_modules (image, name_space, name, error);
7701 if (klass || !is_ok (error))
7702 return klass;
7703 return NULL;
7706 if (mono_metadata_token_table (token) == MONO_TABLE_EXPORTEDTYPE) {
7707 MonoTableInfo *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
7708 guint32 cols [MONO_EXP_TYPE_SIZE];
7709 guint32 idx, impl;
7711 idx = mono_metadata_token_index (token);
7713 mono_metadata_decode_row (t, idx - 1, cols, MONO_EXP_TYPE_SIZE);
7715 impl = cols [MONO_EXP_TYPE_IMPLEMENTATION];
7716 if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_FILE) {
7717 loaded_image = mono_assembly_load_module_checked (image->assembly, impl >> MONO_IMPLEMENTATION_BITS, error);
7718 if (!loaded_image)
7719 return NULL;
7720 klass = mono_class_from_name_checked_aux (loaded_image, name_space, name, visited_images, error);
7721 if (nested)
7722 return klass ? return_nested_in (klass, nested) : NULL;
7723 return klass;
7724 } else if ((impl & MONO_IMPLEMENTATION_MASK) == MONO_IMPLEMENTATION_ASSEMBLYREF) {
7725 guint32 assembly_idx;
7727 assembly_idx = impl >> MONO_IMPLEMENTATION_BITS;
7729 mono_assembly_load_reference (image, assembly_idx - 1);
7730 g_assert (image->references [assembly_idx - 1]);
7731 if (image->references [assembly_idx - 1] == (gpointer)-1)
7732 return NULL;
7733 klass = mono_class_from_name_checked_aux (image->references [assembly_idx - 1]->image, name_space, name, visited_images, error);
7734 if (nested)
7735 return klass ? return_nested_in (klass, nested) : NULL;
7736 return klass;
7737 } else {
7738 g_assert_not_reached ();
7742 token = MONO_TOKEN_TYPE_DEF | token;
7744 klass = mono_class_get_checked (image, token, error);
7745 if (nested)
7746 return return_nested_in (klass, nested);
7747 return klass;
7751 * mono_class_from_name_checked:
7752 * @image: The MonoImage where the type is looked up in
7753 * @name_space: the type namespace
7754 * @name: the type short name.
7756 * Obtains a MonoClass with a given namespace and a given name which
7757 * is located in the given MonoImage.
7759 * Works like mono_class_from_name, but error handling is tricky. It can return NULL and have no error
7760 * set if the class was not found or it will return NULL and set the error if there was a loading error.
7762 MonoClass *
7763 mono_class_from_name_checked (MonoImage *image, const char* name_space, const char *name, MonoError *error)
7765 MonoClass *klass;
7766 GHashTable *visited_images;
7768 visited_images = g_hash_table_new (g_direct_hash, g_direct_equal);
7770 klass = mono_class_from_name_checked_aux (image, name_space, name, visited_images, error);
7772 g_hash_table_destroy (visited_images);
7774 return klass;
7778 * mono_class_from_name:
7779 * @image: The MonoImage where the type is looked up in
7780 * @name_space: the type namespace
7781 * @name: the type short name.
7783 * Obtains a MonoClass with a given namespace and a given name which
7784 * is located in the given MonoImage.
7786 * To reference nested classes, use the "/" character as a separator.
7787 * For example use "Foo/Bar" to reference the class Bar that is nested
7788 * inside Foo, like this: "class Foo { class Bar {} }".
7790 MonoClass *
7791 mono_class_from_name (MonoImage *image, const char* name_space, const char *name)
7793 MonoError error;
7794 MonoClass *klass;
7796 klass = mono_class_from_name_checked (image, name_space, name, &error);
7797 mono_error_cleanup (&error); /* FIXME Don't swallow the error */
7799 return klass;
7803 * mono_class_load_from_name:
7804 * @image: The MonoImage where the type is looked up in
7805 * @name_space: the type namespace
7806 * @name: the type short name.
7808 * This function works exactly like mono_class_from_name but it will abort if the class is not found.
7809 * This function should be used by the runtime for critical types to which there's no way to recover but crash
7810 * If they are missing. Thing of System.Object or System.String.
7812 MonoClass *
7813 mono_class_load_from_name (MonoImage *image, const char* name_space, const char *name)
7815 MonoError error;
7816 MonoClass *klass;
7818 klass = mono_class_from_name_checked (image, name_space, name, &error);
7819 if (!klass)
7820 g_error ("Runtime critical type %s.%s not found", name_space, name);
7821 if (!mono_error_ok (&error))
7822 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
7823 return klass;
7827 * mono_class_try_load_from_name:
7828 * @image: The MonoImage where the type is looked up in
7829 * @name_space: the type namespace
7830 * @name: the type short name.
7832 * This function tries to load a type, returning the class was found or NULL otherwise.
7833 * This function should be used by the runtime when probing for optional types, those that could have being linked out.
7835 * Big design consideration. This function aborts if there was an error loading the type. This prevents us from missing
7836 * a type that we would otherwise assume to be available but was not due some error.
7839 MonoClass*
7840 mono_class_try_load_from_name (MonoImage *image, const char* name_space, const char *name)
7842 MonoError error;
7843 MonoClass *klass;
7845 klass = mono_class_from_name_checked (image, name_space, name, &error);
7846 if (!mono_error_ok (&error))
7847 g_error ("Could not load runtime critical type %s.%s due to %s", name_space, name, mono_error_get_message (&error));
7848 return klass;
7853 * mono_class_is_subclass_of:
7854 * @klass: class to probe if it is a subclass of another one
7855 * @klassc: the class we suspect is the base class
7856 * @check_interfaces: whether we should perform interface checks
7858 * This method determines whether @klass is a subclass of @klassc.
7860 * If the @check_interfaces flag is set, then if @klassc is an interface
7861 * this method return TRUE if the @klass implements the interface or
7862 * if @klass is an interface, if one of its base classes is @klass.
7864 * If @check_interfaces is false then, then if @klass is not an interface
7865 * then it returns TRUE if the @klass is a subclass of @klassc.
7867 * if @klass is an interface and @klassc is System.Object, then this function
7868 * return true.
7871 gboolean
7872 mono_class_is_subclass_of (MonoClass *klass, MonoClass *klassc,
7873 gboolean check_interfaces)
7875 /* FIXME test for interfaces with variant generic arguments */
7876 mono_class_init (klass);
7877 mono_class_init (klassc);
7879 if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && !MONO_CLASS_IS_INTERFACE (klass)) {
7880 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, klassc->interface_id))
7881 return TRUE;
7882 } else if (check_interfaces && MONO_CLASS_IS_INTERFACE (klassc) && MONO_CLASS_IS_INTERFACE (klass)) {
7883 int i;
7885 for (i = 0; i < klass->interface_count; i ++) {
7886 MonoClass *ic = klass->interfaces [i];
7887 if (ic == klassc)
7888 return TRUE;
7890 } else {
7891 if (!MONO_CLASS_IS_INTERFACE (klass) && mono_class_has_parent (klass, klassc))
7892 return TRUE;
7896 * MS.NET thinks interfaces are a subclass of Object, so we think it as
7897 * well.
7899 if (klassc == mono_defaults.object_class)
7900 return TRUE;
7902 return FALSE;
7905 static gboolean
7906 mono_type_is_generic_argument (MonoType *type)
7908 return type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR;
7911 gboolean
7912 mono_class_has_variant_generic_params (MonoClass *klass)
7914 int i;
7915 MonoGenericContainer *container;
7917 if (!mono_class_is_ginst (klass))
7918 return FALSE;
7920 container = mono_class_get_generic_container (mono_class_get_generic_class (klass)->container_class);
7922 for (i = 0; i < container->type_argc; ++i)
7923 if (mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT))
7924 return TRUE;
7926 return FALSE;
7929 static gboolean
7930 mono_gparam_is_reference_conversible (MonoClass *target, MonoClass *candidate, gboolean check_for_reference_conv)
7932 if (target == candidate)
7933 return TRUE;
7935 if (check_for_reference_conv &&
7936 mono_type_is_generic_argument (&target->byval_arg) &&
7937 mono_type_is_generic_argument (&candidate->byval_arg)) {
7938 MonoGenericParam *gparam = candidate->byval_arg.data.generic_param;
7939 MonoGenericParamInfo *pinfo = mono_generic_param_info (gparam);
7941 if (!pinfo || (pinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) == 0)
7942 return FALSE;
7944 if (!mono_class_is_assignable_from (target, candidate))
7945 return FALSE;
7946 return TRUE;
7950 * @container the generic container from the GTD
7951 * @klass: the class to be assigned to
7952 * @oklass: the source class
7954 * Both @klass and @oklass must be instances of the same generic interface.
7956 * Returns: TRUE if @klass can be assigned to a @klass variable
7958 gboolean
7959 mono_class_is_variant_compatible (MonoClass *klass, MonoClass *oklass, gboolean check_for_reference_conv)
7961 int j;
7962 MonoType **klass_argv, **oklass_argv;
7963 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
7964 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
7966 if (klass == oklass)
7967 return TRUE;
7969 /*Viable candidates are instances of the same generic interface*/
7970 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
7971 return FALSE;
7973 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
7974 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
7976 for (j = 0; j < container->type_argc; ++j) {
7977 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
7978 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
7980 if (param1_class->valuetype != param2_class->valuetype || (param1_class->valuetype && param1_class != param2_class))
7981 return FALSE;
7984 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
7985 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
7987 if (param1_class != param2_class) {
7988 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
7989 if (!mono_gparam_is_reference_conversible (param1_class, param2_class, check_for_reference_conv))
7990 return FALSE;
7991 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
7992 if (!mono_gparam_is_reference_conversible (param2_class, param1_class, check_for_reference_conv))
7993 return FALSE;
7994 } else
7995 return FALSE;
7998 return TRUE;
8001 static gboolean
8002 mono_gparam_is_assignable_from (MonoClass *target, MonoClass *candidate)
8004 MonoGenericParam *gparam, *ogparam;
8005 MonoGenericParamInfo *tinfo, *cinfo;
8006 MonoClass **candidate_class;
8007 gboolean class_constraint_satisfied, valuetype_constraint_satisfied;
8008 int tmask, cmask;
8010 if (target == candidate)
8011 return TRUE;
8012 if (target->byval_arg.type != candidate->byval_arg.type)
8013 return FALSE;
8015 gparam = target->byval_arg.data.generic_param;
8016 ogparam = candidate->byval_arg.data.generic_param;
8017 tinfo = mono_generic_param_info (gparam);
8018 cinfo = mono_generic_param_info (ogparam);
8020 class_constraint_satisfied = FALSE;
8021 valuetype_constraint_satisfied = FALSE;
8023 /*candidate must have a super set of target's special constraints*/
8024 tmask = tinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8025 cmask = cinfo->flags & GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINTS_MASK;
8027 if (cinfo->constraints) {
8028 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8029 MonoClass *cc = *candidate_class;
8031 if (mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8032 class_constraint_satisfied = TRUE;
8033 else if (!mono_type_is_reference (&cc->byval_arg) && !MONO_CLASS_IS_INTERFACE (cc))
8034 valuetype_constraint_satisfied = TRUE;
8037 class_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) != 0;
8038 valuetype_constraint_satisfied |= (cmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) != 0;
8040 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && !class_constraint_satisfied)
8041 return FALSE;
8042 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_VALUE_TYPE_CONSTRAINT) && !valuetype_constraint_satisfied)
8043 return FALSE;
8044 if ((tmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !((cmask & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) ||
8045 valuetype_constraint_satisfied)) {
8046 return FALSE;
8050 /*candidate type constraints must be a superset of target's*/
8051 if (tinfo->constraints) {
8052 MonoClass **target_class;
8053 for (target_class = tinfo->constraints; *target_class; ++target_class) {
8054 MonoClass *tc = *target_class;
8057 * A constraint from @target might inflate into @candidate itself and in that case we don't need
8058 * check it's constraints since it satisfy the constraint by itself.
8060 if (mono_metadata_type_equal (&tc->byval_arg, &candidate->byval_arg))
8061 continue;
8063 if (!cinfo->constraints)
8064 return FALSE;
8066 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8067 MonoClass *cc = *candidate_class;
8069 if (mono_class_is_assignable_from (tc, cc))
8070 break;
8073 * This happens when we have the following:
8075 * Bar<K> where K : IFace
8076 * Foo<T, U> where T : U where U : IFace
8077 * ...
8078 * Bar<T> <- T here satisfy K constraint transitively through to U's constraint
8081 if (mono_type_is_generic_argument (&cc->byval_arg)) {
8082 if (mono_gparam_is_assignable_from (target, cc))
8083 break;
8086 if (!*candidate_class)
8087 return FALSE;
8091 /*candidate itself must have a constraint that satisfy target*/
8092 if (cinfo->constraints) {
8093 for (candidate_class = cinfo->constraints; *candidate_class; ++candidate_class) {
8094 MonoClass *cc = *candidate_class;
8095 if (mono_class_is_assignable_from (target, cc))
8096 return TRUE;
8099 return FALSE;
8103 * mono_class_is_assignable_from:
8104 * @klass: the class to be assigned to
8105 * @oklass: the source class
8107 * Returns: TRUE if an instance of object oklass can be assigned to an
8108 * instance of object @klass
8110 gboolean
8111 mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
8113 MonoError error;
8114 /*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
8115 if (!klass->inited)
8116 mono_class_init (klass);
8118 if (!oklass->inited)
8119 mono_class_init (oklass);
8121 if (mono_class_has_failure (klass) || mono_class_has_failure (oklass))
8122 return FALSE;
8124 if (mono_type_is_generic_argument (&klass->byval_arg)) {
8125 if (!mono_type_is_generic_argument (&oklass->byval_arg))
8126 return FALSE;
8127 return mono_gparam_is_assignable_from (klass, oklass);
8130 if (MONO_CLASS_IS_INTERFACE (klass)) {
8131 if ((oklass->byval_arg.type == MONO_TYPE_VAR) || (oklass->byval_arg.type == MONO_TYPE_MVAR)) {
8132 MonoGenericParam *gparam = oklass->byval_arg.data.generic_param;
8133 MonoClass **constraints = mono_generic_container_get_param_info (gparam->owner, gparam->num)->constraints;
8134 int i;
8136 if (constraints) {
8137 for (i = 0; constraints [i]; ++i) {
8138 if (mono_class_is_assignable_from (klass, constraints [i]))
8139 return TRUE;
8143 return FALSE;
8146 /* interface_offsets might not be set for dynamic classes */
8147 if (mono_class_get_ref_info_handle (oklass) && !oklass->interface_bitmap) {
8149 * oklass might be a generic type parameter but they have
8150 * interface_offsets set.
8152 gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
8153 if (!is_ok (&error)) {
8154 mono_error_cleanup (&error);
8155 return FALSE;
8157 return result;
8159 if (!oklass->interface_bitmap)
8160 /* Happens with generic instances of not-yet created dynamic types */
8161 return FALSE;
8162 if (MONO_CLASS_IMPLEMENTS_INTERFACE (oklass, klass->interface_id))
8163 return TRUE;
8165 if (klass->is_array_special_interface && oklass->rank == 1) {
8166 //XXX we could offset this by having the cast target computed at JIT time
8167 //XXX we could go even further and emit a wrapper that would do the extra type check
8168 MonoClass *iface_klass = mono_class_from_mono_type (mono_class_get_generic_class (klass)->context.class_inst->type_argv [0]);
8169 MonoClass *obj_klass = oklass->cast_class; //This gets us the cast class of element type of the array
8171 // If the target we're trying to cast to is a valuetype, we must account of weird valuetype equivalences such as IntEnum <> int or uint <> int
8172 // We can't apply it for ref types as this would go wrong with arrays - IList<byte[]> would have byte tested
8173 if (iface_klass->valuetype)
8174 iface_klass = iface_klass->cast_class;
8176 //array covariant casts only operates on scalar to scalar
8177 //This is so int[] can't be casted to IComparable<int>[]
8178 if (!(obj_klass->valuetype && !iface_klass->valuetype) && mono_class_is_assignable_from (iface_klass, obj_klass))
8179 return TRUE;
8182 if (mono_class_has_variant_generic_params (klass)) {
8183 int i;
8184 mono_class_setup_interfaces (oklass, &error);
8185 if (!mono_error_ok (&error)) {
8186 mono_error_cleanup (&error);
8187 return FALSE;
8190 /*klass is a generic variant interface, We need to extract from oklass a list of ifaces which are viable candidates.*/
8191 for (i = 0; i < oklass->interface_offsets_count; ++i) {
8192 MonoClass *iface = oklass->interfaces_packed [i];
8194 if (mono_class_is_variant_compatible (klass, iface, FALSE))
8195 return TRUE;
8198 return FALSE;
8199 } else if (klass->delegate) {
8200 if (mono_class_has_variant_generic_params (klass) && mono_class_is_variant_compatible (klass, oklass, FALSE))
8201 return TRUE;
8202 }else if (klass->rank) {
8203 MonoClass *eclass, *eoclass;
8205 if (oklass->rank != klass->rank)
8206 return FALSE;
8208 /* vectors vs. one dimensional arrays */
8209 if (oklass->byval_arg.type != klass->byval_arg.type)
8210 return FALSE;
8212 eclass = klass->cast_class;
8213 eoclass = oklass->cast_class;
8216 * a is b does not imply a[] is b[] when a is a valuetype, and
8217 * b is a reference type.
8220 if (eoclass->valuetype) {
8221 if ((eclass == mono_defaults.enum_class) ||
8222 (eclass == mono_defaults.enum_class->parent) ||
8223 (eclass == mono_defaults.object_class))
8224 return FALSE;
8227 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8228 } else if (mono_class_is_nullable (klass)) {
8229 if (mono_class_is_nullable (oklass))
8230 return mono_class_is_assignable_from (klass->cast_class, oklass->cast_class);
8231 else
8232 return mono_class_is_assignable_from (klass->cast_class, oklass);
8233 } else if (klass == mono_defaults.object_class)
8234 return TRUE;
8236 return mono_class_has_parent (oklass, klass);
8239 /*Check if @oklass is variant compatible with @klass.*/
8240 static gboolean
8241 mono_class_is_variant_compatible_slow (MonoClass *klass, MonoClass *oklass)
8243 int j;
8244 MonoType **klass_argv, **oklass_argv;
8245 MonoClass *klass_gtd = mono_class_get_generic_type_definition (klass);
8246 MonoGenericContainer *container = mono_class_get_generic_container (klass_gtd);
8248 /*Viable candidates are instances of the same generic interface*/
8249 if (mono_class_get_generic_type_definition (oklass) != klass_gtd || oklass == klass_gtd)
8250 return FALSE;
8252 klass_argv = &mono_class_get_generic_class (klass)->context.class_inst->type_argv [0];
8253 oklass_argv = &mono_class_get_generic_class (oklass)->context.class_inst->type_argv [0];
8255 for (j = 0; j < container->type_argc; ++j) {
8256 MonoClass *param1_class = mono_class_from_mono_type (klass_argv [j]);
8257 MonoClass *param2_class = mono_class_from_mono_type (oklass_argv [j]);
8259 if (param1_class->valuetype != param2_class->valuetype)
8260 return FALSE;
8263 * The _VARIANT and _COVARIANT constants should read _COVARIANT and
8264 * _CONTRAVARIANT, but they are in a public header so we can't fix it.
8266 if (param1_class != param2_class) {
8267 if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_VARIANT) {
8268 if (!mono_class_is_assignable_from_slow (param1_class, param2_class))
8269 return FALSE;
8270 } else if (mono_generic_container_get_param_info (container, j)->flags & MONO_GEN_PARAM_COVARIANT) {
8271 if (!mono_class_is_assignable_from_slow (param2_class, param1_class))
8272 return FALSE;
8273 } else
8274 return FALSE;
8277 return TRUE;
8279 /*Check if @candidate implements the interface @target*/
8280 static gboolean
8281 mono_class_implement_interface_slow (MonoClass *target, MonoClass *candidate)
8283 MonoError error;
8284 int i;
8285 gboolean is_variant = mono_class_has_variant_generic_params (target);
8287 if (is_variant && MONO_CLASS_IS_INTERFACE (candidate)) {
8288 if (mono_class_is_variant_compatible_slow (target, candidate))
8289 return TRUE;
8292 do {
8293 if (candidate == target)
8294 return TRUE;
8296 /*A TypeBuilder can have more interfaces on tb->interfaces than on candidate->interfaces*/
8297 if (image_is_dynamic (candidate->image) && !candidate->wastypebuilder) {
8298 MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info_raw (candidate); /* FIXME use handles */
8299 int j;
8300 if (tb && tb->interfaces) {
8301 for (j = mono_array_length (tb->interfaces) - 1; j >= 0; --j) {
8302 MonoReflectionType *iface = mono_array_get (tb->interfaces, MonoReflectionType*, j);
8303 MonoClass *iface_class;
8305 /* we can't realize the type here since it can do pretty much anything. */
8306 if (!iface->type)
8307 continue;
8308 iface_class = mono_class_from_mono_type (iface->type);
8309 if (iface_class == target)
8310 return TRUE;
8311 if (is_variant && mono_class_is_variant_compatible_slow (target, iface_class))
8312 return TRUE;
8313 if (mono_class_implement_interface_slow (target, iface_class))
8314 return TRUE;
8317 } else {
8318 /*setup_interfaces don't mono_class_init anything*/
8319 /*FIXME this doesn't handle primitive type arrays.
8320 ICollection<sbyte> x byte [] won't work because candidate->interfaces, for byte[], won't have IList<sbyte>.
8321 A possible way to fix this would be to move that to setup_interfaces from setup_interface_offsets.
8323 mono_class_setup_interfaces (candidate, &error);
8324 if (!mono_error_ok (&error)) {
8325 mono_error_cleanup (&error);
8326 return FALSE;
8329 for (i = 0; i < candidate->interface_count; ++i) {
8330 if (candidate->interfaces [i] == target)
8331 return TRUE;
8333 if (is_variant && mono_class_is_variant_compatible_slow (target, candidate->interfaces [i]))
8334 return TRUE;
8336 if (mono_class_implement_interface_slow (target, candidate->interfaces [i]))
8337 return TRUE;
8340 candidate = candidate->parent;
8341 } while (candidate);
8343 return FALSE;
8347 * Check if @oklass can be assigned to @klass.
8348 * This function does the same as mono_class_is_assignable_from but is safe to be used from mono_class_init context.
8350 gboolean
8351 mono_class_is_assignable_from_slow (MonoClass *target, MonoClass *candidate)
8353 if (candidate == target)
8354 return TRUE;
8355 if (target == mono_defaults.object_class)
8356 return TRUE;
8358 if (mono_class_has_parent (candidate, target))
8359 return TRUE;
8361 /*If target is not an interface there is no need to check them.*/
8362 if (MONO_CLASS_IS_INTERFACE (target))
8363 return mono_class_implement_interface_slow (target, candidate);
8365 if (target->delegate && mono_class_has_variant_generic_params (target))
8366 return mono_class_is_variant_compatible (target, candidate, FALSE);
8368 if (target->rank) {
8369 MonoClass *eclass, *eoclass;
8371 if (target->rank != candidate->rank)
8372 return FALSE;
8374 /* vectors vs. one dimensional arrays */
8375 if (target->byval_arg.type != candidate->byval_arg.type)
8376 return FALSE;
8378 eclass = target->cast_class;
8379 eoclass = candidate->cast_class;
8382 * a is b does not imply a[] is b[] when a is a valuetype, and
8383 * b is a reference type.
8386 if (eoclass->valuetype) {
8387 if ((eclass == mono_defaults.enum_class) ||
8388 (eclass == mono_defaults.enum_class->parent) ||
8389 (eclass == mono_defaults.object_class))
8390 return FALSE;
8393 return mono_class_is_assignable_from_slow (target->cast_class, candidate->cast_class);
8395 /*FIXME properly handle nullables */
8396 /*FIXME properly handle (M)VAR */
8397 return FALSE;
8401 * mono_class_get_cctor:
8402 * @klass: A MonoClass pointer
8404 * Returns: The static constructor of @klass if it exists, NULL otherwise.
8406 MonoMethod*
8407 mono_class_get_cctor (MonoClass *klass)
8409 MonoCachedClassInfo cached_info;
8411 if (image_is_dynamic (klass->image)) {
8413 * has_cctor is not set for these classes because mono_class_init () is
8414 * not run for them.
8416 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8419 mono_class_init (klass);
8421 if (!klass->has_cctor)
8422 return NULL;
8424 if (mono_class_is_ginst (klass) && !klass->methods)
8425 return mono_class_get_inflated_method (klass, mono_class_get_cctor (mono_class_get_generic_class (klass)->container_class));
8427 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8428 MonoError error;
8429 MonoMethod *result = mono_get_method_checked (klass->image, cached_info.cctor_token, klass, NULL, &error);
8430 if (!mono_error_ok (&error))
8431 g_error ("Could not lookup class cctor from cached metadata due to %s", mono_error_get_message (&error));
8432 return result;
8435 return mono_class_get_method_from_name_flags (klass, ".cctor", -1, METHOD_ATTRIBUTE_SPECIAL_NAME);
8439 * mono_class_get_finalizer:
8440 * @klass: The MonoClass pointer
8442 * Returns: The finalizer method of @klass if it exists, NULL otherwise.
8444 MonoMethod*
8445 mono_class_get_finalizer (MonoClass *klass)
8447 MonoCachedClassInfo cached_info;
8449 if (!klass->inited)
8450 mono_class_init (klass);
8451 if (!mono_class_has_finalizer (klass))
8452 return NULL;
8454 if (mono_class_get_cached_class_info (klass, &cached_info)) {
8455 MonoError error;
8456 MonoMethod *result = mono_get_method_checked (cached_info.finalize_image, cached_info.finalize_token, NULL, NULL, &error);
8457 if (!mono_error_ok (&error))
8458 g_error ("Could not lookup finalizer from cached metadata due to %s", mono_error_get_message (&error));
8459 return result;
8460 }else {
8461 mono_class_setup_vtable (klass);
8462 return klass->vtable [finalize_slot];
8467 * mono_class_needs_cctor_run:
8468 * @klass: the MonoClass pointer
8469 * @caller: a MonoMethod describing the caller
8471 * Determines whenever the class has a static constructor and whenever it
8472 * needs to be called when executing CALLER.
8474 gboolean
8475 mono_class_needs_cctor_run (MonoClass *klass, MonoMethod *caller)
8477 MonoMethod *method;
8479 method = mono_class_get_cctor (klass);
8480 if (method)
8481 return (method == caller) ? FALSE : TRUE;
8482 else
8483 return FALSE;
8487 * mono_class_array_element_size:
8488 * @klass:
8490 * Returns: The number of bytes an element of type @klass
8491 * uses when stored into an array.
8493 gint32
8494 mono_class_array_element_size (MonoClass *klass)
8496 MonoType *type = &klass->byval_arg;
8498 handle_enum:
8499 switch (type->type) {
8500 case MONO_TYPE_I1:
8501 case MONO_TYPE_U1:
8502 case MONO_TYPE_BOOLEAN:
8503 return 1;
8504 case MONO_TYPE_I2:
8505 case MONO_TYPE_U2:
8506 case MONO_TYPE_CHAR:
8507 return 2;
8508 case MONO_TYPE_I4:
8509 case MONO_TYPE_U4:
8510 case MONO_TYPE_R4:
8511 return 4;
8512 case MONO_TYPE_I:
8513 case MONO_TYPE_U:
8514 case MONO_TYPE_PTR:
8515 case MONO_TYPE_CLASS:
8516 case MONO_TYPE_STRING:
8517 case MONO_TYPE_OBJECT:
8518 case MONO_TYPE_SZARRAY:
8519 case MONO_TYPE_ARRAY:
8520 return sizeof (gpointer);
8521 case MONO_TYPE_I8:
8522 case MONO_TYPE_U8:
8523 case MONO_TYPE_R8:
8524 return 8;
8525 case MONO_TYPE_VALUETYPE:
8526 if (type->data.klass->enumtype) {
8527 type = mono_class_enum_basetype (type->data.klass);
8528 klass = klass->element_class;
8529 goto handle_enum;
8531 return mono_class_instance_size (klass) - sizeof (MonoObject);
8532 case MONO_TYPE_GENERICINST:
8533 type = &type->data.generic_class->container_class->byval_arg;
8534 goto handle_enum;
8535 case MONO_TYPE_VAR:
8536 case MONO_TYPE_MVAR: {
8537 int align;
8539 return mono_type_size (type, &align);
8541 case MONO_TYPE_VOID:
8542 return 0;
8544 default:
8545 g_error ("unknown type 0x%02x in mono_class_array_element_size", type->type);
8547 return -1;
8551 * mono_array_element_size:
8552 * @ac: pointer to a #MonoArrayClass
8554 * Returns: The size of single array element.
8556 gint32
8557 mono_array_element_size (MonoClass *ac)
8559 g_assert (ac->rank);
8560 return ac->sizes.element_size;
8563 gpointer
8564 mono_ldtoken (MonoImage *image, guint32 token, MonoClass **handle_class,
8565 MonoGenericContext *context)
8567 MonoError error;
8568 gpointer res = mono_ldtoken_checked (image, token, handle_class, context, &error);
8569 g_assert (mono_error_ok (&error));
8570 return res;
8573 gpointer
8574 mono_ldtoken_checked (MonoImage *image, guint32 token, MonoClass **handle_class,
8575 MonoGenericContext *context, MonoError *error)
8577 mono_error_init (error);
8579 if (image_is_dynamic (image)) {
8580 MonoClass *tmp_handle_class;
8581 gpointer obj = mono_lookup_dynamic_token_class (image, token, TRUE, &tmp_handle_class, context, error);
8583 mono_error_assert_ok (error);
8584 g_assert (tmp_handle_class);
8585 if (handle_class)
8586 *handle_class = tmp_handle_class;
8588 if (tmp_handle_class == mono_defaults.typehandle_class)
8589 return &((MonoClass*)obj)->byval_arg;
8590 else
8591 return obj;
8594 switch (token & 0xff000000) {
8595 case MONO_TOKEN_TYPE_DEF:
8596 case MONO_TOKEN_TYPE_REF:
8597 case MONO_TOKEN_TYPE_SPEC: {
8598 MonoType *type;
8599 if (handle_class)
8600 *handle_class = mono_defaults.typehandle_class;
8601 type = mono_type_get_checked (image, token, context, error);
8602 if (!type)
8603 return NULL;
8605 mono_class_init (mono_class_from_mono_type (type));
8606 /* We return a MonoType* as handle */
8607 return type;
8609 case MONO_TOKEN_FIELD_DEF: {
8610 MonoClass *klass;
8611 guint32 type = mono_metadata_typedef_from_field (image, mono_metadata_token_index (token));
8612 if (!type) {
8613 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8614 return NULL;
8616 if (handle_class)
8617 *handle_class = mono_defaults.fieldhandle_class;
8618 klass = mono_class_get_and_inflate_typespec_checked (image, MONO_TOKEN_TYPE_DEF | type, context, error);
8619 if (!klass)
8620 return NULL;
8622 mono_class_init (klass);
8623 return mono_class_get_field (klass, token);
8625 case MONO_TOKEN_METHOD_DEF:
8626 case MONO_TOKEN_METHOD_SPEC: {
8627 MonoMethod *meth;
8628 meth = mono_get_method_checked (image, token, NULL, context, error);
8629 if (handle_class)
8630 *handle_class = mono_defaults.methodhandle_class;
8631 if (!meth)
8632 return NULL;
8634 return meth;
8636 case MONO_TOKEN_MEMBER_REF: {
8637 guint32 cols [MONO_MEMBERREF_SIZE];
8638 const char *sig;
8639 mono_metadata_decode_row (&image->tables [MONO_TABLE_MEMBERREF], mono_metadata_token_index (token) - 1, cols, MONO_MEMBERREF_SIZE);
8640 sig = mono_metadata_blob_heap (image, cols [MONO_MEMBERREF_SIGNATURE]);
8641 mono_metadata_decode_blob_size (sig, &sig);
8642 if (*sig == 0x6) { /* it's a field */
8643 MonoClass *klass;
8644 MonoClassField *field;
8645 field = mono_field_from_token_checked (image, token, &klass, context, error);
8646 if (handle_class)
8647 *handle_class = mono_defaults.fieldhandle_class;
8648 return field;
8649 } else {
8650 MonoMethod *meth;
8651 meth = mono_get_method_checked (image, token, NULL, context, error);
8652 if (handle_class)
8653 *handle_class = mono_defaults.methodhandle_class;
8654 return meth;
8657 default:
8658 mono_error_set_bad_image (error, image, "Bad ldtoken %x", token);
8660 return NULL;
8663 gpointer
8664 mono_lookup_dynamic_token (MonoImage *image, guint32 token, MonoGenericContext *context, MonoError *error)
8666 MonoClass *handle_class;
8667 mono_error_init (error);
8668 return mono_reflection_lookup_dynamic_token (image, token, TRUE, &handle_class, context, error);
8671 gpointer
8672 mono_lookup_dynamic_token_class (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
8674 return mono_reflection_lookup_dynamic_token (image, token, valid_token, handle_class, context, error);
8677 static MonoGetCachedClassInfo get_cached_class_info = NULL;
8679 void
8680 mono_install_get_cached_class_info (MonoGetCachedClassInfo func)
8682 get_cached_class_info = func;
8685 static gboolean
8686 mono_class_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
8688 if (!get_cached_class_info)
8689 return FALSE;
8690 else
8691 return get_cached_class_info (klass, res);
8694 void
8695 mono_install_get_class_from_name (MonoGetClassFromName func)
8697 get_class_from_name = func;
8701 * mono_class_get_image:
8703 * Use this method to get the `MonoImage*` where this class came from.
8705 * Returns: The image where this class is defined.
8707 MonoImage*
8708 mono_class_get_image (MonoClass *klass)
8710 return klass->image;
8714 * mono_class_get_element_class:
8715 * @klass: the MonoClass to act on
8717 * Use this function to get the element class of an array.
8719 * Returns: The element class of an array.
8721 MonoClass*
8722 mono_class_get_element_class (MonoClass *klass)
8724 return klass->element_class;
8728 * mono_class_is_valuetype:
8729 * @klass: the MonoClass to act on
8731 * Use this method to determine if the provided `MonoClass*` represents a value type,
8732 * or a reference type.
8734 * Returns: TRUE if the MonoClass represents a ValueType, FALSE if it represents a reference type.
8736 gboolean
8737 mono_class_is_valuetype (MonoClass *klass)
8739 return klass->valuetype;
8743 * mono_class_is_enum:
8744 * @klass: the MonoClass to act on
8746 * Use this function to determine if the provided `MonoClass*` represents an enumeration.
8748 * Returns: TRUE if the MonoClass represents an enumeration.
8750 gboolean
8751 mono_class_is_enum (MonoClass *klass)
8753 return klass->enumtype;
8757 * mono_class_enum_basetype:
8758 * @klass: the MonoClass to act on
8760 * Use this function to get the underlying type for an enumeration value.
8762 * Returns: The underlying type representation for an enumeration.
8764 MonoType*
8765 mono_class_enum_basetype (MonoClass *klass)
8767 if (klass->element_class == klass)
8768 /* SRE or broken types */
8769 return NULL;
8770 else
8771 return &klass->element_class->byval_arg;
8775 * mono_class_get_parent
8776 * @klass: the MonoClass to act on
8778 * Returns: The parent class for this class.
8780 MonoClass*
8781 mono_class_get_parent (MonoClass *klass)
8783 return klass->parent;
8787 * mono_class_get_nesting_type:
8788 * @klass: the MonoClass to act on
8790 * Use this function to obtain the class that the provided `MonoClass*` is nested on.
8792 * If the return is NULL, this indicates that this class is not nested.
8794 * Returns: The container type where this type is nested or NULL if this type is not a nested type.
8796 MonoClass*
8797 mono_class_get_nesting_type (MonoClass *klass)
8799 return klass->nested_in;
8803 * mono_class_get_rank:
8804 * @klass: the MonoClass to act on
8806 * Returns: The rank for the array (the number of dimensions).
8809 mono_class_get_rank (MonoClass *klass)
8811 return klass->rank;
8815 * mono_class_get_name
8816 * @klass: the MonoClass to act on
8818 * Returns: The name of the class.
8820 const char*
8821 mono_class_get_name (MonoClass *klass)
8823 return klass->name;
8827 * mono_class_get_namespace:
8828 * @klass: the MonoClass to act on
8830 * Returns: The namespace of the class.
8832 const char*
8833 mono_class_get_namespace (MonoClass *klass)
8835 return klass->name_space;
8839 * mono_class_get_type:
8840 * @klass: the MonoClass to act on
8842 * This method returns the internal Type representation for the class.
8844 * Returns: The MonoType from the class.
8846 MonoType*
8847 mono_class_get_type (MonoClass *klass)
8849 return &klass->byval_arg;
8853 * mono_class_get_type_token:
8854 * @klass: the MonoClass to act on
8856 * This method returns type token for the class.
8858 * Returns: The type token for the class.
8860 guint32
8861 mono_class_get_type_token (MonoClass *klass)
8863 return klass->type_token;
8867 * mono_class_get_byref_type:
8868 * @klass: the MonoClass to act on
8872 MonoType*
8873 mono_class_get_byref_type (MonoClass *klass)
8875 return &klass->this_arg;
8879 * mono_class_num_fields:
8880 * @klass: the MonoClass to act on
8882 * Returns: The number of static and instance fields in the class.
8885 mono_class_num_fields (MonoClass *klass)
8887 return mono_class_get_field_count (klass);
8891 * mono_class_num_methods:
8892 * @klass: the MonoClass to act on
8894 * Returns: The number of methods in the class.
8897 mono_class_num_methods (MonoClass *klass)
8899 return mono_class_get_method_count (klass);
8903 * mono_class_num_properties
8904 * @klass: the MonoClass to act on
8906 * Returns: The number of properties in the class.
8909 mono_class_num_properties (MonoClass *klass)
8911 mono_class_setup_properties (klass);
8913 return mono_class_get_property_info (klass)->count;
8917 * mono_class_num_events:
8918 * @klass: the MonoClass to act on
8920 * Returns: The number of events in the class.
8923 mono_class_num_events (MonoClass *klass)
8925 mono_class_setup_events (klass);
8927 return mono_class_get_event_info (klass)->count;
8931 * mono_class_get_fields:
8932 * @klass: the MonoClass to act on
8934 * This routine is an iterator routine for retrieving the fields in a class.
8936 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8937 * iterate over all of the elements. When no more values are
8938 * available, the return value is NULL.
8940 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
8942 MonoClassField*
8943 mono_class_get_fields (MonoClass* klass, gpointer *iter)
8945 MonoClassField* field;
8946 if (!iter)
8947 return NULL;
8948 if (!*iter) {
8949 mono_class_setup_fields (klass);
8950 if (mono_class_has_failure (klass))
8951 return NULL;
8952 /* start from the first */
8953 if (mono_class_get_field_count (klass)) {
8954 *iter = &klass->fields [0];
8955 return &klass->fields [0];
8956 } else {
8957 /* no fields */
8958 return NULL;
8961 field = (MonoClassField *)*iter;
8962 field++;
8963 if (field < &klass->fields [mono_class_get_field_count (klass)]) {
8964 *iter = field;
8965 return field;
8967 return NULL;
8971 * mono_class_get_methods
8972 * @klass: the MonoClass to act on
8974 * This routine is an iterator routine for retrieving the fields in a class.
8976 * You must pass a gpointer that points to zero and is treated as an opaque handle to
8977 * iterate over all of the elements. When no more values are
8978 * available, the return value is NULL.
8980 * Returns: a MonoMethod on each iteration or NULL when no more methods are available.
8982 MonoMethod*
8983 mono_class_get_methods (MonoClass* klass, gpointer *iter)
8985 MonoMethod** method;
8986 if (!iter)
8987 return NULL;
8988 if (!*iter) {
8989 mono_class_setup_methods (klass);
8992 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
8993 * FIXME we should better report this error to the caller
8995 if (!klass->methods)
8996 return NULL;
8997 /* start from the first */
8998 if (mono_class_get_method_count (klass)) {
8999 *iter = &klass->methods [0];
9000 return klass->methods [0];
9001 } else {
9002 /* no method */
9003 return NULL;
9006 method = (MonoMethod **)*iter;
9007 method++;
9008 if (method < &klass->methods [mono_class_get_method_count (klass)]) {
9009 *iter = method;
9010 return *method;
9012 return NULL;
9016 * mono_class_get_virtual_methods:
9018 * Iterate over the virtual methods of KLASS.
9020 * LOCKING: Assumes the loader lock is held (because of the klass->methods check).
9022 static MonoMethod*
9023 mono_class_get_virtual_methods (MonoClass* klass, gpointer *iter)
9025 MonoMethod** method;
9026 if (!iter)
9027 return NULL;
9028 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9029 if (!*iter) {
9030 mono_class_setup_methods (klass);
9032 * We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9033 * FIXME we should better report this error to the caller
9035 if (!klass->methods)
9036 return NULL;
9037 /* start from the first */
9038 method = &klass->methods [0];
9039 } else {
9040 method = (MonoMethod **)*iter;
9041 method++;
9043 int mcount = mono_class_get_method_count (klass);
9044 while (method < &klass->methods [mcount]) {
9045 if (*method && ((*method)->flags & METHOD_ATTRIBUTE_VIRTUAL))
9046 break;
9047 method ++;
9049 if (method < &klass->methods [mcount]) {
9050 *iter = method;
9051 return *method;
9052 } else {
9053 return NULL;
9055 } else {
9056 /* Search directly in metadata to avoid calling setup_methods () */
9057 MonoMethod *res = NULL;
9058 int i, start_index;
9060 if (!*iter) {
9061 start_index = 0;
9062 } else {
9063 start_index = GPOINTER_TO_UINT (*iter);
9066 int first_idx = mono_class_get_first_method_idx (klass);
9067 int mcount = mono_class_get_method_count (klass);
9068 for (i = start_index; i < mcount; ++i) {
9069 guint32 flags;
9071 /* first_idx points into the methodptr table */
9072 flags = mono_metadata_decode_table_row_col (klass->image, MONO_TABLE_METHOD, first_idx + i, MONO_METHOD_FLAGS);
9074 if (flags & METHOD_ATTRIBUTE_VIRTUAL)
9075 break;
9078 if (i < mcount) {
9079 MonoError error;
9080 res = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
9081 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9083 /* Add 1 here so the if (*iter) check fails */
9084 *iter = GUINT_TO_POINTER (i + 1);
9085 return res;
9086 } else {
9087 return NULL;
9093 * mono_class_get_properties:
9094 * @klass: the MonoClass to act on
9096 * This routine is an iterator routine for retrieving the properties in a class.
9098 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9099 * iterate over all of the elements. When no more values are
9100 * available, the return value is NULL.
9102 * Returns: a @MonoProperty* on each invocation, or NULL when no more are available.
9104 MonoProperty*
9105 mono_class_get_properties (MonoClass* klass, gpointer *iter)
9107 MonoProperty* property;
9108 if (!iter)
9109 return NULL;
9110 if (!*iter) {
9111 mono_class_setup_properties (klass);
9112 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
9113 /* start from the first */
9114 if (info->count) {
9115 *iter = &info->properties [0];
9116 return (MonoProperty *)*iter;
9117 } else {
9118 /* no fields */
9119 return NULL;
9122 property = (MonoProperty *)*iter;
9123 property++;
9124 MonoClassPropertyInfo *info = mono_class_get_property_info (klass);
9125 if (property < &info->properties [info->count]) {
9126 *iter = property;
9127 return (MonoProperty *)*iter;
9129 return NULL;
9133 * mono_class_get_events:
9134 * @klass: the MonoClass to act on
9136 * This routine is an iterator routine for retrieving the properties in a class.
9138 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9139 * iterate over all of the elements. When no more values are
9140 * available, the return value is NULL.
9142 * Returns: a @MonoEvent* on each invocation, or NULL when no more are available.
9144 MonoEvent*
9145 mono_class_get_events (MonoClass* klass, gpointer *iter)
9147 MonoEvent* event;
9148 if (!iter)
9149 return NULL;
9150 if (!*iter) {
9151 mono_class_setup_events (klass);
9152 MonoClassEventInfo *info = mono_class_get_event_info (klass);
9153 /* start from the first */
9154 if (info->count) {
9155 *iter = &info->events [0];
9156 return (MonoEvent *)*iter;
9157 } else {
9158 /* no fields */
9159 return NULL;
9162 event = (MonoEvent *)*iter;
9163 event++;
9164 MonoClassEventInfo *info = mono_class_get_event_info (klass);
9165 if (event < &info->events [info->count]) {
9166 *iter = event;
9167 return (MonoEvent *)*iter;
9169 return NULL;
9173 * mono_class_get_interfaces
9174 * @klass: the MonoClass to act on
9176 * This routine is an iterator routine for retrieving the interfaces implemented by this class.
9178 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9179 * iterate over all of the elements. When no more values are
9180 * available, the return value is NULL.
9182 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9184 MonoClass*
9185 mono_class_get_interfaces (MonoClass* klass, gpointer *iter)
9187 MonoError error;
9188 MonoClass** iface;
9189 if (!iter)
9190 return NULL;
9191 if (!*iter) {
9192 if (!klass->inited)
9193 mono_class_init (klass);
9194 if (!klass->interfaces_inited) {
9195 mono_class_setup_interfaces (klass, &error);
9196 if (!mono_error_ok (&error)) {
9197 mono_error_cleanup (&error);
9198 return NULL;
9201 /* start from the first */
9202 if (klass->interface_count) {
9203 *iter = &klass->interfaces [0];
9204 return klass->interfaces [0];
9205 } else {
9206 /* no interface */
9207 return NULL;
9210 iface = (MonoClass **)*iter;
9211 iface++;
9212 if (iface < &klass->interfaces [klass->interface_count]) {
9213 *iter = iface;
9214 return *iface;
9216 return NULL;
9219 static void
9220 setup_nested_types (MonoClass *klass)
9222 MonoError error;
9223 GList *classes, *nested_classes, *l;
9224 int i;
9226 if (klass->nested_classes_inited)
9227 return;
9229 if (!klass->type_token) {
9230 mono_loader_lock ();
9231 klass->nested_classes_inited = TRUE;
9232 mono_loader_unlock ();
9233 return;
9236 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, 1);
9237 classes = NULL;
9238 while (i) {
9239 MonoClass* nclass;
9240 guint32 cols [MONO_NESTED_CLASS_SIZE];
9241 mono_metadata_decode_row (&klass->image->tables [MONO_TABLE_NESTEDCLASS], i - 1, cols, MONO_NESTED_CLASS_SIZE);
9242 nclass = mono_class_create_from_typedef (klass->image, MONO_TOKEN_TYPE_DEF | cols [MONO_NESTED_CLASS_NESTED], &error);
9243 if (!mono_error_ok (&error)) {
9244 /*FIXME don't swallow the error message*/
9245 mono_error_cleanup (&error);
9247 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9248 continue;
9251 classes = g_list_prepend (classes, nclass);
9253 i = mono_metadata_nesting_typedef (klass->image, klass->type_token, i + 1);
9256 nested_classes = NULL;
9257 for (l = classes; l; l = l->next)
9258 nested_classes = g_list_prepend_image (klass->image, nested_classes, l->data);
9259 g_list_free (classes);
9261 mono_loader_lock ();
9262 if (!klass->nested_classes_inited) {
9263 mono_class_set_nested_classes_property (klass, nested_classes);
9264 mono_memory_barrier ();
9265 klass->nested_classes_inited = TRUE;
9267 mono_loader_unlock ();
9271 * mono_class_get_nested_types
9272 * @klass: the MonoClass to act on
9274 * This routine is an iterator routine for retrieving the nested types of a class.
9275 * This works only if @klass is non-generic, or a generic type definition.
9277 * You must pass a gpointer that points to zero and is treated as an opaque handle to
9278 * iterate over all of the elements. When no more values are
9279 * available, the return value is NULL.
9281 * Returns: a @Monoclass* on each invocation, or NULL when no more are available.
9283 MonoClass*
9284 mono_class_get_nested_types (MonoClass* klass, gpointer *iter)
9286 GList *item;
9288 if (!iter)
9289 return NULL;
9290 if (!klass->nested_classes_inited)
9291 setup_nested_types (klass);
9293 if (!*iter) {
9294 GList *nested_classes = mono_class_get_nested_classes_property (klass);
9295 /* start from the first */
9296 if (nested_classes) {
9297 *iter = nested_classes;
9298 return (MonoClass *)nested_classes->data;
9299 } else {
9300 /* no nested types */
9301 return NULL;
9304 item = (GList *)*iter;
9305 item = item->next;
9306 if (item) {
9307 *iter = item;
9308 return (MonoClass *)item->data;
9310 return NULL;
9315 * mono_class_is_delegate
9316 * @klass: the MonoClass to act on
9318 * Returns: TRUE if the MonoClass represents a System.Delegate.
9320 mono_bool
9321 mono_class_is_delegate (MonoClass *klass)
9323 return klass->delegate;
9327 * mono_class_implements_interface
9328 * @klass: The MonoClass to act on
9329 * @interface: The interface to check if @klass implements.
9331 * Returns: TRUE if @klass implements @interface.
9333 mono_bool
9334 mono_class_implements_interface (MonoClass* klass, MonoClass* iface)
9336 return mono_class_is_assignable_from (iface, klass);
9340 * mono_field_get_name:
9341 * @field: the MonoClassField to act on
9343 * Returns: The name of the field.
9345 const char*
9346 mono_field_get_name (MonoClassField *field)
9348 return field->name;
9352 * mono_field_get_type:
9353 * @field: the MonoClassField to act on
9355 * Returns: MonoType of the field.
9357 MonoType*
9358 mono_field_get_type (MonoClassField *field)
9360 MonoError error;
9361 MonoType *type = mono_field_get_type_checked (field, &error);
9362 if (!mono_error_ok (&error)) {
9363 mono_trace_warning (MONO_TRACE_TYPE, "Could not load field's type due to %s", mono_error_get_message (&error));
9364 mono_error_cleanup (&error);
9366 return type;
9371 * mono_field_get_type_checked:
9372 * @field: the MonoClassField to act on
9373 * @error: used to return any erro found while retrieving @field type
9375 * Returns: MonoType of the field.
9377 MonoType*
9378 mono_field_get_type_checked (MonoClassField *field, MonoError *error)
9380 mono_error_init (error);
9381 if (!field->type)
9382 mono_field_resolve_type (field, error);
9383 return field->type;
9387 * mono_field_get_parent:
9388 * @field: the MonoClassField to act on
9390 * Returns: MonoClass where the field was defined.
9392 MonoClass*
9393 mono_field_get_parent (MonoClassField *field)
9395 return field->parent;
9399 * mono_field_get_flags;
9400 * @field: the MonoClassField to act on
9402 * The metadata flags for a field are encoded using the
9403 * FIELD_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9405 * Returns: The flags for the field.
9407 guint32
9408 mono_field_get_flags (MonoClassField *field)
9410 if (!field->type)
9411 return mono_field_resolve_flags (field);
9412 return field->type->attrs;
9416 * mono_field_get_offset:
9417 * @field: the MonoClassField to act on
9419 * Returns: The field offset.
9421 guint32
9422 mono_field_get_offset (MonoClassField *field)
9424 return field->offset;
9427 static const char *
9428 mono_field_get_rva (MonoClassField *field)
9430 guint32 rva;
9431 int field_index;
9432 MonoClass *klass = field->parent;
9433 MonoFieldDefaultValue *def_values;
9435 g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);
9437 def_values = mono_class_get_field_def_values (klass);
9438 if (!def_values) {
9439 def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));
9441 mono_class_set_field_def_values (klass, def_values);
9444 field_index = mono_field_get_index (field);
9446 if (!def_values [field_index].data && !image_is_dynamic (klass->image)) {
9447 int first_field_idx = mono_class_get_first_field_idx (klass);
9448 mono_metadata_field_info (field->parent->image, first_field_idx + field_index, NULL, &rva, NULL);
9449 if (!rva)
9450 g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), field->parent->name);
9451 def_values [field_index].data = mono_image_rva_map (field->parent->image, rva);
9454 return def_values [field_index].data;
9458 * mono_field_get_data:
9459 * @field: the MonoClassField to act on
9461 * Returns: A pointer to the metadata constant value or to the field
9462 * data if it has an RVA flag.
9464 const char *
9465 mono_field_get_data (MonoClassField *field)
9467 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT) {
9468 MonoTypeEnum def_type;
9470 return mono_class_get_field_default_value (field, &def_type);
9471 } else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
9472 return mono_field_get_rva (field);
9473 } else {
9474 return NULL;
9479 * mono_property_get_name:
9480 * @prop: the MonoProperty to act on
9482 * Returns: The name of the property
9484 const char*
9485 mono_property_get_name (MonoProperty *prop)
9487 return prop->name;
9491 * mono_property_get_set_method
9492 * @prop: the MonoProperty to act on.
9494 * Returns: The setter method of the property (A MonoMethod)
9496 MonoMethod*
9497 mono_property_get_set_method (MonoProperty *prop)
9499 return prop->set;
9503 * mono_property_get_get_method
9504 * @prop: the MonoProperty to act on.
9506 * Returns: The setter method of the property (A MonoMethod)
9508 MonoMethod*
9509 mono_property_get_get_method (MonoProperty *prop)
9511 return prop->get;
9515 * mono_property_get_parent:
9516 * @prop: the MonoProperty to act on.
9518 * Returns: The MonoClass where the property was defined.
9520 MonoClass*
9521 mono_property_get_parent (MonoProperty *prop)
9523 return prop->parent;
9527 * mono_property_get_flags:
9528 * @prop: the MonoProperty to act on.
9530 * The metadata flags for a property are encoded using the
9531 * PROPERTY_ATTRIBUTE_* constants. See the tabledefs.h file for details.
9533 * Returns: The flags for the property.
9535 guint32
9536 mono_property_get_flags (MonoProperty *prop)
9538 return prop->attrs;
9542 * mono_event_get_name:
9543 * @event: the MonoEvent to act on
9545 * Returns: The name of the event.
9547 const char*
9548 mono_event_get_name (MonoEvent *event)
9550 return event->name;
9554 * mono_event_get_add_method:
9555 * @event: The MonoEvent to act on.
9557 * Returns: The @add' method for the event (a MonoMethod).
9559 MonoMethod*
9560 mono_event_get_add_method (MonoEvent *event)
9562 return event->add;
9566 * mono_event_get_remove_method:
9567 * @event: The MonoEvent to act on.
9569 * Returns: The @remove method for the event (a MonoMethod).
9571 MonoMethod*
9572 mono_event_get_remove_method (MonoEvent *event)
9574 return event->remove;
9578 * mono_event_get_raise_method:
9579 * @event: The MonoEvent to act on.
9581 * Returns: The @raise method for the event (a MonoMethod).
9583 MonoMethod*
9584 mono_event_get_raise_method (MonoEvent *event)
9586 return event->raise;
9590 * mono_event_get_parent:
9591 * @event: the MonoEvent to act on.
9593 * Returns: The MonoClass where the event is defined.
9595 MonoClass*
9596 mono_event_get_parent (MonoEvent *event)
9598 return event->parent;
9602 * mono_event_get_flags
9603 * @event: the MonoEvent to act on.
9605 * The metadata flags for an event are encoded using the
9606 * EVENT_* constants. See the tabledefs.h file for details.
9608 * Returns: The flags for the event.
9610 guint32
9611 mono_event_get_flags (MonoEvent *event)
9613 return event->attrs;
9617 * mono_class_get_method_from_name:
9618 * @klass: where to look for the method
9619 * @name: name of the method
9620 * @param_count: number of parameters. -1 for any number.
9622 * Obtains a MonoMethod with a given name and number of parameters.
9623 * It only works if there are no multiple signatures for any given method name.
9625 MonoMethod *
9626 mono_class_get_method_from_name (MonoClass *klass, const char *name, int param_count)
9628 return mono_class_get_method_from_name_flags (klass, name, param_count, 0);
9631 static MonoMethod*
9632 find_method_in_metadata (MonoClass *klass, const char *name, int param_count, int flags)
9634 MonoMethod *res = NULL;
9635 int i;
9637 /* Search directly in the metadata to avoid calling setup_methods () */
9638 int first_idx = mono_class_get_first_method_idx (klass);
9639 int mcount = mono_class_get_method_count (klass);
9640 for (i = 0; i < mcount; ++i) {
9641 MonoError error;
9642 guint32 cols [MONO_METHOD_SIZE];
9643 MonoMethod *method;
9644 MonoMethodSignature *sig;
9646 /* first_idx points into the methodptr table */
9647 mono_metadata_decode_table_row (klass->image, MONO_TABLE_METHOD, first_idx + i, cols, MONO_METHOD_SIZE);
9649 if (!strcmp (mono_metadata_string_heap (klass->image, cols [MONO_METHOD_NAME]), name)) {
9650 method = mono_get_method_checked (klass->image, MONO_TOKEN_METHOD_DEF | (first_idx + i + 1), klass, NULL, &error);
9651 if (!method) {
9652 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9653 continue;
9655 if (param_count == -1) {
9656 res = method;
9657 break;
9659 sig = mono_method_signature_checked (method, &error);
9660 if (!sig) {
9661 mono_error_cleanup (&error); /* FIXME don't swallow the error */
9662 continue;
9664 if (sig->param_count == param_count) {
9665 res = method;
9666 break;
9671 return res;
9675 * mono_class_get_method_from_name_flags:
9676 * @klass: where to look for the method
9677 * @name_space: name of the method
9678 * @param_count: number of parameters. -1 for any number.
9679 * @flags: flags which must be set in the method
9681 * Obtains a MonoMethod with a given name and number of parameters.
9682 * It only works if there are no multiple signatures for any given method name.
9684 MonoMethod *
9685 mono_class_get_method_from_name_flags (MonoClass *klass, const char *name, int param_count, int flags)
9687 MonoMethod *res = NULL;
9688 int i;
9690 mono_class_init (klass);
9692 if (mono_class_is_ginst (klass) && !klass->methods) {
9693 res = mono_class_get_method_from_name_flags (mono_class_get_generic_class (klass)->container_class, name, param_count, flags);
9694 if (res) {
9695 MonoError error;
9696 res = mono_class_inflate_generic_method_full_checked (res, klass, mono_class_get_context (klass), &error);
9697 if (!mono_error_ok (&error))
9698 mono_error_cleanup (&error); /*FIXME don't swallow the error */
9700 return res;
9703 if (klass->methods || !MONO_CLASS_HAS_STATIC_METADATA (klass)) {
9704 mono_class_setup_methods (klass);
9706 We can't fail lookup of methods otherwise the runtime will burst in flames on all sort of places.
9707 See mono/tests/array_load_exception.il
9708 FIXME we should better report this error to the caller
9710 if (!klass->methods)
9711 return NULL;
9712 int mcount = mono_class_get_method_count (klass);
9713 for (i = 0; i < mcount; ++i) {
9714 MonoMethod *method = klass->methods [i];
9716 if (method->name[0] == name [0] &&
9717 !strcmp (name, method->name) &&
9718 (param_count == -1 || mono_method_signature (method)->param_count == param_count) &&
9719 ((method->flags & flags) == flags)) {
9720 res = method;
9721 break;
9725 else {
9726 res = find_method_in_metadata (klass, name, param_count, flags);
9729 return res;
9733 * mono_class_set_failure:
9734 * @klass: class in which the failure was detected
9735 * @ex_type: the kind of exception/error to be thrown (later)
9736 * @ex_data: exception data (specific to each type of exception/error)
9738 * Keep a detected failure informations in the class for later processing.
9739 * Note that only the first failure is kept.
9741 * LOCKING: Acquires the loader lock.
9743 static gboolean
9744 mono_class_set_failure (MonoClass *klass, MonoErrorBoxed *boxed_error)
9746 g_assert (boxed_error != NULL);
9748 if (mono_class_has_failure (klass))
9749 return FALSE;
9751 mono_loader_lock ();
9752 klass->has_failure = 1;
9753 mono_class_set_exception_data (klass, boxed_error);
9754 mono_loader_unlock ();
9756 return TRUE;
9759 gboolean
9760 mono_class_has_failure (const MonoClass *klass)
9762 g_assert (klass != NULL);
9763 return klass->has_failure != 0;
9768 * mono_class_set_type_load_failure:
9769 * @klass: class in which the failure was detected
9770 * @fmt: Printf-style error message string.
9772 * Collect detected failure informaion in the class for later processing.
9773 * The error is stored as a MonoErrorBoxed as with mono_error_set_type_load_class ()
9774 * Note that only the first failure is kept.
9776 * Returns FALSE if a failure was already set on the class, or TRUE otherwise.
9778 * LOCKING: Acquires the loader lock.
9780 gboolean
9781 mono_class_set_type_load_failure (MonoClass *klass, const char * fmt, ...)
9783 MonoError prepare_error;
9784 va_list args;
9786 if (mono_class_has_failure (klass))
9787 return FALSE;
9789 mono_error_init (&prepare_error);
9791 va_start (args, fmt);
9792 mono_error_vset_type_load_class (&prepare_error, klass, fmt, args);
9793 va_end (args);
9795 MonoErrorBoxed *box = mono_error_box (&prepare_error, klass->image);
9796 mono_error_cleanup (&prepare_error);
9797 return mono_class_set_failure (klass, box);
9801 * mono_classes_init:
9803 * Initialize the resources used by this module.
9805 void
9806 mono_classes_init (void)
9808 mono_os_mutex_init (&classes_mutex);
9810 mono_native_tls_alloc (&setup_fields_tls_id, NULL);
9811 mono_native_tls_alloc (&init_pending_tls_id, NULL);
9813 mono_counters_register ("MonoClassDef count",
9814 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_def_count);
9815 mono_counters_register ("MonoClassGtd count",
9816 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gtd_count);
9817 mono_counters_register ("MonoClassGenericInst count",
9818 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_ginst_count);
9819 mono_counters_register ("MonoClassGenericParam count",
9820 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_gparam_count);
9821 mono_counters_register ("MonoClassArray count",
9822 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_array_count);
9823 mono_counters_register ("MonoClassPointer count",
9824 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_pointer_count);
9825 mono_counters_register ("Inflated methods size",
9826 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_methods_size);
9827 mono_counters_register ("Inflated classes size",
9828 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &inflated_classes_size);
9829 mono_counters_register ("MonoClass size",
9830 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &classes_size);
9834 * mono_classes_cleanup:
9836 * Free the resources used by this module.
9838 void
9839 mono_classes_cleanup (void)
9841 mono_native_tls_free (setup_fields_tls_id);
9842 mono_native_tls_free (init_pending_tls_id);
9844 if (global_interface_bitset)
9845 mono_bitset_free (global_interface_bitset);
9846 global_interface_bitset = NULL;
9847 mono_os_mutex_destroy (&classes_mutex);
9851 * mono_class_get_exception_for_failure:
9852 * @klass: class in which the failure was detected
9854 * Return a constructed MonoException than the caller can then throw
9855 * using mono_raise_exception - or NULL if no failure is present (or
9856 * doesn't result in an exception).
9858 MonoException*
9859 mono_class_get_exception_for_failure (MonoClass *klass)
9861 if (!mono_class_has_failure (klass))
9862 return NULL;
9863 MonoError unboxed_error;
9864 mono_error_init (&unboxed_error);
9865 mono_error_set_for_class_failure (&unboxed_error, klass);
9866 return mono_error_convert_to_exception (&unboxed_error);
9869 static gboolean
9870 is_nesting_type (MonoClass *outer_klass, MonoClass *inner_klass)
9872 outer_klass = mono_class_get_generic_type_definition (outer_klass);
9873 inner_klass = mono_class_get_generic_type_definition (inner_klass);
9874 do {
9875 if (outer_klass == inner_klass)
9876 return TRUE;
9877 inner_klass = inner_klass->nested_in;
9878 } while (inner_klass);
9879 return FALSE;
9882 MonoClass *
9883 mono_class_get_generic_type_definition (MonoClass *klass)
9885 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
9886 return gklass ? gklass->container_class : klass;
9890 * Check if @klass is a subtype of @parent ignoring generic instantiations.
9892 * Generic instantiations are ignored for all super types of @klass.
9894 * Visibility checks ignoring generic instantiations.
9896 gboolean
9897 mono_class_has_parent_and_ignore_generics (MonoClass *klass, MonoClass *parent)
9899 int i;
9900 klass = mono_class_get_generic_type_definition (klass);
9901 parent = mono_class_get_generic_type_definition (parent);
9902 mono_class_setup_supertypes (klass);
9904 for (i = 0; i < klass->idepth; ++i) {
9905 if (parent == mono_class_get_generic_type_definition (klass->supertypes [i]))
9906 return TRUE;
9908 return FALSE;
9911 * Subtype can only access parent members with family protection if the site object
9912 * is subclass of Subtype. For example:
9913 * class A { protected int x; }
9914 * class B : A {
9915 * void valid_access () {
9916 * B b;
9917 * b.x = 0;
9919 * void invalid_access () {
9920 * A a;
9921 * a.x = 0;
9924 * */
9925 static gboolean
9926 is_valid_family_access (MonoClass *access_klass, MonoClass *member_klass, MonoClass *context_klass)
9928 if (!mono_class_has_parent_and_ignore_generics (access_klass, member_klass))
9929 return FALSE;
9931 if (context_klass == NULL)
9932 return TRUE;
9933 /*if access_klass is not member_klass context_klass must be type compat*/
9934 if (access_klass != member_klass && !mono_class_has_parent_and_ignore_generics (context_klass, access_klass))
9935 return FALSE;
9936 return TRUE;
9939 static gboolean
9940 can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
9942 GSList *tmp;
9943 if (accessing == accessed)
9944 return TRUE;
9945 if (!accessed || !accessing)
9946 return FALSE;
9948 /* extra safety under CoreCLR - the runtime does not verify the strongname signatures
9949 * anywhere so untrusted friends are not safe to access platform's code internals */
9950 if (mono_security_core_clr_enabled ()) {
9951 if (!mono_security_core_clr_can_access_internals (accessing->image, accessed->image))
9952 return FALSE;
9955 mono_assembly_load_friends (accessed);
9956 for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
9957 MonoAssemblyName *friend_ = (MonoAssemblyName *)tmp->data;
9958 /* Be conservative with checks */
9959 if (!friend_->name)
9960 continue;
9961 if (strcmp (accessing->aname.name, friend_->name))
9962 continue;
9963 if (friend_->public_key_token [0]) {
9964 if (!accessing->aname.public_key_token [0])
9965 continue;
9966 if (!mono_public_tokens_are_equal (friend_->public_key_token, accessing->aname.public_key_token))
9967 continue;
9969 return TRUE;
9971 return FALSE;
9975 * If klass is a generic type or if it is derived from a generic type, return the
9976 * MonoClass of the generic definition
9977 * Returns NULL if not found
9979 static MonoClass*
9980 get_generic_definition_class (MonoClass *klass)
9982 while (klass) {
9983 MonoGenericClass *gklass = mono_class_try_get_generic_class (klass);
9984 if (gklass && gklass->container_class)
9985 return gklass->container_class;
9986 klass = klass->parent;
9988 return NULL;
9991 static gboolean
9992 can_access_instantiation (MonoClass *access_klass, MonoGenericInst *ginst)
9994 int i;
9995 for (i = 0; i < ginst->type_argc; ++i) {
9996 MonoType *type = ginst->type_argv[i];
9997 switch (type->type) {
9998 case MONO_TYPE_SZARRAY:
9999 if (!can_access_type (access_klass, type->data.klass))
10000 return FALSE;
10001 break;
10002 case MONO_TYPE_ARRAY:
10003 if (!can_access_type (access_klass, type->data.array->eklass))
10004 return FALSE;
10005 break;
10006 case MONO_TYPE_PTR:
10007 if (!can_access_type (access_klass, mono_class_from_mono_type (type->data.type)))
10008 return FALSE;
10009 break;
10010 case MONO_TYPE_CLASS:
10011 case MONO_TYPE_VALUETYPE:
10012 case MONO_TYPE_GENERICINST:
10013 if (!can_access_type (access_klass, mono_class_from_mono_type (type)))
10014 return FALSE;
10015 default:
10016 break;
10019 return TRUE;
10022 static gboolean
10023 can_access_type (MonoClass *access_klass, MonoClass *member_klass)
10025 int access_level;
10027 if (access_klass == member_klass)
10028 return TRUE;
10030 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10031 return TRUE;
10033 if (access_klass->element_class && !access_klass->enumtype)
10034 access_klass = access_klass->element_class;
10036 if (member_klass->element_class && !member_klass->enumtype)
10037 member_klass = member_klass->element_class;
10039 access_level = mono_class_get_flags (member_klass) & TYPE_ATTRIBUTE_VISIBILITY_MASK;
10041 if (member_klass->byval_arg.type == MONO_TYPE_VAR || member_klass->byval_arg.type == MONO_TYPE_MVAR)
10042 return TRUE;
10044 if (mono_class_is_ginst (member_klass) && !can_access_instantiation (access_klass, mono_class_get_generic_class (member_klass)->context.class_inst))
10045 return FALSE;
10047 if (is_nesting_type (access_klass, member_klass) || (access_klass->nested_in && is_nesting_type (access_klass->nested_in, member_klass)))
10048 return TRUE;
10050 if (member_klass->nested_in && !can_access_type (access_klass, member_klass->nested_in))
10051 return FALSE;
10053 /*Non nested type with nested visibility. We just fail it.*/
10054 if (access_level >= TYPE_ATTRIBUTE_NESTED_PRIVATE && access_level <= TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM && member_klass->nested_in == NULL)
10055 return FALSE;
10057 switch (access_level) {
10058 case TYPE_ATTRIBUTE_NOT_PUBLIC:
10059 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10061 case TYPE_ATTRIBUTE_PUBLIC:
10062 return TRUE;
10064 case TYPE_ATTRIBUTE_NESTED_PUBLIC:
10065 return TRUE;
10067 case TYPE_ATTRIBUTE_NESTED_PRIVATE:
10068 return is_nesting_type (member_klass, access_klass);
10070 case TYPE_ATTRIBUTE_NESTED_FAMILY:
10071 return mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10073 case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
10074 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10076 case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
10077 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) &&
10078 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10080 case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
10081 return can_access_internals (access_klass->image->assembly, member_klass->nested_in->image->assembly) ||
10082 mono_class_has_parent_and_ignore_generics (access_klass, member_klass->nested_in);
10084 return FALSE;
10087 /* FIXME: check visibility of type, too */
10088 static gboolean
10089 can_access_member (MonoClass *access_klass, MonoClass *member_klass, MonoClass* context_klass, int access_level)
10091 MonoClass *member_generic_def;
10092 if (access_klass->image->assembly && access_klass->image->assembly->corlib_internal)
10093 return TRUE;
10095 MonoGenericClass *access_gklass = mono_class_try_get_generic_class (access_klass);
10096 if (((access_gklass && access_gklass->container_class) ||
10097 mono_class_is_gtd (access_klass)) &&
10098 (member_generic_def = get_generic_definition_class (member_klass))) {
10099 MonoClass *access_container;
10101 if (mono_class_is_gtd (access_klass))
10102 access_container = access_klass;
10103 else
10104 access_container = access_gklass->container_class;
10106 if (can_access_member (access_container, member_generic_def, context_klass, access_level))
10107 return TRUE;
10110 /* Partition I 8.5.3.2 */
10111 /* the access level values are the same for fields and methods */
10112 switch (access_level) {
10113 case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
10114 /* same compilation unit */
10115 return access_klass->image == member_klass->image;
10116 case FIELD_ATTRIBUTE_PRIVATE:
10117 return access_klass == member_klass;
10118 case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
10119 if (is_valid_family_access (access_klass, member_klass, context_klass) &&
10120 can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
10121 return TRUE;
10122 return FALSE;
10123 case FIELD_ATTRIBUTE_ASSEMBLY:
10124 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10125 case FIELD_ATTRIBUTE_FAMILY:
10126 if (is_valid_family_access (access_klass, member_klass, context_klass))
10127 return TRUE;
10128 return FALSE;
10129 case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
10130 if (is_valid_family_access (access_klass, member_klass, context_klass))
10131 return TRUE;
10132 return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
10133 case FIELD_ATTRIBUTE_PUBLIC:
10134 return TRUE;
10136 return FALSE;
10140 * mono_method_can_access_field:
10141 * @method: Method that will attempt to access the field
10142 * @field: the field to access
10144 * Used to determine if a method is allowed to access the specified field.
10146 * Returns: TRUE if the given @method is allowed to access the @field while following
10147 * the accessibility rules of the CLI.
10149 gboolean
10150 mono_method_can_access_field (MonoMethod *method, MonoClassField *field)
10152 /* FIXME: check all overlapping fields */
10153 int can = can_access_member (method->klass, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10154 if (!can) {
10155 MonoClass *nested = method->klass->nested_in;
10156 while (nested) {
10157 can = can_access_member (nested, field->parent, NULL, mono_field_get_type (field)->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10158 if (can)
10159 return TRUE;
10160 nested = nested->nested_in;
10163 return can;
10167 * mono_method_can_access_method:
10168 * @method: Method that will attempt to access the other method
10169 * @called: the method that we want to probe for accessibility.
10171 * Used to determine if the @method is allowed to access the specified @called method.
10173 * Returns: TRUE if the given @method is allowed to invoke the @called while following
10174 * the accessibility rules of the CLI.
10176 gboolean
10177 mono_method_can_access_method (MonoMethod *method, MonoMethod *called)
10179 method = mono_method_get_method_definition (method);
10180 called = mono_method_get_method_definition (called);
10181 return mono_method_can_access_method_full (method, called, NULL);
10185 * mono_method_can_access_method_full:
10186 * @method: The caller method
10187 * @called: The called method
10188 * @context_klass: The static type on stack of the owner @called object used
10190 * This function must be used with instance calls, as they have more strict family accessibility.
10191 * It can be used with static methods, but context_klass should be NULL.
10193 * Returns: TRUE if caller have proper visibility and acessibility to @called
10195 gboolean
10196 mono_method_can_access_method_full (MonoMethod *method, MonoMethod *called, MonoClass *context_klass)
10198 /* Wrappers are except from access checks */
10199 if (method->wrapper_type != MONO_WRAPPER_NONE || called->wrapper_type != MONO_WRAPPER_NONE)
10200 return TRUE;
10202 MonoClass *access_class = method->klass;
10203 MonoClass *member_class = called->klass;
10204 int can = can_access_member (access_class, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10205 if (!can) {
10206 MonoClass *nested = access_class->nested_in;
10207 while (nested) {
10208 can = can_access_member (nested, member_class, context_klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
10209 if (can)
10210 break;
10211 nested = nested->nested_in;
10215 if (!can)
10216 return FALSE;
10218 can = can_access_type (access_class, member_class);
10219 if (!can) {
10220 MonoClass *nested = access_class->nested_in;
10221 while (nested) {
10222 can = can_access_type (nested, member_class);
10223 if (can)
10224 break;
10225 nested = nested->nested_in;
10229 if (!can)
10230 return FALSE;
10232 if (called->is_inflated) {
10233 MonoMethodInflated * infl = (MonoMethodInflated*)called;
10234 if (infl->context.method_inst && !can_access_instantiation (access_class, infl->context.method_inst))
10235 return FALSE;
10238 return TRUE;
10243 * mono_method_can_access_field_full:
10244 * @method: The caller method
10245 * @field: The accessed field
10246 * @context_klass: The static type on stack of the owner @field object used
10248 * This function must be used with instance fields, as they have more strict family accessibility.
10249 * It can be used with static fields, but context_klass should be NULL.
10251 * Returns: TRUE if caller have proper visibility and acessibility to @field
10253 gboolean
10254 mono_method_can_access_field_full (MonoMethod *method, MonoClassField *field, MonoClass *context_klass)
10256 MonoClass *access_class = method->klass;
10257 MonoClass *member_class = field->parent;
10258 /* FIXME: check all overlapping fields */
10259 int can = can_access_member (access_class, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10260 if (!can) {
10261 MonoClass *nested = access_class->nested_in;
10262 while (nested) {
10263 can = can_access_member (nested, member_class, context_klass, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
10264 if (can)
10265 break;
10266 nested = nested->nested_in;
10270 if (!can)
10271 return FALSE;
10273 can = can_access_type (access_class, member_class);
10274 if (!can) {
10275 MonoClass *nested = access_class->nested_in;
10276 while (nested) {
10277 can = can_access_type (nested, member_class);
10278 if (can)
10279 break;
10280 nested = nested->nested_in;
10284 if (!can)
10285 return FALSE;
10286 return TRUE;
10290 * mono_class_can_access_class:
10291 * @source_class: The source class
10292 * @target_class: The accessed class
10294 * This function returns is @target_class is visible to @source_class
10296 * Returns: TRUE if source have proper visibility and acessibility to target
10298 gboolean
10299 mono_class_can_access_class (MonoClass *source_class, MonoClass *target_class)
10301 return can_access_type (source_class, target_class);
10305 * mono_type_is_valid_enum_basetype:
10306 * @type: The MonoType to check
10308 * Returns: TRUE if the type can be used as the basetype of an enum
10310 gboolean mono_type_is_valid_enum_basetype (MonoType * type) {
10311 switch (type->type) {
10312 case MONO_TYPE_I1:
10313 case MONO_TYPE_U1:
10314 case MONO_TYPE_BOOLEAN:
10315 case MONO_TYPE_I2:
10316 case MONO_TYPE_U2:
10317 case MONO_TYPE_CHAR:
10318 case MONO_TYPE_I4:
10319 case MONO_TYPE_U4:
10320 case MONO_TYPE_I8:
10321 case MONO_TYPE_U8:
10322 case MONO_TYPE_I:
10323 case MONO_TYPE_U:
10324 return TRUE;
10325 default:
10326 return FALSE;
10331 * mono_class_is_valid_enum:
10332 * @klass: An enum class to be validated
10334 * This method verify the required properties an enum should have.
10336 * Returns: TRUE if the informed enum class is valid
10338 * FIXME: TypeBuilder enums are allowed to implement interfaces, but since they cannot have methods, only empty interfaces are possible
10339 * FIXME: enum types are not allowed to have a cctor, but mono_reflection_create_runtime_class sets has_cctor to 1 for all types
10340 * FIXME: TypeBuilder enums can have any kind of static fields, but the spec is very explicit about that (P II 14.3)
10342 gboolean
10343 mono_class_is_valid_enum (MonoClass *klass)
10345 MonoClassField * field;
10346 gpointer iter = NULL;
10347 gboolean found_base_field = FALSE;
10349 g_assert (klass->enumtype);
10350 /* we cannot test against mono_defaults.enum_class, or mcs won't be able to compile the System namespace*/
10351 if (!klass->parent || strcmp (klass->parent->name, "Enum") || strcmp (klass->parent->name_space, "System") ) {
10352 return FALSE;
10355 if (!mono_class_is_auto_layout (klass))
10356 return FALSE;
10358 while ((field = mono_class_get_fields (klass, &iter))) {
10359 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC)) {
10360 if (found_base_field)
10361 return FALSE;
10362 found_base_field = TRUE;
10363 if (!mono_type_is_valid_enum_basetype (field->type))
10364 return FALSE;
10368 if (!found_base_field)
10369 return FALSE;
10371 if (mono_class_get_method_count (klass) > 0)
10372 return FALSE;
10374 return TRUE;
10377 gboolean
10378 mono_generic_class_is_generic_type_definition (MonoGenericClass *gklass)
10380 return gklass->context.class_inst == mono_class_get_generic_container (gklass->container_class)->context.class_inst;
10384 * mono_class_setup_interface_id:
10386 * Initializes MonoClass::interface_id if required.
10388 * LOCKING: Acquires the loader lock.
10390 void
10391 mono_class_setup_interface_id (MonoClass *klass)
10393 mono_loader_lock ();
10394 if (MONO_CLASS_IS_INTERFACE (klass) && !klass->interface_id)
10395 klass->interface_id = mono_get_unique_iid (klass);
10396 mono_loader_unlock ();
10400 * mono_class_setup_interfaces:
10402 * Initialize klass->interfaces/interfaces_count.
10403 * LOCKING: Acquires the loader lock.
10404 * This function can fail the type.
10406 void
10407 mono_class_setup_interfaces (MonoClass *klass, MonoError *error)
10409 int i, interface_count;
10410 MonoClass **interfaces;
10412 mono_error_init (error);
10414 if (klass->interfaces_inited)
10415 return;
10417 if (klass->rank == 1 && klass->byval_arg.type != MONO_TYPE_ARRAY) {
10418 MonoType *args [1];
10420 /* generic IList, ICollection, IEnumerable */
10421 interface_count = mono_defaults.generic_ireadonlylist_class ? 2 : 1;
10422 interfaces = (MonoClass **)mono_image_alloc0 (klass->image, sizeof (MonoClass*) * interface_count);
10424 args [0] = &klass->element_class->byval_arg;
10425 interfaces [0] = mono_class_bind_generic_parameters (
10426 mono_defaults.generic_ilist_class, 1, args, FALSE);
10427 if (interface_count > 1)
10428 interfaces [1] = mono_class_bind_generic_parameters (
10429 mono_defaults.generic_ireadonlylist_class, 1, args, FALSE);
10430 } else if (mono_class_is_ginst (klass)) {
10431 MonoClass *gklass = mono_class_get_generic_class (klass)->container_class;
10433 mono_class_setup_interfaces (gklass, error);
10434 if (!mono_error_ok (error)) {
10435 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10436 return;
10439 interface_count = gklass->interface_count;
10440 interfaces = mono_class_new0 (klass, MonoClass *, interface_count);
10441 for (i = 0; i < interface_count; i++) {
10442 interfaces [i] = mono_class_inflate_generic_class_checked (gklass->interfaces [i], mono_generic_class_get_context (mono_class_get_generic_class (klass)), error);
10443 if (!mono_error_ok (error)) {
10444 mono_class_set_type_load_failure (klass, "Could not setup the interfaces");
10445 return;
10448 } else {
10449 interface_count = 0;
10450 interfaces = NULL;
10453 mono_loader_lock ();
10454 if (!klass->interfaces_inited) {
10455 klass->interface_count = interface_count;
10456 klass->interfaces = interfaces;
10458 mono_memory_barrier ();
10460 klass->interfaces_inited = TRUE;
10462 mono_loader_unlock ();
10465 static void
10466 mono_field_resolve_type (MonoClassField *field, MonoError *error)
10468 MonoClass *klass = field->parent;
10469 MonoImage *image = klass->image;
10470 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
10471 MonoType *ftype;
10472 int field_idx = field - klass->fields;
10474 mono_error_init (error);
10476 if (gtd) {
10477 MonoClassField *gfield = &gtd->fields [field_idx];
10478 MonoType *gtype = mono_field_get_type_checked (gfield, error);
10479 if (!mono_error_ok (error)) {
10480 char *full_name = mono_type_get_full_name (gtd);
10481 mono_class_set_type_load_failure (klass, "Could not load generic type of field '%s:%s' (%d) due to: %s", full_name, gfield->name, field_idx, mono_error_get_message (error));
10482 g_free (full_name);
10485 ftype = mono_class_inflate_generic_type_no_copy (image, gtype, mono_class_get_context (klass), error);
10486 if (!mono_error_ok (error)) {
10487 char *full_name = mono_type_get_full_name (klass);
10488 mono_class_set_type_load_failure (klass, "Could not load instantiated type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
10489 g_free (full_name);
10491 } else {
10492 const char *sig;
10493 guint32 cols [MONO_FIELD_SIZE];
10494 MonoGenericContainer *container = NULL;
10495 int idx = mono_class_get_first_field_idx (klass) + field_idx;
10497 /*FIXME, in theory we do not lazy load SRE fields*/
10498 g_assert (!image_is_dynamic (image));
10500 if (mono_class_is_gtd (klass)) {
10501 container = mono_class_get_generic_container (klass);
10502 } else if (gtd) {
10503 container = mono_class_get_generic_container (gtd);
10504 g_assert (container);
10507 /* first_field_idx and idx points into the fieldptr table */
10508 mono_metadata_decode_table_row (image, MONO_TABLE_FIELD, idx, cols, MONO_FIELD_SIZE);
10510 if (!mono_verifier_verify_field_signature (image, cols [MONO_FIELD_SIGNATURE], NULL)) {
10511 char *full_name = mono_type_get_full_name (klass);
10512 mono_error_set_type_load_class (error, klass, "Could not verify field '%s:%s' signature", full_name, field->name);;
10513 mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error));
10514 g_free (full_name);
10515 return;
10518 sig = mono_metadata_blob_heap (image, cols [MONO_FIELD_SIGNATURE]);
10520 mono_metadata_decode_value (sig, &sig);
10521 /* FIELD signature == 0x06 */
10522 g_assert (*sig == 0x06);
10524 ftype = mono_metadata_parse_type_checked (image, container, cols [MONO_FIELD_FLAGS], FALSE, sig + 1, &sig, error);
10525 if (!ftype) {
10526 char *full_name = mono_type_get_full_name (klass);
10527 mono_class_set_type_load_failure (klass, "Could not load type of field '%s:%s' (%d) due to: %s", full_name, field->name, field_idx, mono_error_get_message (error));
10528 g_free (full_name);
10531 mono_memory_barrier ();
10532 field->type = ftype;
10535 static guint32
10536 mono_field_resolve_flags (MonoClassField *field)
10538 MonoClass *klass = field->parent;
10539 MonoImage *image = klass->image;
10540 MonoClass *gtd = mono_class_is_ginst (klass) ? mono_class_get_generic_type_definition (klass) : NULL;
10541 int field_idx = field - klass->fields;
10543 if (gtd) {
10544 MonoClassField *gfield = &gtd->fields [field_idx];
10545 return mono_field_get_flags (gfield);
10546 } else {
10547 int idx = mono_class_get_first_field_idx (klass) + field_idx;
10549 /*FIXME, in theory we do not lazy load SRE fields*/
10550 g_assert (!image_is_dynamic (image));
10552 return mono_metadata_decode_table_row_col (image, MONO_TABLE_FIELD, idx, MONO_FIELD_FLAGS);
10557 * mono_class_get_fields_lazy:
10558 * @klass: the MonoClass to act on
10560 * This routine is an iterator routine for retrieving the fields in a class.
10561 * Only minimal information about fields are loaded. Accessors must be used
10562 * for all MonoClassField returned.
10564 * You must pass a gpointer that points to zero and is treated as an opaque handle to
10565 * iterate over all of the elements. When no more values are
10566 * available, the return value is NULL.
10568 * Returns: a @MonoClassField* on each iteration, or NULL when no more fields are available.
10570 MonoClassField*
10571 mono_class_get_fields_lazy (MonoClass* klass, gpointer *iter)
10573 MonoClassField* field;
10574 if (!iter)
10575 return NULL;
10576 if (!*iter) {
10577 mono_class_setup_basic_field_info (klass);
10578 if (!klass->fields)
10579 return NULL;
10580 /* start from the first */
10581 if (mono_class_get_field_count (klass)) {
10582 *iter = &klass->fields [0];
10583 return (MonoClassField *)*iter;
10584 } else {
10585 /* no fields */
10586 return NULL;
10589 field = (MonoClassField *)*iter;
10590 field++;
10591 if (field < &klass->fields [mono_class_get_field_count (klass)]) {
10592 *iter = field;
10593 return (MonoClassField *)*iter;
10595 return NULL;
10598 char*
10599 mono_class_full_name (MonoClass *klass)
10601 return mono_type_full_name (&klass->byval_arg);
10604 /* Declare all shared lazy type lookup functions */
10605 GENERATE_TRY_GET_CLASS_WITH_CACHE (safehandle, "System.Runtime.InteropServices", "SafeHandle")
10608 * mono_method_get_base_method:
10609 * @method: a method
10610 * @definition: if true, get the definition
10611 * @error: set on failure
10613 * Given a virtual method associated with a subclass, return the corresponding
10614 * method from an ancestor. If @definition is FALSE, returns the method in the
10615 * superclass of the given method. If @definition is TRUE, return the method
10616 * in the ancestor class where it was first declared. The type arguments will
10617 * be inflated in the ancestor classes. If the method is not associated with a
10618 * class, or isn't virtual, returns the method itself. On failure returns NULL
10619 * and sets @error.
10621 MonoMethod*
10622 mono_method_get_base_method (MonoMethod *method, gboolean definition, MonoError *error)
10624 MonoClass *klass, *parent;
10625 MonoGenericContext *generic_inst = NULL;
10626 MonoMethod *result = NULL;
10627 int slot;
10629 if (method->klass == NULL)
10630 return method;
10632 if (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
10633 MONO_CLASS_IS_INTERFACE (method->klass) ||
10634 method->flags & METHOD_ATTRIBUTE_NEW_SLOT)
10635 return method;
10637 slot = mono_method_get_vtable_slot (method);
10638 if (slot == -1)
10639 return method;
10641 klass = method->klass;
10642 if (mono_class_is_ginst (klass)) {
10643 generic_inst = mono_class_get_context (klass);
10644 klass = mono_class_get_generic_class (klass)->container_class;
10647 retry:
10648 if (definition) {
10649 /* At the end of the loop, klass points to the eldest class that has this virtual function slot. */
10650 for (parent = klass->parent; parent != NULL; parent = parent->parent) {
10651 /* on entry, klass is either a plain old non-generic class and generic_inst == NULL
10652 or klass is the generic container class and generic_inst is the instantiation.
10654 when we go to the parent, if the parent is an open constructed type, we need to
10655 replace the type parameters by the definitions from the generic_inst, and then take it
10656 apart again into the klass and the generic_inst.
10658 For cases like this:
10659 class C<T> : B<T, int> {
10660 public override void Foo () { ... }
10662 class B<U,V> : A<HashMap<U,V>> {
10663 public override void Foo () { ... }
10665 class A<X> {
10666 public virtual void Foo () { ... }
10669 if at each iteration the parent isn't open, we can skip inflating it. if at some
10670 iteration the parent isn't generic (after possible inflation), we set generic_inst to
10671 NULL;
10673 MonoGenericContext *parent_inst = NULL;
10674 if (mono_class_is_open_constructed_type (mono_class_get_type (parent))) {
10675 parent = mono_class_inflate_generic_class_checked (parent, generic_inst, error);
10676 return_val_if_nok (error, NULL);
10678 if (mono_class_is_ginst (parent)) {
10679 parent_inst = mono_class_get_context (parent);
10680 parent = mono_class_get_generic_class (parent)->container_class;
10683 mono_class_setup_vtable (parent);
10684 if (parent->vtable_size <= slot)
10685 break;
10686 klass = parent;
10687 generic_inst = parent_inst;
10689 } else {
10690 klass = klass->parent;
10691 if (!klass)
10692 return method;
10693 if (mono_class_is_open_constructed_type (mono_class_get_type (klass))) {
10694 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
10695 return_val_if_nok (error, NULL);
10697 generic_inst = NULL;
10699 if (mono_class_is_ginst (klass)) {
10700 generic_inst = mono_class_get_context (klass);
10701 klass = mono_class_get_generic_class (klass)->container_class;
10706 if (generic_inst) {
10707 klass = mono_class_inflate_generic_class_checked (klass, generic_inst, error);
10708 return_val_if_nok (error, NULL);
10711 if (klass == method->klass)
10712 return method;
10714 /*This is possible if definition == FALSE.
10715 * Do it here to be really sure we don't read invalid memory.
10717 if (slot >= klass->vtable_size)
10718 return method;
10720 mono_class_setup_vtable (klass);
10722 result = klass->vtable [slot];
10723 if (result == NULL) {
10724 /* It is an abstract method */
10725 gboolean found = FALSE;
10726 gpointer iter = NULL;
10727 while ((result = mono_class_get_methods (klass, &iter))) {
10728 if (result->slot == slot) {
10729 found = TRUE;
10730 break;
10733 /* found might be FALSE if we looked in an abstract class
10734 * that doesn't override an abstract method of its
10735 * parent:
10736 * abstract class Base {
10737 * public abstract void Foo ();
10739 * abstract class Derived : Base { }
10740 * class Child : Derived {
10741 * public override void Foo () { }
10744 * if m was Child.Foo and we ask for the base method,
10745 * then we get here with klass == Derived and found == FALSE
10747 /* but it shouldn't be the case that if we're looking
10748 * for the definition and didn't find a result; the
10749 * loop above should've taken us as far as we could
10750 * go! */
10751 g_assert (!(definition && !found));
10752 if (!found)
10753 goto retry;
10756 g_assert (result != NULL);
10757 return result;